React nested state object not updating - reactjs

I am trying to update a nested state object (checkedObjects) in a react class component, to track when checkboxes are checked and unchecked. checkedObjects has the following structure:
checkedObjects: {
[assignmentName]: boolean,
}
verifyObjects is a local variable that checks if the new name property was actually received. When I console out the contents of these objects however, checkedObjects is empty, while the new property was added to verifyObjects (see screenshot below). Can anyone advise why the state variable checkedObjects is not updating immediately?
Screenshot:
Code Snippet:
this.state = {
checkedObjects: {},
};
incrementCount(totalCount, id, checked, assignmentName) {
console.log("increment: totalCount", totalCount, " ; id:", id, checked);
// If a checkbox is clicked with an assignment name store on the checkedObjects
if (assignmentName) {
let verifyObjects = { ...this.state.checkedObjects };
verifyObjects[assignmentName] = checked;
this.setState(prevState => {
let tempObj = {...prevState.checkedObjects}
tempObj[assignmentName] = checked;
return {checkedObjects: tempObj}
});
console.log("SelectedAssignmentsObj:", this.state.checkedObjects);
console.log("VerifiedObject:", verifyObjects);
} //if
}

State updates don't occur instantaneously. When we call the setState() function, it schedules a state update. Try console logging tempObj to see the value that is being put inside of this.state.checkedObjects.
In short, your code is working the way it should but you wont be able to see the state update right after calling this.setState() [because the state update is scheduled and didnt happen at that instant]. If you want to ensure that your state did update the way you wanted, can add a dummy button on the side that console logs the value of this.state.checkedObjects or you can use the chrome extension React Developer Tools to find out the values in the state object.

Related

How to push/force state update in reactJS

I know there is already a lot of questions related to state updates. But I'm not able to get my head around why it is not working. or is there any simple way to force update state ?
I have a click handler that does this
Below code works perfectly fine
onButtonClick(){
var state = JSON.parse(JSON.stringify(this.state)) // To mutate the state;
state.name = "newName";
this.setState(state)
}
Below doesn't update the state.items with "Hellow"
onButtonClick(){
var state = JSON.parse(JSON.stringify(this.state)) // To mutate the state;
state.items.push("Fourth")
this.setState(state)
}
I have used similar example in a project I'm building but not able to figure out why above syntax isn't working.
Open https://imvetri.github.io/ui-editor/
Click "Editor" on left
Open debugger
Move mouse on black area and right click.
Set breakpoint at line #46. Its the render function, if you inspect this.state you will notice that the this.state.items wouldn't have changed
Expected:
First
Second
Third
Fourth
Actual:
First
Second
Third
Mutate the state to trigger the update, something like this:
onButtonClick(){
var items = this.state.items;
this.setState({items: [...items, "Helow"])
}

Updating a value that's within an array within an array in a state

I'm trying to update the state of the id value in shoeList. Currently I have a textfield that allows for entering of a new ID and I want the state to update when the OK button is clicked.
Here is some of the relevant code:
state = {
editingToggle: false,
shoeList : [
{name: 'bob', id: '123213-0', shoeSize: 'L'}
],
}
<TextInput className='text-area-header' id="textM" width="m" type="text" placeholder={this.state.shoeList[0].id} />
<Button className="ok-button" variant="tertiary" size ='xs' type="button" handleClick={this.saveHeader}>OK</Button>
saveHeader(e) {
this.setState(state=> ({
shoeList[0].name:
}))
alert('Header changed to ' + this.state.shoeList[0].id);
e.preventDefault();
}
I'm not sure what to put in this.setState as I haven't found anything on how to update nested values through a google search. Also whenever I put a value attribute to the TextInput tags it doesn't allow me to edit in the textinput on the webpage anymore. Any help would be great
Consider this example:
saveHeader() {
this.state.shoeList[0].id = 'newid'
this.setState({ shoeList: this.state.shoeList })
}
setState() checks if the values have changed, and if not, it does not update the component. Changing a nested value does not change the reference to the array, which means that simply calling setState() is not enough.
There are two ways around this. The first is to use forceUpdate():
saveHeader() {
this.state.shoeList[0].id = 'newid'
this.forceUpdate()
}
This forces the component to re-render, even though the state didn't change.
The second way is to actually change the shoeList array by creating a new one:
saveHeader() {
let newShoeList = this.state.shoeList.slice()
newShoeList[0].id = 'newid'
this.setState({ shoeList: newShoeList })
}
Using .slice() on an array creates a new array that is completely identical. But because it is a new array, React will notice that the state changed and re-render the component.

React dev tools show empty state, console shows data

I'm having a strange issue with state in my React app. I set initial state as an empty array and in the componentDidMount() method I retrieve some data from Firebase. I put the JSON objects into a new array and call setState(), passing it the new array.
The problem is that it doesn't seem to be updating state. From what I can tell:
Render() is being called after setState
My callback on setState() is being fired
When I console.log the array that I set the state to, it looks fine
The strangest thing, when I inspect state in the Chrome React Devtools, it shows empty but for some reason I can print the array to the console using $r.state.nameOfMyObject
If I change some other piece of state directly from the dev tools, the app immediately renders and finally displays the piece of data I've been struggling with all along.
I thought maybe there was some issue with updating the array; maybe the diffing algorithm didn't go deep enough to see that the data inside the array changed. To test this, I tried to set the initial state of the object in question to null, but then set off errors throughout the app that it was trying to call various array methods on null.
I've tried walking through the app, console logging each step, but I can't find the issue.
Snippet of initial state:
state = {
fullSchedule: [],
currentSet: [],
aCoupleOfOtherObjects,
}
componentDidMount():
componentDidMount() {
const activities = [];
const projectReference = firestoreDB.collection("project").doc("revision001").collection("activities");
projectReference.get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
activities.push(doc.data());
});
});
console.log(activities);
this.setState({fullSchedule: activities});
this.setState({currentSet: activities}, () => {
console.log("State updated from DB");
});
console.log("called setstate");
}
I can't tell why the setState() method doesn't seem to be setting the state, any ideas?
Thanks!
projectReference.get() is asynchronous, and you are trying to set the state right after you call it, which won't work.
try setting the state inside then callback:
projectReference.get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
activities.push(doc.data());
});
this.setState({fullSchedule: activities, currentSet: activities});
});
This should give you a better idea of what's going on.

React Component state value not updated, when setState is called on jsonObject's property

I am working on three properties of JSON object which returns boolean values.
updateChange=(value) =>{
//Making copy of existing json Object
let newState = JSON.parse(JSON.stringify(this.state.mainValue));
// chaning property of cellular over here
newState.cellular = value;
console.log(newState);
this.setState({mainValue:newState});
//I tried setState in many different ways. But Component is not changing state value
console.log(this.state.mainValue)
};
I found why this is happening. I am using getDerivedStateFromProps in this component to look at changes made by parent to update values. This is avoiding changes made to state of the child. So I have created a state called previous state to compare the previous props and present props from parent to render. This avoids component to refresh when ever it local state values changes.
static getDerivedStateFromProps(propsnow,state){
if(state.previous !== propsnow.detailSwitches){
return{
previous :propsnow.detailSwitches,
cellular: propsnow.detailSwitches.cellular,
wifi1: propsnow.detailSwitches.wifi1,
wifi2: propsnow.detailSwitches.wifi2
};
}
return null;
}
Any examples or better practices can be helpful. Thanks
You are ONLY setting the 'mainValue' variable of your state to the value of newstate, shouldn't you be updating the whole state?
this.setState({...newState})
You can try this
this.setState(prevState => ({
mainValue: {
...prevState.mainValue,
cellular: value
}}))
It is an immutable way to update state.

Reactjs every time refreshing page on setState

I'm using MultiSelect Plugin for Select DropDown. Here onChange event I'm storing the value in setState. Here is below code :
$('#selectbox-id-onChange').multiselect({
onChange: function(option, checked) {
var newArray = this.state.options.slice();
newArray.push($(option).val());
this.setState({options: newArray});
}
});
The above code is working fine, I'm able to store the array value in state also. But the only issue is that page is refreshing everytime while storing the value in state.
Please do let me know where I'm going wrong here. I tried to figure out but couldn't get the solution.
Yes, that's what React is meant to do. If you do not want it not to re-render then you have to override the shouldComponentUpdate method.
shouldComponentUpdate() {
return false; // Will cause component to never re-render.
}

Resources