Reputation: 906
So I am using Airbnb's react-dates library for a calendar:
export const Calendar = ({setDates, startDate, endDate, setFocused, focusedInput}) => {
return (
<div className="input-group">
<div className="input-group_addon">
<i className="icon-date-inactive" aria-hidden="true"></i>
</div>
<DateRangePicker
startDate={startDate}
endDate={endDate}
focusedInput={focusedInput}
displayFormat="ddd, D MMM"
onDatesChange={setDates}
onFocusChange={setFocused}
/>
</div>
)
}
const mapStateToProps = (state) => {
return {
startDate: state.model.model.calendar.startDate,
endDate: state.model.model.calendar.endDate,
focusedInput: state.model.model.calendar.focusedInput
}
}
const mapDispatchToProps = (dispatch) => {
return {
setDates: (dates) => {
dispatch(marketplaceSetDates(dates.startDate, dates.endDate));
},
setFocused: (focusedInput) => {
dispatch(marketplaceSetFocused(focusedInput));
}
}
}
export const CalendarContainer = connect(mapStateToProps, mapDispatchToProps)(Calendar);
export function marketplaceSetDates(startDate, endDate) {
return {
type: 'MARKETPLACE_MODEL_DATES_CHANGE',
dates: {
start: startDate,
end: endDate
}
}
}
export function marketplaceSetFocused(focusedInput) {
return {
type: 'MARKETPLACE_MODEL_FOCUS_CHANGE',
focusedInput: focusedInput
}
}
let initialState = {
model: {
calendar: {
startDate: moment().add(1, 'day'),
endDate: moment().add(4, 'day'),
focusedInput: null
}
},
}
export const modelReducer = (state = initialState, action) => {
let newState = {};
switch(action.type) {
case 'MARKETPLACE_MODEL_FOCUS_CHANGE':
newState = Object.assign({}, state);
newState.model.calendar.focusedInput = action.focusedInput;
return newState;
case 'MARKETPLACE_MODEL_DATES_CHANGE':
newState = Object.assign({}, state);
newState.model.calendar.startDate = (action.dates.start === null) ?
state.model.calendar.startDate : action.dates.start;
newState.model.calendar.endDate = (action.dates.end === null) ?
state.model.calendar.startDate.add(4, 'day') : action.dates.end;
return newState;
}
return state;
}
The one rule for our calendar is that, whenever the user select a new startDate
or endDate
, it must automatically adjust to be at least 3 days apart.
For example as you could see, the initial state sets the dates to be tomorrow and 4 days from now.
startDate
on Oct 24, (NOTE THAT IT IS NOT WITHIN THE RANGE OF THE PREVIOUS DAYS), thus the endDate
must automatically adjust to Oct 27. endDate
before the selected range, the startDate
must automatically adjust accordingly, 3 days before the selected endDate
.But with my current code, when I click on the startDate
, both startDate
and endDate
is set to 3 days after, which should only be endDate
's value.
I suspect the reason behind this is due to mutating the state in redux
is asynchronous, thus the state.model.calendar.startDate.add(4, 'day')
goes first before the newState.model.calendar.startDate = ...
, am I correct in my assumption?
Otherwise, I would like help for a workaround.
Upvotes: 0
Views: 42
Reputation: 4166
TL;DR:
Change the add days function to:
state.model.calendar.startDate.clone().add(4, 'day')
I believe the issue is with the momentjs add function. From the docs: http://momentjs.com/docs/#/manipulating/add/
Add
... Mutates the original moment by adding time.
This means that when you do
state.model.calendar.startDate.add(4, 'day')
it actually changes the value of state.model.calendar.startDate
.
So ideally, you should copy the moment and then change it using clone()
Upvotes: 2