React: Setting State for Deeply Nested Objects w/ Hooks

后端 未结 2 1344
终归单人心
终归单人心 2021-02-08 17:34

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

相关标签:
2条回答
  • 2021-02-08 18:05

    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"/>

    0 讨论(0)
  • 2021-02-08 18:09

    Another approach is to use the useReducer hook

    const App = () => {      
      const reducer = (state, action) =>{
        return {...state, [action.type]: action.payload}
      }
      
      const [state, dispatch] = React.useReducer(reducer,{
        propA: 'foo1',
        propB: 'bar1'
      });
      
      const changeSelect = (prop, event) => {
        const newValue = event.target.value;
        dispatch({type: prop, payload: newValue});
      }
      
      return(
        <React.Fragment>
          <div>My nested state:</div>
          <div>{JSON.stringify(state)}</div>
          <select 
            value={state.propA} 
            onChange={(e) => changeSelect('propA', e)}
          >
            <option value='foo1'>foo1</option>
            <option value='foo2'>foo2</option>
            <option value='foo3'>foo3</option>
          </select>
          <select 
            value={state.propB} 
            onChange={(e) => changeSelect('propB', e)}
          >
            <option value='bar1'>bar1</option>
            <option value='bar2'>bar2</option>
            <option value='bar3'>bar3</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"/>

    0 讨论(0)
提交回复
热议问题