React forceupload not resetting state - reactjs

I have in my constructor set the state of key to 0 and on CommponentDidMount have the following code:
this.setState({ key: Math.random() });
console.log(this.state.key)
this.forceUpdate();
console.log(this.state.key)
But I get the same value for state. How is that possible?

The (setState) method is behaving like async, so any console.logs or logic after it doesn't mean it will wait till the state is updated, any logic you want to make sure it's executed after the state is updated wrap it in function and pass it as a second param to (setState) like this:
this.setState({ key: Math.random() }, () => {
console.log(this.state.key)
});
Also note that you can force update by using the (setState) with empty object like this: this.setState({});

Related

State remains the same after calling setState, even in the callback of setState

I'm facing with weird bug related to setState. I know that it is asynchronous, thus I added console.log(this.state) in the callback function of setState, but state remains the same, and no changes are reflected on app. Here is code:
if (response && response.data && response.data.data) {
if (this._isMounted) {
const arrangedSenderEmailAddresses = arrangeEmailAddresses(response.data.data);
console.log('update data: ', arrangedSenderEmailAddresses);
this.setState({ emailAddresses: arrangedSenderEmailAddresses }, () => {
console.log('state after update: ', this.state.emailAddresses);
});
}
}
response is object retrieved from backend.
console.log('update data: ', arrangedSenderEmailAddresses) shows new data that should be set on state, but in callback:
console.log('state after update: ', this.state.emailAddresses); shows old state.
Did anyone face with such bug?
Even in the callback it will be using the previous value of state, as you are passing in this.state to the console log, which doesn't get re-evaluated in that callback, but gets given the old state.
From the React docs:
The second parameter to setState() is an optional callback function that will be executed once setState is completed and the component is re-rendered. Generally we recommend using componentDidUpdate() for such logic instead.

set the state through a function in reactjs

I am checking a condition and if that condition holds true then through function a want to change the state. i tries but i console it is still showing false only. it will be really helpful if you suggest good way to to it,
this.state = {
popUpStatus:false,
}
handlePopUp = () => {
this.setState({
popUpStatus: true,
});
}
if(a > 100){
this.handlePopUp;
console.log(popUpStatus)l // false
}
this.setState() is an asynchronous call. Therefore, You should not check this.state.popUpStat value right after calling this.setState().
The correct way to do so is passing a callback function as a second parameter in this.setState() call like
this.setState({
popUpStatus: true,
},()=>console.log(this.state.popUpStatus))
setState function does not update the state immediately. It just enqueues the changes. popUpStatus will have a different value once the component is re-rendered.
"setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. Think of setState() as a request rather than an immediate command to update the component....."
You can read more on setState here https://reactjs.org/docs/react-component.html#setstate
To test it, you can log it in your render function, and check how it updates.
You have to display this.state.popUpStatus
Replace console.log(popUpStatus) with console.log(this.state.popUpStatus)
Try to do this:
this.handlePopUp();
console.log(this.state.popUpStatus);
But consider that setState is async function so you have to do this:
this.setState({
popUpStatus: true,
}, ()=> { console.log(this.state.popUpStatus); });
Perhaps with hooks should be better:
useEffect(()=> { setPopUpStatus(a>100); }, [a])

react table: refresh table after new data received

I want to refresh my react table after new data is received. I was expecting I trigger this when I change state, however it doesnt work.
Below is state and the update function:
this.state = {
switchListSelected: [],
switchListData: [],
interfaceStatusData: [],
interfaceErrorsData: []
}
updateParentState(data, element){
this.setState(prevState => {
return prevState[element].push(data)
}
}
You are using setState wrong. You should call setState with the new state (or an updater function which returns the new state) and optionally a callback which will be called when the update is done. You can check the usage of setState in the react docs here.
In your example the updateParentState function should look like this:
updateParentState = (data, element) => {
this.setState({
...this.state,
[element]: [...this.state[element], data]
})
}
Note that the state of a component should never be mutated directly. Hence the creation of a new array with the spread operator instead of Array.push which mutates the array.
2 issues here :
When using setState you need to return an object of the state's attributes to update, here you return the result of prevState[element].push(data) (the array length).
You are mutating the array by using Array.push(), you need to use immutable pattern updates to correctly trigger a render with your updated state.
This should work for your case :
this.setState(prevState => ({
[element]: [...prevState[element], data],
}));

React - how to add new element in array type state?

I have refereed this , this and this link to find solution but none of them work for me.
I have decleared state with array type and other state with null.
this.state = { from: '', to: '',journeyDate: '',searchDetails: [] }
As user fill up search form with source city , destination city and journey date I set these state like below .
let from = this.state.from;
let to = this.state.to;
let journeyDate = moment(this.state.journeyDate).format('YYYY-MM-DD');
final step to push these all variables into searchDetails array state. for that I have tried below options but none of them worked.
OPTION 1
this.setState({ searchDetails: [...this.state.searchDetails, from] });
OPTION 2
this.setState(prevState => ({
searchDetails: [...prevState.searchDetails, from]
}))
OPTION 3
let newState = this.state.searchDetails.slice();
newState.push(from);
this.setState({
searchDetails: newState
});
console.log('final state is : ' + this.state.searchDetails);
every time console log remains empty.
any advice ?
Actually setState is an asynchronous method. That means right after writing setState, you cannot expect the state to be changed immediately. So console.log right after setState may show you last state instead of new state. If you want to log the updated state then use the callback of setState which is called when state is updated like this
this.setState({ searchDetails: [...this.state.searchDetails, from] }, () => {
console.log(this.state.searchDetails)
});
Try :
this.setState({
searchDetails: newState // use any of your 3 methods to set state
},() => {
console.log('final state is : ' + this.state.searchDetails);
});
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.
For More Detail, Please read : https://reactjs.org/docs/react-component.html#setstate

When to use React setState callback

When a react component state changes, the render method is called. Hence for any state change, an action can be performed in the render methods body. Is there a particular use case for the setState callback then?
Yes there is, since setState works in an asynchronous way. That means after calling setState the this.state variable is not immediately changed. so if you want to perform an action immediately after setting state on a state variable and then return a result, a callback will be useful
Consider the example below
....
changeTitle: function changeTitle (event) {
this.setState({ title: event.target.value });
this.validateTitle();
},
validateTitle: function validateTitle () {
if (this.state.title.length === 0) {
this.setState({ titleError: "Title can't be blank" });
}
},
....
The above code may not work as expected since the title variable may not have mutated before validation is performed on it. Now you may wonder that we can perform the validation in the render() function itself but it would be better and a cleaner way if we can handle this in the changeTitle function itself since that would make your code more organised and understandable
In this case callback is useful
....
changeTitle: function changeTitle (event) {
this.setState({ title: event.target.value }, function() {
this.validateTitle();
});
},
validateTitle: function validateTitle () {
if (this.state.title.length === 0) {
this.setState({ titleError: "Title can't be blank" });
}
},
....
Another example will be when you want to dispatch and action when the state changed. you will want to do it in a callback and not the render() as it will be called everytime rerendering occurs and hence many such scenarios are possible where you will need callback.
Another case is a API Call
A case may arise when you need to make an API call based on a particular state change, if you do that in the render method, it will be called on every render onState change or because some Prop passed down to the Child Component changed.
In this case you would want to use a setState callback to pass the updated state value to the API call
....
changeTitle: function (event) {
this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
// Call API with the updated value
}
....
this.setState({
name:'value'
},() => {
console.log(this.state.name);
});
The 1. usecase which comes into my mind, is an api call, which should't go into the render, because it will run for each state change. And the API call should be only performed on special state change, and not on every render.
changeSearchParams = (params) => {
this.setState({ params }, this.performSearch)
}
performSearch = () => {
API.search(this.state.params, (result) => {
this.setState({ result })
});
}
Hence for any state change, an action can be performed in the render methods body.
Very bad practice, because the render-method should be pure, it means no actions, state changes, api calls, should be performed, just composite your view and return it. Actions should be performed on some events only. Render is not an event, but componentDidMount for example.
Consider setState call
this.setState({ counter: this.state.counter + 1 })
IDEA
setState may be called in async function
So you cannot rely on this. If the above call was made inside a async function this will refer to state of component at that point of time but we expected this to refer to property inside state at time setState calling or beginning of async task. And as task was async call thus that property may have changed in time being. Thus it is unreliable to use this keyword to refer to some property of state thus we use callback function whose arguments are previousState and props which means when async task was done and it was time to update state using setState call prevState will refer to state now when setState has not started yet. Ensuring reliability that nextState would not be corrupted.
Wrong Code: would lead to corruption of data
this.setState(
{counter:this.state.counter+1}
);
Correct Code with setState having call back function:
this.setState(
(prevState,props)=>{
return {counter:prevState.counter+1};
}
);
Thus whenever we need to update our current state to next state based on value possed by property just now and all this is happening in async fashion it is good idea to use setState as callback function.
I have tried to explain it in codepen here CODE PEN
Sometimes we need a code block where we need to perform some operation right after setState where we are sure the state is being updated. That is where setState callback comes into play
For example, there was a scenario where I needed to enable a modal for 2 customers out of 20 customers, for the customers where we enabled it, there was a set of time taking API calls, so it looked like this
async componentDidMount() {
const appConfig = getCustomerConfig();
this.setState({enableModal: appConfig?.enableFeatures?.paymentModal }, async
()=>{
if(this.state.enableModal){
//make some API call for data needed in poput
}
});
}
enableModal boolean was required in UI blocks in the render function as well, that's why I did setState here, otherwise, could've just checked condition once and either called API set or not.

Resources