Agenda renders items under wrong date when navigating to a date other than the initial selected
Description
When the Agenda component is mounted with a selected date (e.g. today), then the user navigates to a different date, items from the original date appear under the wrong date section header. The symptoms shift depending on which date is selected, making the bug look like a data problem rather than a rendering one.
Root cause
Two issues combine to produce the bug:
1. Reservation.shouldComponentUpdate ignores item content when date is undefined
// reservation-list/reservation.js
if (!d1 && !d2) {
changed = false;
}Only the first item in each day's group receives a date prop; all subsequent items always have date: undefined. When the list shifts to a new selectedDay, React reuses existing Reservation instances (matched by key). For any reused instance where both the old and new date are undefined, shouldComponentUpdate returns false — even when the actual item (reservation content) has changed. The component keeps rendering the stale item.
2. The default keyExtractor produces non-unique keys for custom item types
keyExtractor = (item, index) => {
return this.props.reservationsKeyExtractor?.(item, index) || `${item?.reservation?.day}${index}`;
};item.reservation.day is undefined for any item type that doesn't match the built-in AgendaEntry shape ({ name, height, day }). This causes all keys to be "undefined0", "undefined1", etc. — purely positional — so React reuses the wrong component instances when the list shifts, triggering the shouldComponentUpdate bug above.
Steps to reproduce
- Mount
<Agenda selected="2024-01-05" items={...} />where the items for2024-01-05have multiple entries (e.g. 4 items) and the previous day (2024-01-04) also has items. - Use custom item objects that don't have a
dayproperty (i.e. anything other than the built-inAgendaEntryshape). - Navigate to
2024-01-04(e.g. viaonDayPress). - Observe that items from
2024-01-05appear in the2024-01-04section.
Expected behaviour
Items for 2024-01-04 appear under the 2024-01-04 section header after navigation.
Actual behaviour
Some items from 2024-01-05 remain visible under the 2024-01-04 section header. The number of incorrect items equals the number of non-first items in the original day's group (i.e. items 2–N, which all have date: undefined).
Workaround
Pass a reservationsKeyExtractor prop that returns a unique key per item. This forces React to create fresh Reservation instances when the list shifts, bypassing the shouldComponentUpdate guard entirely:
<Agenda
reservationsKeyExtractor={(item, index) => item?.id ?? String(index)}
...
/>Where item is your agenda item object. Any field that uniquely identifies the item works — item?.id, item?.name, etc.
Proposed fix
shouldComponentUpdate should include the item content in its change check when date is undefined, not short-circuit to false:
shouldComponentUpdate(nextProps) {
const d1 = this.props.date;
const d2 = nextProps.date;
if (!d1 && !d2) {
// date didn't change, but the item content might have
if (isFunction(this.props.rowHasChanged)) {
return this.props.rowHasChanged(this.props.item, nextProps.item);
}
return this.props.item !== nextProps.item;
}
// ... existing logic
}Version
react-native-calendars 1.1314.0
Environment
- Platform: iOS
- react-native-calendars: 1.1314.0
- React Native: 0.79.6
- Expo SDK: 53.0.27
Source: wix/react-native-calendars