React Hooks useState() with Object

前端 未结 9 1686
猫巷女王i
猫巷女王i 2020-12-02 06:04

What is the correct way of updating state, is a nested object, in React with Hooks?

export Example = () => {
  const [exampleState, setExampleState] = use         


        
相关标签:
9条回答
  • 2020-12-02 06:58

    Initially I used object in useState, but then I moved to useReducer hook for complex cases. I felt a performance improvement when I refactored the code.

    useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.

    useReducer React docs

    I already implemented such hook for my own use:

    /**
     * Same as useObjectState but uses useReducer instead of useState
     *  (better performance for complex cases)
     * @param {*} PropsWithDefaultValues object with all needed props 
     * and their initial value
     * @returns [state, setProp] state - the state object, setProp - dispatch 
     * changes one (given prop name & prop value) or multiple props (given an 
     * object { prop: value, ...}) in object state
     */
    export function useObjectReducer(PropsWithDefaultValues) {
      const [state, dispatch] = useReducer(reducer, PropsWithDefaultValues);
    
      //newFieldsVal={[field_name]: [field_value], ...}
      function reducer(state, newFieldsVal) {
        return { ...state, ...newFieldsVal };
      }
    
      return [
        state,
        (newFieldsVal, newVal) => {
          if (typeof newVal !== "undefined") {
            const tmp = {};
            tmp[newFieldsVal] = newVal;
            dispatch(tmp);
          } else {
            dispatch(newFieldsVal);
          }
        },
      ];
    }
    

    more related hooks.

    0 讨论(0)
  • 2020-12-02 07:01

    I'm late to the party.. :)

    @aseferov answer works very well when the intention is to re-enter the entire object structure. However, if the target/goal is to update a specific field value in an Object, I believe the approach below is better.

    situation:

    const [infoData, setInfoData] = useState({
        major: {
          name: "John Doe",
          age: "24",
          sex: "M",
        },
    
        minor:{
          id: 4,
          collegeRegion: "south",
    
        }
    
      });
    

    Updating a specific record will require making a recall to the previous State prevState

    Here:

    setInfoData((prevState) => ({
          ...prevState,
          major: {
            ...prevState.major,
            name: "Tan Long",
          }
        }));
    

    perhaps

    setInfoData((prevState) => ({
          ...prevState,
          major: {
            ...prevState.major,
            name: "Tan Long",
          },
          minor: {
            ...prevState.minor,
            collegeRegion: "northEast"
    
        }));
    

    I hope this helps anyone trying to solve a similar problem.

    0 讨论(0)
  • 2020-12-02 07:02

    You can pass new value like this

      setExampleState({...exampleState,  masterField2: {
            fieldOne: "c",
            fieldTwo: {
               fieldTwoOne: "d",
               fieldTwoTwo: "e"
               }
            },
       }})
    
    0 讨论(0)
提交回复
热议问题