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?
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?
Most helpful comment
You are not treating
markedDatesas immutable. Since the reference ofmarkedDatesdoes not change update condition is not triggered. Use this whenever you changemarkedDates:this.viewData.markedDates = Object.assign({}, this.viewData.markedDates);