Not able to set state in componentWillReceiveProps in React - reactjs

I am trying to update the state of a component with new props received by the parent component.
However, the setState call doesn't seem to be working as I would expect.
I understand componentWillReceiveProps won't re-render the component, but it doesn't even seem to be allowing a setState call.
Any ideas what I might be doing wrong?
The code:
componentWillReceiveProps (nextProps) {
this.setState({name: nextProps.site.name});
console.log(nextProps.site.name); // logs the updated name
console.log(this.state.name); // logs the old name, even after presumably being set again
}

It's done asynchronously. So you may not see the update within the method. Check that in componentDidUpdate.

you can see the result in the setState callback , like this :
this.setState({name: nextProps.site.name} , ()=>{
console.log(this.state.name);
});

Related

How to use setState from .then in another function as a parameter in ReactJS

I am new to ReactJS. I have:
this.service
.getData({})
.then((response: any) => {
this.setState({
id: response.id
});
})
getStats(this.state.id) {
...
}
I am not able to get the value for id outside .then. I want to use id in multiple functions. How do I get the value in state so that I don't have to call the function several times? Please suggest.
on class base components, given the async nature of state update you use more often componentDidUpdate lifecycle. this lifecycle provides prevProps, prevState, snapshot as arguments, which are usefull to you do some validation with current state before triggering your actions.
fwiw, this.setState can receive a function as second parameter also. that function will be executed once state is updated, enabling you to have access to the most current state.
Once the state is updated, it will call the render method again. In the next render call you will have the state updated.
Calls to setState are asynchronous - don’t rely on this.state to reflect the new value immediately after calling setState.
So in order to use the state after the state is set, either you can use some effects or component life cycle to get the updated state.

React-redux mapStateToProps not received in the componentDidMount

So I've rewrote my code a bit to use state instead of modifying props since it is not what I should do. The problem that occurred now is that when componentDidMount runs props are still not fetched from the backend, therefore the if statements in the function are always false.
componentDidMount() {
this.props.getTypes('sport');
this.props.getSchema();
this.props.getDomainForm();
if(Object.keys(this.props.schema).length) {
this.setState({schema: this.props.schema})
}
if(Object.keys(this.props.formData).length) {
this.setState({form: this.props.formData})
}
}
const mapStateToProps = (state) => {
return {
schema: state.admin.settings.Domains.schema.data || {},
formData: state.admin.settings.Domains.domain.data || {},
types: state.admin.settings.Domains.types.data || {},
}
};
I've stepped trough the code and it seems like componentDidMount runs only once. Since componentWillRecieveProps is deprecated I am unsure what to do to fix this, and I hope you guys can help me with this one.
PS. there is no problems with fetch actions and reducers works perfectly I haven't changed anything there and redux debugger is displaying the results correctly.
i think the problem is your fetch is async and it takes little bit time to accomplish the task, and before the fetch is been finished , your component mounts on the DOM.
as you noted you can see the data is been received via redux debugger and you have no problem with it , so i'm guessing that you passed the initial state as empty object or array to your state. so then your component receives data through props and you are not updating the state to reRender the component , what you need to do is just use componentWillReceiveProps to update the state whenever the new data is been received by just checking if current props is not equal to previous props , some code like this :
componentWillReceiveProps = (nextProps) => {
if(this.props.yourPropsFromRedux != nextProps.yourPropsFromRedux ) {
this.setState({ yourState: nextProps.yourPropsFromRedux })
}
}
As a replacement of componentWillReceiveProps there was introduced static getDerivedStateFromProps(props, state) method, it's called each time component receives new props, so it might be helpful for you. Here's the docs.
Using componentDidUpdate along with componentDidMount is more suitable for this situation. componentDidMount will set the state for initial render and componentDidUpdate will set state for future renders. Don't forget to test the prevProps parameter of the componentDidUpdate method with current props to check if the data has changed or not. Read the documentation here

How to setState the props value in ComponentDidUpdate in react-native?

componentDidUpdate(){
var date = this.props.navigation.state.params.selected_date
this.setState({
sleepinputs_date: date
})
}
When I try to setState the props value it throws an error "
You had created infinite state update.
Inside componentDidUpdate you update the state, when it updates the state, componentDidUpdate invokes again in this stuff keeps going without ending.
According to react docs, you will get an argument in componentDidUpdate. You can set state only if you use a conditional like the following.
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
Basically you are comparing the old props with the new ones. Only if they are different, you can keep updating or modifying the value. If previous props are the same as current props, why you botter to set state them again.

`componentWillReceiveProps` explanation

I recently wanted to upgrade my knowledge of React, so I started from the component lifecycle methods. The first thing that got me curious, is this componentWillReceiveProps. So, the docs are saying that it's fired when component is receiving new (not necessarily updated) props. Inside that method we can compare them and save into the state if needed.
My question is: Why do we need that method, if changes in props of that component (inside parent render) will trigger the re-render of this child component?
One common use case are state (this.state) updates that may be necessary in response to the updated props.
Since you should not try to update the component's state via this.setState() in the render function, this needs to happen in componentWillReceiveProps.
Additionally, if some prop is used as a parameter to some fetch function you should watch this prop in componentWillReceiveProps to re-fetch data using the new parameter.
Usually componentDidMount is used as a place where you trigger a method to fetch some data. But if your container, for example, UserData is not unmounted and you change userId prop, the container needs to fetch data of a user for corresponding userId.
class UserData extends Component {
componentDidMount() {
this.props.getUser(this.props.userId);
}
componentWillReceiveProps(nextProps) {
if (this.props.userId !== nextProps.userid) {
this.props.getUser(nextProps.userId);
}
}
render() {
if (this.props.loading) {
return <div>Loading...</div>
}
return <div>{this.user.firstName}</div>
}
}
It is not a full working example. Let's imagine that getUser dispatch Redux action and Redux assign to the component user, loading and getUser props.
It 'serves' as an opportunity to react to the incoming props to set the state of your application before render. If your call setState after render you will re-render infinitely and that's why you're not allowed to do that, so you can use componentWillReceiveProps instead.
But... you are beyond CORRECT in your confusion, so correct in fact that they are deprecating it and other Will-lifecycle hooks Discussion Deprecation.
There are other ways to accomplish what you want to do without most of those Will-lifecycle methods, one way being don't call setState after render, just use the new incoming props directly in render (or wherever) to create the stateful value you need and then just use the new value directly, you can then later set state to keep a reference for the next iteration ex: this.state.someState = someValue, this will accomplish everything and not re-render the component in an infinite loop.
Use this as an opportunity to react to a prop transition before render() is called by updating the state using this.setState(). The old props can be accessed via this.props. Calling this.setState() within this function will not trigger an additional render.
Look at this article
the componentWillReceiveProps will always receive as param "NxtProps", componentWillReceiveProps is called after render().
some people use this method use this to compare nxtProps and this.props to check, if something should happen before the component call render, and to some validations.
check the react's documentation to know more about react lifecycle!
hope this could help you!
changes in props of that component (inside parent render) will trigger the re-render of this child component
You are absolutely right. You only need to use this method if you need to react to those changes. For instance, you might have a piece of state in a child component that is calculated using multiple props.
Small Example:
class Test extends Component {
state = {
modified: "blank"
};
componentDidMount(){
this.setState({
modified: `${this.props.myProp} isModified`
});
}
componentWillReceiveProps(nextProps) {
this.setState({
modified: `${nextProps.myProp} isModified`
});
}
render() {
return <div className="displayed">{this.state.modified}</div>
}
}
In this example, componentDidMount sets the state using this.props. When this component receives new props, without componentWillReceiveProps, this.state.modified would never be updated again.
Of course, you could just do {this.props.myProp + "IsModified"} in the render method, but componentWillReceiveProps is useful when you need to update this.state on prop changes.

Is there a way to know if a specific prop was updated without using state in React?

I'm using React, Redux, and some antd components
I'm using this modal to alert users of errors, but if you look at it, its not exactly a component, its a function, so right now I'm using componentDidUpdate like this:
componentDidUpdate () {
if (this.props.states.ErrorReducer.displayError) {
error(() => {
this.props.dispatch(ErrorActionCreators.acceptError())
}, this.props.states.ErrorReducer.errorMessage )
}
}
Problem is, if I make multiple changes to state at once, for example make multiple calls to the API and they alter the state at different times, this modal open multiple times.
I could use state to do something like
if (this.state.displayError !== this.props.displayError {
updateState();
error();
}
But I'm avoiding using React state.
Is there anyway I can check if one specific prop was changed on the Component?
You can use the lifecycle method, componentWillReceiveProps. This gets called every time props are updated. Here's a link for help componentWillreceiveProps and a code snippet:
componentWillReceiveProps(nextProps){
if(this.props !== nextProps){
// your code and conditions go here
}
}
You can actually compare the old props (this.props) with the new or updated props (nextProps).

Resources