Thursday, May 23, 2024
 Popular · Latest · Hot · Upcoming
69
rated 0 times [  72] [ 3]  / answers: 1 / hits: 20422  / 5 Years ago, thu, september 5, 2019, 12:00:00

I'm working with a deeply nested state object in React. My code base dictates that we try to stick with function components and so every time I want to update a key/value pair inside that nested object, I have to use a hook to set the state. I can't seem to get at the deeper nested items, though. I have a drop down menu w/ an onChange handler. . .inside the onChange handler is an inline function to directly setValue of whatever key/val pair is changing.



The syntax I'm using after the spread operator in each inline function is wrong, however.



As a workaround, I have resorted to factoring out the inline function to its own function that rewrites the entire state object every time the state changes, but that is extremely time consuming and ugly. I'd rather do it inline like the below:



 const [stateObject, setStateObject] = useState({

top_level_prop: [
{
nestedProp1: nestVal1,
nestedProp2: nestVal2
nestedProp3: nestVal3,
nestedProp4: [
{
deepNestProp1: deepNestedVal1,
deepNestProp2: deepNestedVal2
}
]
}
]
});

<h3>Top Level Prop</h3>

<span>NestedProp1:</span>
<select
id=nested-prop1-selector
value={stateObject.top_level_prop[0].nestedProp1}
onChange={e => setStateObject({...stateObject,
top_level_prop[0].nestedProp1: e.target.value})}
>
<option value=nestVal1>nestVal1</option>
<option value=nestVal2>nestVal2</option>
<option value=nestVal3>nestVal3</option>
</select>

<h3>Nested Prop 4</h3>

<span>Deep Nest Prop 1:</span>
<select
id=deep-nested-prop-1-selector
value={stateObject.top_level_prop[0].nestprop4[0].deepNestProp1}
onChange={e => setStateObject({...stateObject,
top_level_prop[0].nestedProp4[0].deepNestProp1: e.target.value})}
>
<option value=deepNestVal1>deepNestVal1</option>
<option value=deepNestVal2>deepNestVal2</option>
<option value=deepNestVal3>deepNestVal3</option>
</select>



The result of the code above gives me a nestProp1 and deepNestProp1 are undefined, presumably because they are never being reached/having their state changed by each selector. My expected output would be the selected option matching the value of whatever the selector's current val is (after the state changes). Any help would be greatly appreciated.


More From » reactjs

 Answers
3

I think you should be using the functional form of setState, so you can have access to the current state and update it.



Like:



setState((prevState) => 
//DO WHATEVER WITH THE CURRENT STATE AND RETURN A NEW ONE
return newState;
);


See if that helps:





function App() {

const [nestedState,setNestedState] = React.useState({
top_level_prop: [
{
nestedProp1: nestVal1,
nestedProp2: nestVal2,
nestedProp3: nestVal3,
nestedProp4: [
{
deepNestProp1: deepNestedVal1,
deepNestProp2: deepNestedVal2
}
]
}
]
});

return(
<React.Fragment>
<div>This is my nestedState:</div>
<div>{JSON.stringify(nestedState)}</div>
<button
onClick={() => setNestedState((prevState) => {
prevState.top_level_prop[0].nestedProp4[0].deepNestProp1 = 'XXX';
return({
...prevState
})
}
)}
>
Click to change nestedProp4[0].deepNestProp1
</button>
</React.Fragment>
);
}

ReactDOM.render(<App/>, document.getElementById('root'));

<script src=https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js></script>
<div id=root/>





UPDATE: With dropdown





function App() {

const [nestedState,setNestedState] = React.useState({
propA: 'foo1',
propB: 'bar'
});

function changeSelect(event) {
const newValue = event.target.value;
setNestedState((prevState) => {
return({
...prevState,
propA: newValue
});
});
}

return(
<React.Fragment>
<div>My nested state:</div>
<div>{JSON.stringify(nestedState)}</div>
<select
value={nestedState.propA}
onChange={changeSelect}
>
<option value='foo1'>foo1</option>
<option value='foo2'>foo2</option>
<option value='foo3'>foo3</option>
</select>
</React.Fragment>
);
}

ReactDOM.render(<App/>, document.getElementById('root'));

<script src=https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js></script>
<div id=root/>




[#51692] Wednesday, August 28, 2019, 5 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
alfonsok

Total Points: 386
Total Questions: 101
Total Answers: 90

Location: Puerto Rico
Member since Sun, Jun 27, 2021
3 Years ago
alfonsok questions
Sat, Jun 5, 21, 00:00, 3 Years ago
Wed, Jun 2, 21, 00:00, 3 Years ago
Mon, Oct 5, 20, 00:00, 4 Years ago
;