Javascript React Hooks useState() 与 Object

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/54150783/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 05:12:34  来源:igfitidea点击:

React Hooks useState() with Object

javascriptreactjsreact-hooks

提问by isaacsultan

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

在 React with Hooks 中,更新状态的正确方法是嵌套对象是什么?

export Example = () => {
  const [exampleState, setExampleState] = useState(
  {masterField: {
        fieldOne: "a",
        fieldTwo: {
           fieldTwoOne: "b"
           fieldTwoTwo: "c"
           }
        }
   })

How would one use setExampleStateto update exampleStateto a(appending an field)?

如何使用setExampleState更新exampleStatea(附加字段)?

const a = {
masterField: {
        fieldOne: "a",
        fieldTwo: {
           fieldTwoOne: "b",
           fieldTwoTwo: "c"
           }
        },
  masterField2: {
        fieldOne: "c",
        fieldTwo: {
           fieldTwoOne: "d",
           fieldTwoTwo: "e"
           }
        },
   }
}

b(Changing values)?

b(改变值)?

const b = {masterField: {
        fieldOne: "e",
        fieldTwo: {
           fieldTwoOne: "f"
           fieldTwoTwo: "g"
           }
        }
   })

回答by aseferov

You can pass new value like this

您可以像这样传递新值

  setExampleState({...exampleState,  masterField2: {
        fieldOne: "c",
        fieldTwo: {
           fieldTwoOne: "d",
           fieldTwoTwo: "e"
           }
        },
   }})

回答by Ilyas Assainov

Generally you should watch out for deeply nested objects in React state. To avoid unexpected behavior, the state should be updated immutably. When you have deep objects, you end up deep cloning them for immutability, which can be quite expensive in React. Why?

通常,您应该注意 React 状态中的深层嵌套对象。为了避免意外行为,状态应该不可变地更新。当您拥有深层对象时,您最终会深入克隆它们以实现不变性,这在 React 中可能非常昂贵。为什么?

Once you deep clone the state, React will recalculate and re-render everything that depends on the variables, even though they haven't changed!

一旦你深度克隆状态,React 将重新计算并重新渲染依赖于变量的一切,即使它们没有改变!

So, before trying to solve your issue, think how you can flatten the state first. As soon as you do that, you will find beautiful tools that will help dealing with large states, such as useReducer().

因此,在尝试解决您的问题之前,请先考虑如何使状态变平。一旦你这样做了,你就会发现有助于处理大状态的漂亮工具,比如 useReducer()。

In case you thought about it, but are still convinced you need to use a deeply nested state tree, you can still use useState() with libraries like immutable.jsand Immutability-helper. They make it simple to update or clone deep objects without having to worry about mutability.

如果您考虑过,但仍然确信您需要使用深度嵌套的状态树,您仍然可以将 useState() 与诸如immutable.js和Immutability -helper 之类的库一起使用。它们使更新或克隆深层对象变得简单,而不必担心可变性。

回答by Maheshvirus

If anyone is searching for useState()hooks update for object

如果有人正在搜索 useState()挂钩更新对象

- Through Input

        const [state, setState] = useState({ fName: "", lName: "" });
        const handleChange = e => {
        const { name, value } = e.target;
        setState(prevState => ({
            ...prevState,
            [name]: value
        }));
        };

        <input
            value={state.fName}
            type="text"
            onChange={handleChange}
            name="fName"
        />
        <input
            value={state.lName}
            type="text"
            onChange={handleChange}
            name="lName"
        />
   ***************************

 - Through onSubmit or button click

        setState(prevState => ({
            ...prevState,
            fName: 'your updated value here'
         }));

回答by Kavitha Vikas

Thanks Philip this helped me - my use case was I had a form with lot of input fields so I maintained initial state as object and I was not able to update the object state.The above post helped me :)

谢谢菲利普,这帮助了我 - 我的用例是我有一个包含很多输入字段的表单,所以我将初始状态保持为对象,但我无法更新对象状态。上面的帖子帮助了我:)

const [projectGroupDetails, setProjectGroupDetails] = useState({ "projectGroupId": "", "projectGroup": "DDD", "project-id": "", "appd-ui": "", "appd-node": ""

const [projectGroupDetails, setProjectGroupDetails] = useState({ "projectGroupId": "", "projectGroup": "DDD", "project-id": "", "appd-ui": "", "appd-node": " ”

});

const inputGroupChangeHandler = (event) => {

const inputGroupChangeHandler = (事件) => {

    setProjectGroupDetails((prevState) => ({
        ...prevState,
        [event.target.id]: event.target.value
    }));

}

回答by Olamigoke Philip

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.

当目的是重新输入整个对象结构时,@aseferov 答案非常有效。但是,如果目标/目标是更新对象中的特定字段值,我相信下面的方法会更好。

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

更新特定记录将需要召回之前的状态 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.

我希望这可以帮助任何试图解决类似问题的人。

回答by Gonzalo

I leave you a utility function to inmutably update objects

我给你留下了一个实用函数来不变地更新对象

/**
 * Inmutable update object
 * @param  {Object} oldObject     Object to update
 * @param  {Object} updatedValues Object with new values
 * @return {Object}               New Object with updated values
 */
export const updateObject = (oldObject, updatedValues) => {
  return {
    ...oldObject,
    ...updatedValues
  };
};

So you can use it like this

所以你可以像这样使用它

const MyComponent = props => {

  const [orderForm, setOrderForm] = useState({
    specialities: {
      elementType: "select",
      elementConfig: {
        options: [],
        label: "Specialities"
      },
      touched: false
    }
  });


// I want to update the options list, to fill a select element

  // ---------- Update with fetched elements ---------- //

  const updateSpecialitiesData = data => {
    // Inmutably update elementConfig object. i.e label field is not modified
    const updatedOptions = updateObject(
      orderForm[formElementKey]["elementConfig"],
      {
        options: data
      }
    );
    // Inmutably update the relevant element.
    const updatedFormElement = updateObject(orderForm[formElementKey], {
      touched: true,
      elementConfig: updatedOptions
    });
    // Inmutably update the relevant element in the state.
    const orderFormUpdated = updateObject(orderForm, {
      [formElementKey]: updatedFormElement
    });
    setOrderForm(orderFormUpdated);
  };

  useEffect(() => {
      // some code to fetch data
      updateSpecialitiesData.current("specialities",fetchedData);
  }, [updateSpecialitiesData]);

// More component code
}

If not you have more utilities here : https://es.reactjs.org/docs/update.html

如果没有,您还有更多实用程序:https: //es.reactjs.org/docs/update.html

回答by Gabriele Rapone

That's an ES6 solution I came up with that allows to update any object nested in the state:

这是我想出的 ES6 解决方案,它允许更新嵌套在状态中的任何对象:

export const updateStateObject = (object, keyToUpdate, newValue) => {

  let updatedObject = {};

  // Iterate over the object
  Object.entries(object).forEach(([key, value]) => {

    // Update the chosen key
    if (key === keyToUpdate) Object.assign(updatedObject, { [key]: newValue });

    // If the iterated key doesn't match the given key return the current value
    else if (key !== keyToUpdate) Object.assign(updatedObject, { [key]: value });
  });

  return updatedObject;
};

Then when you have to update the state just call:

然后,当您必须更新状态时,只需调用:

setState({
  ...state,
  key: updateStateObject(object, keyToUpdate, newValue)
})