question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Agenda : "shouldComponentUpdate" is not working properly

See original GitHub issue

Description

Hi, When the name of an item for a day has changed (other than the first), the reservation component does not trigger the update.

Expected Behavior

Trigger update for all changed items.

Suggested fix

I think the issue came from : reservation We see that we say do NOT update the reservation if the d1/d2 does not exist. And we know that d1/d2 is a date that only exists for the first reservation item. That’s why I think only my first item is updated.

  shouldComponentUpdate(nextProps: ReservationProps) {
    const d1 = this.props.date;
    const d2 = nextProps.date;
    const r1 = this.props.item;
    const r2 = nextProps.item;
    
    let changed = true;
    if (!d1 && !d2) { 
      changed = false; // HERE
    } else if (d1 && d2) {
      if (d1.getTime() !== d2.getTime()) {
        changed = true;
      } else if (!r1 && !r2) {
        changed = false;
      } else if (r1 && r2) {
        if ((!d1 && !d2) || (d1 && d2)) {
          if (isFunction(this.props.rowHasChanged)) {
            changed = this.props.rowHasChanged(r1, r2);
          }
        }
      }
    }
    return changed;
  }

Environment

  • npm ls react-native-calendars: react-native-calendars@1.1280.0
  • npm ls react-native: react-native@0.66.4

Device/emulator/simulator & OS version: Android / Galaxy A12 / Android version : 11

Reproducible Demo

I took the example of the demo by adding an action which should modify the name of the clicked item by “Has changed !” Below the code :

import React, {Component} from 'react';
import {StyleSheet, Text, TouchableOpacity, View} from 'react-native';
import {Agenda, AgendaEntry, AgendaSchedule, DateData} from 'react-native-calendars';

interface State {
  items?: AgendaSchedule;
}

export default class AgendaScreen extends Component<State> {
  state: State = {
    items: undefined,
  };

  render() {
    return (
      <Agenda
        reservationsKeyExtractor={item => `${item.reservation?.day}`}
        items={this.state.items}
        loadItemsForMonth={this.loadItems}
        selected={'2017-05-16'}
        renderItem={this.renderItem}
        renderEmptyDate={this.renderEmptyDate}
        rowHasChanged={this.rowHasChanged}
        showClosingKnob={true}
        // markingType={'period'}
        // markedDates={{
        //    '2017-05-08': {textColor: '#43515c'},
        //    '2017-05-09': {textColor: '#43515c'},
        //    '2017-05-14': {startingDay: true, endingDay: true, color: 'blue'},
        //    '2017-05-21': {startingDay: true, color: 'blue'},
        //    '2017-05-22': {endingDay: true, color: 'gray'},
        //    '2017-05-24': {startingDay: true, color: 'gray'},
        //    '2017-05-25': {color: 'gray'},
        //    '2017-05-26': {endingDay: true, color: 'gray'}}}
        // monthFormat={'yyyy'}
        // theme={{calendarBackground: 'red', agendaKnobColor: 'green'}}
        //renderDay={(day, item) => (<Text>{day ? day.day: 'item'}</Text>)}
        // hideExtraDays={false}
        // showOnlySelectedDayItems
      />
    );
  }

  loadItems = (day: DateData) => {
    const items = this.state.items || {};

    setTimeout(() => {
      for (let i = -15; i < 85; i++) {
        const time = day.timestamp + i * 24 * 60 * 60 * 1000;
        const strTime = this.timeToString(time);

        if (!items[strTime]) {
          items[strTime] = [];

          const numItems = 3;
          for (let j = 0; j < numItems; j++) {
            items[strTime].push({
              name: 'Item for ' + '#' + j,
              height: Math.max(50, Math.floor(Math.random() * 150)),
              day: strTime + j,
            });
          }
        }
      }

      const newItems: AgendaSchedule = {};
      Object.keys(items).forEach(key => {
        newItems[key] = items[key];
      });
      this.setState({
        items: newItems,
      });
    }, 1000);
  };

  updateItem = (id: string) => {
    const newItems: AgendaSchedule = {...this.state.items};
    if (this.state.items) {
      Object.keys(this.state.items).forEach(key => {
        newItems[key] = this.updateAgendaEntry(key, id);
      });
      this.setState({
        items: newItems,
      });
    }
  };
  updateAgendaEntry = (date: string, id: string) => {
    let agendaEntryToUpdate: AgendaEntry[] = Object.assign([], this.state.items?.[date]);
    let index = agendaEntryToUpdate.findIndex(a => a.day === id);

    agendaEntryToUpdate[index] = Object.assign(
      {},
      {
        ...agendaEntryToUpdate[index],
        name: 'Has changed !',
      }
    );
    return agendaEntryToUpdate;
  };
  renderItem = (reservation: AgendaEntry, isFirst: boolean) => {
    const fontSize = isFirst ? 16 : 14;
    const color = isFirst ? 'black' : '#43515c';

    return (
      <TouchableOpacity style={[styles.item, {height: reservation.height}]} onPress={() => this.updateItem(reservation.day)}>
        <Text style={{fontSize, color}}>{reservation.name}</Text>
      </TouchableOpacity>
    );
  };

  renderEmptyDate = () => {
    return (
      <View style={styles.emptyDate}>
        <Text>This is empty date!</Text>
      </View>
    );
  };

  rowHasChanged = (r1: AgendaEntry, r2: AgendaEntry) => {
    return r1.name !== r2.name;
  };

  timeToString(time: number) {
    const date = new Date(time);
    return date.toISOString().split('T')[0];
  }
}

const styles = StyleSheet.create({
  item: {
    backgroundColor: 'white',
    flex: 1,
    borderRadius: 5,
    padding: 10,
    marginRight: 10,
    marginTop: 17,
  },
  emptyDate: {
    height: 15,
    flex: 1,
    paddingTop: 30,
  },
});

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:5
  • Comments:10

github_iconTop GitHub Comments

3reactions
DianaKoenraadtcommented, Apr 4, 2022

I seem to have a similar problem here. Agenda does not rerender when items changes.

2reactions
Lettycommented, Apr 26, 2022

Any updates on the issue? Patched the library for now, but it would be nice to see this fixed.

Read more comments on GitHub >

github_iconTop Results From Across the Web

shouldComponentUpdate not working in child component ...
shouldComponentUpdate () affect on parent component. If it returns true, parent component will be rerender. So, I think you should move ...
Read more >
Should I use shouldComponentUpdate? - James K Nelson
Maintaining shouldComponentUpdate is hard​​ The thing is, shouldComponentUpdate is sometimes necessary, and certainly makes your app respond ...
Read more >
Memoization in React js - Topcoder
... challenging problems, and tap into specialized skills on demand. ... It depends on the shouldComponentUpdate() lifecycle method but it ...
Read more >
How To Use Inline Functions In React Applications Efficiently
Inline function definitions are right where they are invoked or passed down. ... The comparison checks in shouldComponentUpdate and tells React to re-render ......
Read more >
I wish I knew these before diving into React | by Canberk Morelli
Setting shouldComponentUpdate wrongly or forgetting that you set it can cause major problems since your component may not be updated as ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found