当前位置: 首页 > 知识库问答 >
问题:

使用React useState()钩子更新和合并状态对象

於乐
2023-03-14

我发现这两个反应钩文档有点混乱。使用状态钩子更新状态对象的最佳实践是哪一个?

假设一个用户希望进行以下状态更新:

INITIAL_STATE = {
  propA: true,
  propB: true
}

stateAfter = {
  propA: true,
  propB: false   // Changing this property
}

选择1

从使用React Hook一文中,我们可以看出这是可能的:

const [count, setCount] = useState(0);
setCount(count + 1);

所以我可以做:

const [myState, setMyState] = useState(INITIAL_STATE);

然后呢:

setMyState({
  ...myState,
  propB: false
});

选择2

从Hooks参考中我们得到:

与类组件中的setState方法不同,useState不会自动合并更新对象。通过将函数更新程序窗体与对象扩展语法相结合,可以复制此行为:

setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});

据我所知,两者都有效。那么,有什么区别呢?哪一个是最佳实践?我应该使用pass函数(选项2)访问前一个状态,还是应该使用扩展语法(选项1)访问当前状态?

共有3个答案

养翔
2023-03-14

最佳做法是使用单独调用:

const [a, setA] = useState(true);
const [b, setB] = useState(true);

选项1可能会导致更多的bug,因为这样的代码通常会在一个具有过时值myState的闭包中结束。

当新状态基于旧状态时,应使用选项2:

setCount(count => count + 1);

对于复杂的状态结构考虑使用UrError

对于共享某些形状和逻辑的复杂结构,您可以创建自定义钩子:

function useField(defaultValue) {
  const [value, setValue] = useState(defaultValue);
  const [dirty, setDirty] = useState(false);
  const [touched, setTouched] = useState(false);

  function handleChange(e) {
    setValue(e.target.value);
    setTouched(true);
  }

  return {
    value, setValue,
    dirty, setDirty,
    touched, setTouched,
    handleChange
  }
}

function MyComponent() {
  const username = useField('some username');
  const email = useField('some@mail.com');

  return <input name="username" value={username.value} onChange={username.handleChange}/>;
}
宗安宁
2023-03-14

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

>

  • 通过输入

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

    通过onSubmit或按钮单击

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

  • 包翔
    2023-03-14

    这两个选项都是有效的,但是就像类组件中的setState一样,在更新从已经处于状态的东西派生的状态时,您需要小心。

    例如,如果您连续更新计数两次,如果您不使用更新状态的函数版本,它将无法正常工作。

    const { useState } = React;
    
    function App() {
      const [count, setCount] = useState(0);
    
      function brokenIncrement() {
        setCount(count + 1);
        setCount(count + 1);
      }
    
      function increment() {
        setCount(count => count + 1);
        setCount(count => count + 1);
      }
    
      return (
        <div>
          <div>{count}</div>
          <button onClick={brokenIncrement}>Broken increment</button>
          <button onClick={increment}>Increment</button>
        </div>
      );
    }
    
    ReactDOM.render(<App />, document.getElementById("root"));
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    
    <div id="root"></div>
     类似资料:
    • 问题内容: 我发现React Hooks文档的这两部分有些令人困惑。使用状态挂钩更新状态对象的最佳实践是哪一种? 想象一下要进行以下状态更新: 选项1 从使用React Hook的文章中,我们可以做到: 所以我可以做: 然后: 选项2 从钩子参考中我们可以得出: 与类组件中的setState方法不同,useState不会自动合并更新对象。您可以通过将函数更新程序形式与对象传播语法结合使用来复制此行

    • 我有一个对象的状态数组: 我有一个添加按钮,用于将对象添加到数组中,这是onclick事件的主体:

    • 它几乎添加了一个对象,该对象包含来自主窗体的子窗体的值。 这是我用作按钮的函数的函数。 这将一个新对象添加到一个名为的状态,该状态是一个对象数组。 提前谢了。

    • 在基于类的React组件中,我们可以使用setState的函数形式定义处理函数,例如: 其中,两个参数表示传递给此组件的先前状态和更新的道具。 类似地,我们有一个函数形式,使用useState钩子在函数组件中设置状态,如下所示: 但正如我们所看到的,useState钩子中的函数形式缺少表示更新的道具的第二个参数 这是React开发团队故意留下的吗?在useState钩子中设置状态时,我们如何访问更

    • 我正在尝试使用状态将一个表单输入值复制到另一个表单输入值,但状态没有更新 我创建了一个带有按钮的表单,其中左侧表单输入的值应复制到右侧表单输入。这是我的代码: 无论我做什么,dbSecName的状态都不会改变。我试着设置一个新的常量。我尝试使onclick函数异步并等待。如果我为我试图设置的变量的值添加,我可以正确地看到它,但是dbSecName的console.log总是显示原始值。 我真的不知

    • 问题内容: 我正在尝试新的React Hooks,并有一个带有计数器的Clock组件,该计数器应该每秒增加一次。但是,该值不会增加到超过一。 问题答案: 原因是传递给的闭包中的回调仅访问第一个渲染器中的变量,而无法访问后续渲染器中的新值,因为第二次未调用。 回调中的值始终为0 。 就像您熟悉的状态挂钩一样,状态挂钩有两种形式:一种是处于更新状态的状态,另一种是将当前状态传入的回调形式。您应该使用第