What's the best alternative to update nested React state property with setState()?

后端 未结 4 1309
甜味超标
甜味超标 2021-02-08 08:45

I\'ve been thinking about what would be the best way among these options to update a nested property using React setState() method. I\'m also opened to more efficient methods co

相关标签:
4条回答
  • 2021-02-08 09:12

    You can try with nested Object.Assign:

     const newState = Object.assign({}, state, {
      inputs: Object.assign({}, state.inputs, {
        username: Object.assign({}, state.inputs.username, { touched: true }),
      }),
    });
    

    };

    You can also use spread operator:

    {
      ...state,
      inputs: {
        ...state.inputs,
          username: {
          ...state.inputs.username,
          touched: true
       }
    }
    

    This is proper way to update nested property and keep state immutable.

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

    I can think of a few other ways to achieve it.

    Deconstructing every nested element and only overriding the right one :

    this.setState(prevState => ({
        inputs: {
            ...prevState.inputs,
            username: {
                ...prevState.inputs.username,
                touched: true
            }
        }
    }))
    

    Using the deconstructing operator to copy your inputs :

    this.setState(prevState => {
        const inputs = {...prevState.inputs};
        inputs.username.touched = true;
        return { inputs }
    })
    

    EDIT

    First solution using computed properties :

    this.setState(prevState => ({
        inputs: {
            ...prevState.inputs,
            [field]: {
                ...prevState.inputs[field],
                [action]: value
            }
        }
    }))
    
    0 讨论(0)
  • 2021-02-08 09:26

    I made a util function that updates nested states with dynamic keys.

     function _recUpdateState(state, selector, newval) {
              if (selector.length > 1) {
                let field = selector.shift();
                let subObject = {};
                try {
                  //Select the subobject if it exists
                  subObject = { ..._recUpdateState(state[field], selector, newval) };
                } catch {
                  //Create the subobject if it doesn't exist
                  subObject = {
                    ..._recUpdateState(state, selector, newval)
                  };
                }
                return { ...state, [field]: subObject };
              } else {
                let updatedState = {};
                updatedState[selector.shift()] = newval;
                return { ...state, ...updatedState };
              }
            }
            
            function updateState(state, selector, newval, autoAssign = true) {
              let newState = _recUpdateState(state, selector, newval);
              if (autoAssign) return Object.assign(state, newState);
              return newState;
            }
            
    // Example
    
    let initState = {
           sub1: {
              val1: "val1",
              val2: "val2",
              sub2: {
                 other: "other value",
                 testVal: null
              }
           }
        } 
        
        console.log(initState)
        updateState(initState, ["sub1", "sub2", "testVal"], "UPDATED_VALUE")
        console.log(initState)

    You pass a state along with a list of key selectors and the new value.

    You can also set the autoAssign value to false to return an object that is a copy of the old state but with the new updated field - otherwise autoAssign = true with update the previous state.

    Lastly, if the sequence of selectors don't appear in the object, an object and all nested objects with those keys will be created.

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

    Use the spread operator

      let {foo} = this.state;
    
      foo = {
        ...foo,
        bar: baz
      }
    
      this.setState({
        foo
      })
    
    0 讨论(0)
提交回复
热议问题