Skip to content

Agenda renders items under wrong date when navigating to a date other than the initial selected #2781

@clivegross

Description

@clivegross

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

  1. Mount <Agenda selected="2024-01-05" items={...} /> where the items for 2024-01-05 have multiple entries (e.g. 4 items) and the previous day (2024-01-04) also has items.
  2. Use custom item objects that don't have a day property (i.e. anything other than the built-in AgendaEntry shape).
  3. Navigate to 2024-01-04 (e.g. via onDayPress).
  4. Observe that items from 2024-01-05 appear in the 2024-01-04 section.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions