Reputation: 1180
I learnt React
and Redux
about an year ago and had not used them intensively until recently. I was surprised to find out that there are quite a few changes in both React
and Redux
.
The first thing i noticed is that I can no longer use the componentWillReceiveProps
lifecycle method and its telling me i need to use some weird getDerivedStateFromProps
method which doesn't really solve my current issue.
Basically, I have a register function which dispatches
3 actions
- REGISTER_REQUEST
, REGISTER_SUCCESS
and REGISTER_FAIL
. I also have 3 flags in my userReducer - registering
, registered
, registerError
.
In my Register
component, i want to do the following:
registering
is true, add a loading animationregistering
is false and registered
is true, redirect the user to /profile
routeregisterError
is true, get the error from the redux store
and set it in the component's state
.My first approach was the following:
componentWillReceiveProps() {
if(this.props.user){
if(this.props.user.registered && !this.props.user.registering){
this.props.history.push("/jobs")
}
}
if(this.props.user.registerError){
this.setState({error: this.props.user.registerErrorMessage})
}
}
Which did not work out as I expected it to. As i mentioned above, its telling me that I am no longer allowed to use componentWillRecieveProps
.
My next guess was to use the componentDidUpdate
method but in that method, I can not call setState
because it causes the infamous state loop error
. I have worked around this error before but not without doing a lot of hacky things which I do not like.
I did end up solving this problem by creating a history helper
which allowed me to redirect user from outside the component (the register function), but that ended up causing more problems with the react router
and it did not solve my issue of setting the registerErrorMessage
to the components state
.
So what is the correct way of doing this in React and Redux? I am really trying to avoid using hacky tricks to get around these problems since almost always they have come around and bit me in the ass later on.
Upvotes: 0
Views: 596
Reputation: 29282
Although i don't see a reason why would you need to save the error message in your component's state instead of just getting the error from the redux store and displaying it to the user, you can call this.setState
inside componentDidUpdate
function but to avoid the infinite cycle of state update and re-render, you need to update the state conditionally.
Assuming both registerError
inside redux store and error
in your component's state are initially null
, inside componentDidUpdate
function, check if this.state.error
is equal to register error from the redux store or not. If they are not equal, update the state.
componentDidUpdate(prevProps, prevState) {
if (this.state.error != this.props.registerError) {
this.setState({ error: this.props.registerError });
}
}
In this demo there's a Register
component which dispatches an action to fetch the user from jsonplaceholder API. When HTTP request starts, REGISTER_REQUEST
action is dispatched which sets registering
state in the redux store to true. If user is fetched successfully, REGISTER_SUCCESS
action is dispatched. Incase of an error, REGISTER_ERROR
action is dispatched. When there's an error, that error is saved in the state inside Register
component and is also displayed to the user.
To produce an error while making the HTTP request, i have changed API URL from
"https://jsonplaceholder.typicode.com/users/1" // correct URL
to
"https://jsonplaceholder.typicode.com/user/1" // incorrect URL
Upvotes: 1
Reputation: 1862
When the props
change due to changes in the redux store, the component is rendered again. So you should put this logic in the render
function. Since calling setState
will call another render, you should just use the error value from the props
and not save it in the state.
Upvotes: 0