I am trying to highlight the 14 days after the selected start date because we do not allow rentals longer than 14 days. This is a good common use for something like highlighting. However, when onChange fires with a new startDate having been selected, isDayHighlighted is not re-run, so the highlighting is then incorrect.
onChange = ({ startDate, endDate }: any) => {
if (startDate) {
this.props.setPickupDate(startDate);
this.setState({ startDate });
}
if (endDate) {
this.props.setDropoffDate(endDate);
this.setState({ endDate });
} else {
this.props.setDropoffDate(null);
this.setState({ endDate: null });
}
if (startDate && endDate) {
// run check availability
const { pickupLocation } = this.props.activeBooking;
const params = {
location_ids: pickupLocation.multi_car_location_ids,
pickup_on: moment(startDate).format('YYYY-MM-DD'),
dropoff_on: moment(endDate).format('YYYY-MM-DD'),
};
this.props.locationsAvailability(params);
}
};
onFocusChange = (focusedInput: any) =>
this.setState({
focusedInput: !focusedInput ? START_FOCUS : focusedInput,
});
isDayHighlighted =
(day: any) => (
isInclusivelyAfterDay(day, moment(this.state.startDate)) &&
!isInclusivelyAfterDay(day, moment(this.state.startDate).add(14, 'days')) &&
!this.state.endDate
);
isOutsideRange =
(day: any) => (
!isInclusivelyAfterDay(day, this.state.openDate) ||
isInclusivelyAfterDay(day, moment(this.state.openDate).add(180, 'days'))
);
render() {
return (
<div className="sc-date-picker">
<div>
<DayPickerRangeController
daySize={48}
endDate={this.state.endDate}
firstDayOfWeek={1}
focusedInput={this.state.focusedInput}
hideKeyboardShortcutsPanel
initialVisibleMonth={() => moment(this.state.openDate)}
isDayHighlighted={this.isDayHighlighted}
isOutsideRange={this.isOutsideRange}
minimumNights={0}
numberOfMonths={this.state.numberOfMonths}
onDatesChange={this.onChange}
onFocusChange={this.onFocusChange}
orientation="verticalScrollable"
startDate={this.state.startDate}
/>
</div>
</div>
);
}
}
+1
I think that isDayHighlighted (or any of the prop modifiers for that matter) only get recomputed if focus changes or if the method itself is different (see https://github.com/airbnb/react-dates/blob/master/src/components/DayPickerRangeController.jsx#L364-L400).
The motivation behind this was largely to try and minimize the number of times the prop modifiers are automatically recomputed because they're fairly expensive.
One thing I can recommend doing is using a factory method instead of isDayHighlighted directly. That's what we do internally. It allows to better control when you want to trigger a recalculation of the method (because you basically generate a new method every time you want to guarantee a recalculation).
For your case, I'd do something like the following:
constructor(props) {
super(props);
this.isDayHighlighted = this.isDayHighlightedFactory()
}
onChange = ({ startDate, endDate }: any) => {
if (startDate) {
this.props.setPickupDate(startDate);
this.setState({ startDate }, () => {
this.isDayHighlighted = this.isDayHighlightedFactory();
});
}
...
};
isDayHighlightedFactory() {
return (day: any) => (
isInclusivelyAfterDay(day, moment(this.state.startDate)) &&
!isInclusivelyAfterDay(day, moment(this.state.startDate).add(14, 'days')) &&
!this.state.endDate
);
}
render() {
return (
<div className="sc-date-picker">
<div>
<DayPickerRangeController
isDayHighlighted={this.isDayHighlighted}
...
/>
</div>
</div>
);
}
}
You can see that I generate a new isDayHighlighted method every time the start date changes (but only after I've updated the state). Does that make sense?
@majapw Amazing! Thank you! This was driving me crazy. This is a brilliant and elegant solution. Thank you so much. We'll be doing our best to contribute back to the library and that you for all your work.
Most helpful comment
I think that
isDayHighlighted(or any of the prop modifiers for that matter) only get recomputed if focus changes or if the method itself is different (see https://github.com/airbnb/react-dates/blob/master/src/components/DayPickerRangeController.jsx#L364-L400).The motivation behind this was largely to try and minimize the number of times the prop modifiers are automatically recomputed because they're fairly expensive.
One thing I can recommend doing is using a
factorymethod instead ofisDayHighlighteddirectly. That's what we do internally. It allows to better control when you want to trigger a recalculation of the method (because you basically generate a new method every time you want to guarantee a recalculation).For your case, I'd do something like the following:
You can see that I generate a new
isDayHighlightedmethod every time the start date changes (but only after I've updated the state). Does that make sense?