Reputation: 6158
I have a DatePicker component, when I click on a new date it should set the change the date in the redux store, and also visibly UX-wise.
I'll put my code down below, for some reason in the handleChange
function, with both the setState
and the this.props.addFitler
there firing off, the redux store updates correctly but the UX doesn't.
However if I comment out the this.props.addFilter
dispatch function, the UX update correctly (and obviously the store doesn't).
Why aren't both of these working together? I've tried changing the order in which they're called, extracting each into another function, using mapDispatchToProps instead of calling the action creator directly, all to no avail.
DatePicker.js:
import DatePicker from 'react-datepicker';
class DatePick extends React.Component {
constructor(props) {
super(props);
this.state = {
date: moment()
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(date) {
const { dashboardName } = this.props;
const { name } = this.props.column;
this.props.addFilter(date, dashboardName, name);
this.setState({date});
}
render() {
return (
<div style={{display: 'inline-block', fontWeight: 'bold'}}>
<DatePicker
dateFormat="DD/MM/YYYY"
selected={this.state.date}
onChange={this.handleChange} />
</div>
);
}
}
const mapActionToProps = {
addFilter
};
export default connect(null, mapActionToProps)(DatePick);
The 'date' parameter that comes through in the handleChange function is a moment object just like the one used to set initialState, so that isn't the issue.
Additional info: If I console log before and after setState()
it logs the initial state both times.
Has anyone ran into this problem or have any ideas? If you need to see my redux I can update the post with more code but I don't think that's the problem as it updates the store fine.
Upvotes: 2
Views: 3494
Reputation: 2377
I don't think setTimeout
would be a good solution as suggested in the previous answer. We can not determine the actual time taken by the action creator (as it may contain an asynchronous call such as API call). This would again lead to the original problem of setState rendering going missing. Again setting a long timeout would be bad practice. Your application will have an unnecessary delay.
A possible solution would be to use the callback method of setState
to fire the action creator.
handleChange(date) {
const { dashboardName } = this.props;
const { name } = this.props.column;
this.setState({date}, () => {
this.props.addFilter(date, dashboardName, name);
});
}
In this case the action creator will be fired after the setState
is finished rendering.
Other solution is to use react lifecycle method to run setState
when new props are received.
This way the setState
is fired after the action creator has returned the props and changed the state.
componentWillRecieveProps (nextProps) {
// check the related prop is changed
// setState
}
But with react 17 this method will be deprecated soon. The new stable replacement for it is the following. https://hackernoon.com/problematic-react-lifecycle-methods-are-going-away-in-react-17-4216acc7d58b
static getDerivedStateFromProps(nextProps, prevState) {
// check the related prop is changed
// setState
}
Upvotes: 1
Reputation: 1591
I found the solution, action creator calling is doing some synchronous operation and the whole UI thread is locked until it finishes whatever it's doing. Hence we can delay the call a little bit with the help of setTimeout and everything will go as expected
Upvotes: 1