React-native-calendars: What's the update condition?

Created on 3 Aug 2017  路  7Comments  路  Source: wix/react-native-calendars

First, it's an awesome project!

I found that the control not always update as state changed, but it would update selected status if changing month, so what's the update condition or is there any method to force updating control?

if comment this.shouldComponentUpdate = shouldComponentUpdate; in the calendar\index.js, it would update if component state changes.

anyway, i want to know why override shouldcomponentupdate method?

Most helpful comment

You are not treating markedDates as immutable. Since the reference of markedDates does not change update condition is not triggered. Use this whenever you change markedDates:

this.viewData.markedDates = Object.assign({}, this.viewData.markedDates);

All 7 comments

Hi, shouldComponentUpdate is implemented in order to minimize rerenders and make calendar more performant. Can you give me example code snippet so that I could reproduce your problem easily?

@tautvilas here is the code, just use a switch button to mark dates, first time it's OK, but next time, choose another date in the same month, no changes would show although data has changed.

// a class to record date, press one day, the next 5 days would be marked.
class CycleRecord extends Component {


    constructor(props) {
        super(props);

        this.state = {
            showPeriodOff: false,
            selected: '',
            needReloadView: 0,
        };

        this.viewData = {
            periodStartDates: [],
            markedDates: {
                // '2017-07-16': {selected: true, marked: true},
                // '2017-07-17': {marked: true},
                // '2017-07-18': {disabled: true}
            },
            periodEndDates: {},
            selected: '',
        };
    }


    reloadView() {
        let {needReloadView} = this.state;
        this.setState({
            needReloadView: needReloadView + 1,
        })
    }

    _onPeriodStartDateCheckChange(startDateStr, checked) {
        let {periodStartDates, periodEndDates, markedDates} = this.viewData;
        if (checked) {
            periodStartDates.push(startDateStr);

            markedDates[startDateStr] = {
                // startingDay: true,
                // color: 'green',
                // textColor: 'red',
                selected: startDateStr == this.viewData.selected,
                marked: true,
            };

            let sDate = DateUtil.convertDateFromString(startDateStr);

            if (!sDate) {
                return;
            }

            let endDates = [];
            for (let i = 1; i <= 5; i++) {
                let dateStr = DateUtil.format(DateUtil.add(sDate, i), 'yyyy-MM-dd')
                endDates.push(dateStr);

                markedDates[dateStr] = {
                    marked: true,
                };
            }

            periodEndDates[startDateStr] = endDates;

        } else {
            let index = periodStartDates.indexOf(startDateStr);
            if (index < 0) {
                return;
            }

            periodStartDates.splice(index, 1);
            delete periodEndDates[startDateStr];
        }

       this.reloadView();
    }

    _onDayChange(dateString) {

        if (this.viewData.markedDates[this.viewData.selected]) {
           delete this.viewData.markedDates[this.viewData.selected].selected;
        }

        this.viewData.selected = dateString;

        if (this.viewData.markedDates[dateString]) {
            this.viewData.markedDates[dateString].selected = true;
        } else {
            this.viewData.markedDates[dateString] = {
                selected: true,
            }
        }

        this.reloadView();
    }

    render() {

        return (
            <View style={[styles.container,]}>

                <ScrollView style={{backgroundColor: '#ffffff', flex: 1}}>

                    <Calendar
                        maxDate={new Date()}
                        onDayPress={(day) => {
                            console.log('day changed', day);
                            //this.setState({selected: day.dateString});
                            this._onDayChange(day.dateString);
                        }}

                        onMonthChange={(month) => {
                            console.log('month changed', month)
                        }}
                        hideExtraDays={true}
                        firstDay={1}
                        theme={{
                            calendarBackground: '#ffffff',
                            textSectionTitleColor: '#7f7f7f',
                            selectedDayBackgroundColor: '#00adf5',
                            selectedDayTextColor: '#ffffff',
                            todayTextColor: '#f17cb5',
                            dayTextColor: '#7f7f7f',
                            textDisabledColor: '#d9e1e8',
                            dotColor: '#00adf5',
                            selectedDotColor: themeColor,
                            arrowColor: '#f17cb5',
                            monthTextColor: '#7f7f7f',
                            textDayFontFamily: 'monospace',
                            textMonthFontFamily: 'monospace',
                            textDayHeaderFontFamily: 'monospace',
                            textDayFontSize: 14,
                            textMonthFontSize: 16,
                            textDayHeaderFontSize: 14
                        }}
                        displayLoadingIndicator
                        markedDates={this.viewData.markedDates}
                    />

                    <View style={styles.optionContainer}>
                        <Text style={{flex: 1,}}>mark</Text>
                        <Switch style={{flex: 1,}}
                                onValueChange={(value) => {
                                    this._onPeriodStartDateCheckChange(this.viewData.selected, value);
                                }}
                                value={this.viewData.periodStartDates.indexOf(this.viewData.selected) >= 0}/>
                    </View>

                </ScrollView>
            </View>
        )
    }
}

class DateUtil extends Component {
    static getDateOfLastDay(date = new Date()) {
        let year = date.getFullYear();
        let month = date.getMonth() + 1;
        let day = new Date(year, month, 0);

        return day;
    }


    //yyyy-MM-dd
    static convertDateFromString(dateString) {
        if (dateString) {
            let date = new Date(dateString.replace(/-/, "/"))

            return date;
        }

        return null;
    }

    static format(date, fmt = 'yyyy-MM-dd') {
        let o = {
            "M+": date.getMonth() + 1,                 //
            "d+": date.getDate(),                    //
            "h+": date.getHours(),                   //
            "m+": date.getMinutes(),                 //
            "s+": date.getSeconds(),                 //
            "q+": Math.floor((date.getMonth() + 3) / 3), //
            "S": date.getMilliseconds()             //
        };
        if (/(y+)/.test(fmt)) {
            fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
        }
        for (var k in o) {
            if (new RegExp("(" + k + ")").test(fmt)) {
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
            }
        }

        return fmt;
    }

    static add(date, count) {
        let y = date.getFullYear();
        let m = date.getMonth();
        let d = date.getDate() + count;

        return new Date(y, m, d);
    }
}

BTW, console.log(shouldUpdate.field, shouldUpdate.update); outputs undefined false in the second state update. @tautvilas

You are not treating markedDates as immutable. Since the reference of markedDates does not change update condition is not triggered. Use this whenever you change markedDates:

this.viewData.markedDates = Object.assign({}, this.viewData.markedDates);

@tautvilas thanks for the solution, i think it's better to point out in the wiki.

Yes, I added to Readme, thx

Hi,

I have the same problem I am updating my markedDates:

loadItems(dates) {
    const { events } = this.props;

    const startDate = new Date(dates[0].year, dates[0].day, dates[0].month),
        endDate = new Date(dates[2].year, dates[2].day, dates[2].month),


    const newEvents = events.filter(date => { 
        moment()
            .range(startDate, endDate)
            .contains(date);
    });

    this.setState({
        markedDates: { ...newEvents, this.state.markedDates }
    });
}
 return (
            <CalendarList
                style={styles.calendar}
                markingType={"multi-dot"}
                onVisibleMonthsChange={this.loadItems}
                onDayPress={this.onDayPress}
                maxDate={"2019-12-19"}
                markedDates={this.state.markedDates}
                pastScrollRange={-1}
                futureScrollRange={12}
                scrollEnabled={true}
                showScrollIndicator={true}
            />
        );

@tautvilas Any ideas how I can get it to update?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

matieux picture matieux  路  4Comments

moiiiiit picture moiiiiit  路  4Comments

filippoitaliano picture filippoitaliano  路  3Comments

Yandamuri picture Yandamuri  路  4Comments

dobiedad picture dobiedad  路  4Comments