I want the getKey function to wait for the updated state from friendExist.
Currently getKey is set to false as the initial state however friendExist should set the boolean to "true". But it seems that "this.props.getKey(this.props.exist)" dosen't wait "this.props.friendExist(uid)" to update before it runs the code.
componentDidMount(){
const uid = 'MZdKuFpGmGRntb0nyF4PO0f6kco1';
this.props.friendExist(uid);
//friendExist should update this.props.exist to true
this.props.getKey(this.props.exist)
}
Both friendExist and getKey are actions that dispatch the new state.
Your function componentDidMount is a synchronous function, so it will execute inside code without waiting for any unrelated functions. Unless you change its type to asynchronous, and tell exactly how you want it to wait, this.props.exist will never be true at the time this.props.getKey is executed.
An alternative, simpler solution is taking the update of this.props.exist at componentWillReceiveProps, and execute this.props.getKey in there instead
componentDidMount(){
const uid = 'MZdKuFpGmGRntb0nyF4PO0f6kco1';
this.props.friendExist(uid);
}
componentWillReceiveProps(nextProps, nextState) {
if (nextProps.exist) {
this.props.getKey(nextProps.exist)
}
}
I assume you are using react-redux mapStateToProps() to get the updated state. This behavior is expected as react-redux uses react's setState() internally, which is asynchronous, meaning your state may not map to the props on the same time you dispatch the action.
I suggest creating a function getKeyIfFriendExist() instead which does the dispatching and checking of the latest state inside.
Related
I have added the below piece of code in my react project to set the state with the response of a method. But the state never updated. It is always null. May i know how to set the state here
_onload():any{
this._DataAccessObj = new DataAccess();
let result = this._DataAccessObj.getRequest(this.props.itemId).then((item:IRequest) =>{
console.log("item");
console.log(item);
this.setState ({
Request: item
});
console.log(this.state.Request);
console.log("setstate");
});
return;
}
From the documentation of ReactJS and lifecycle:
Every second the browser calls the tick() method. Inside it, the Clock
component schedules a UI update by calling setState() with an object
containing the current time. Thanks to the setState() call, React
knows the state has changed, and calls the render() method again to
learn what should be on the screen. This time, this.state.date in the
render() method will be different, and so the render output will
include the updated time. React updates the DOM accordingly.
The last part is important: The actual state object will be update later on the line, not directly when the setState method has been called.
On the same page:
React may batch multiple setState() calls into a single update for
performance.
Because this.props and this.state may be updated asynchronously, you
should not rely on their values for calculating the next state.
componentWillMount() {
let dID=this.props.match.params.datumID;
this.setState({datumID: dID});
console.log(dID);
console.log(this.state.datumID);
}
I'm just trying use setState() method.
But the problem is it is not working.
Here is what I get as output:
First console.log() : 66
Second console.log(): null
this.setState accepts a second argument as callback which is fired after the state is successfully changed.
componentWillMount() {
let dID=this.props.match.params.datumID;
console.log(dID);
this.setState({datumID: dID},()=>console.log(this.state.datumID));
}
side note : Move your code to componentDidMount.
componentWillMount() is invoked immediately before mounting occurs. It
is called before render(), therefore setting state in this method
will not trigger a re-render. Avoid introducing any side-effects or
subscriptions in this method.
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
If you need to set the state based on the previous state,
read about the updater argument below.
this.setState((prevState, props) => {
return {datumID: props.match.params.datumID};
});
Because SetState() is an asynchronous function, use below code
componentWillMount() {
let dID=this.props.match.params.datumID;
this.setState({datumID: dID},
function(){
console.log(this.state.datumID)});
console.log(dID);
}
and if possible try to avoid compenentWillMount since it would be deprecated soon
setState() being an asynchronous function it is in progress of updating the state and javascript being single-threaded language it will execute the next line of code. So if you want to see the state value set you have to do something like this.
componentDidMount=()=> {
let dID=this.props.match.params.datumID;
this.setState({
datumID: dID
},()=>{
console.log(dID);
console.log(this.state.datumID);
});
}
Also I would recommend you to use componentDidMount as willMount won't work in the future as it is deprecated
this.setState is an asynchronous function that takes time and passes the newly assigned
state value over all of the React's life-cycle functions in order to update a state and trigger the re rendering of a component. Your first console logs out the value that is assigned to set state and the next console logs out the value that is currently residing in the state this.state.datumID. if you need to perform operations after setting state you can pass a callback that is triggered after a state is successfully updated.
this.setState({datumID: dID}, () => console.log(this.state.datumID) ); // this will log the updated value
Another thing I want to point out is componentWillMount will wont work in the future release. If you want to do something after DOM is rendered, use componentDidMount or you can perform pre-render task in the constructor of your Class Component.
What's the correct way to set the state after a redux action is called? Before I used to do it using the componentWillReceiveProps but now as I read, it's considered legacy and should be avoided. The question is, how should I set the state without this method?
I'll give you an example:
componentDidMount() {
this.props.getProfile();
}
Let's say I call this getProfile action in componentDidMount() and as a result I get a profile object which among other things, contains a simple string field, let's say color: "red".
Based on this color field that I got from calling getProfile(), I want to setState and call another redux action without performing any click action or anything. I want to call this.props.getFavoriteColor(this.state.color)
What's the best practice?
static getDerivedStateFromProps(nextProps, prevState)
The new function which main responsibility is ensuring that the state and props are in sync for when it is required. It’s main job is replacing componentWillReceiveProps
checkout the docus: https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops
I would do something like below:
async componentDidMount() {
const {color} = await this.props.getProfile();
this.props.getFavoriteColor(color)
}
componentWillReceiveProps(nextProps) {
// Check to see if the requestRefresh prop has changed
if (nextProps.requestRefresh !== this.props.requestRefresh) {
this.setState({loading: true}, this.updateData);
}
}
As far as my understanding goes, this lifecycle hook is called when a Component's properties are updated by the parent.
This piece of code checks if the requestRefresh property is different (one to update and one that it currently has)
Now what i dont understand is this , this.updateData);
why is this with the setState method. Please help me understand
Secondly where does prevState come from and which lifecycle hook can update it
the setState method can be called with a callback as its second parameter, mainly to handle operations which need to be done when the state is fully updated.
In your example this.updateData is the callback.
setState's first argument is also a function, with the signature (prevState, props) => stateChange, this is allowing you to get access to the previous state when performing updates.
You may want to check the official doc for further details :
https://reactjs.org/docs/react-component.html#setstate
The React maintainers discourage the use of componenetWillReceiveProps.
From the React docs:
It is recommended that you use the static getDerivedStateFromProps lifecycle instead of UNSAFE_componentWillReceiveProps. Learn more about this recommendation here.
To answer your question: prevstate is the previous state, so it is the state of your component before new props are received which in turn might chnage the new state. You can also hanlde prevstate in the static getDerivedStateFromProps method:
static getDerivedStateFromProps(nextProps, prevState)
getDerivedStateFromProps is invoked after a component is instantiated as well as when it receives new props. It should return an object to update state, or null to indicate that the new props do not require any state updates.
I see that setState is async. So if I were to call:
this.setState({ variable: true });
and immediately call:
this.setState({ variable: false });
before render is called, am I guaranteed that 'variable' will be false when React is finished processing? In other words, are the async operations sync? Will render be called twice, or will 'variable' be overwritten and render called once with variable=false?
From the react docs for setState:
setState() does not always immediately update the component. It may
batch or defer the update until later. This makes reading this.state
right after calling setState() a potential pitfall. Instead, use
componentDidUpdate or a setState callback (setState(updater,
callback)), either of which are guaranteed to fire after the update
has been applied. If you need to set the state based on the previous
state, read about the updater argument below.
So your logic should not rely on setState execution time. If you like to control render you should consider using shouldComponentUpdate(nextProps, nextState).
Use shouldComponentUpdate() to let React know if a component’s
output is not affected by the current change in state or props. The
default behavior is to re-render on every state change, and in the
vast majority of cases you should rely on the default behavior.
It is best not to rely upon this behavior. It will only work sometimes and not others.
To reliably set multiple state properties, gather all the updates and set them in a single call:
const changes = {};
if (some logic) { changes.variable = true; }
if (some more logic) { changes.variable = false; }
this.setState(changes);
Great question! Made me curious as well, so I whipped up this JSFiddle demonstrating this behavior.
React calls render synchronously after your event handler.
Meaning that because your are doing two updates in the same function, it won't re-render until after the function completes. That means that in each render, this.state.variable will be false.