何时使用 useState() 挂钩的功能更新形式,例如。 setX(x=>x+1)

When to use functional update form of useState() hook, eg. setX(x=>x+1)

通常当我们需要更新功能组件中的状态时,我们会这样做:

function Example() {
    const [count, setCount] = React.useState(0);
    return (<div><p>You clicked {count} times</p>
                 <button onClick={() => setCount(count + 1)}>
                    Click me
                 </button>
            </div>);
}

我们何时以及为何需要使用功能更新表单?

function Example() {
    const [count, setCount] = React.useState(0);
    return (<div><p>You clicked {count} times</p>
                 <button onClick={() => setCount(c=>c + 1)}>
                    Click me
                 </button>
            </div>);
}

当 setter 可能关闭旧状态值时使用函数形式。

例如,如果启动异步请求,并且您想在完成后更新状态,则发出的请求将具有请求开始时的状态范围,这可能不是与最新的渲染状态相同。

如果刚刚更新了相同的状态值,您可能还需要使用函数形式,例如

setValue(value + 1);
// complicated logic here
if (someCondition) {
  setValue(value => value + 1);
}

因为 setValue 的第二次调用结束了旧的 value

状态更新可能是异步的:

https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

useState在这种情况下与setState相同。

两次调用set state时可以看到不同:

<button
  onClick={() => {
    setCount(count + 1);
    setCount(count + 1);
  }}
></button>;

<button
  onClick={() => {
    setCount(c => (c + 1));
    setCount(c => (c + 1));
  }}
></button>;

据此:https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

当可能调用多个 setState 挂钩(异步)时(例如,如果用户垃圾邮件点击按钮)

而且由于其异步性质,状态不会在函数内立即更新,例如:

func() {
 console.log(counter) // counter = 1
 setCounter(counter => counter + 1) // counter = 1
 console.log(counter) // counter = 1
}

还有其他用例。例如,当您在效果中调用 useState 时。如果新状态依赖于旧状态,这可能会导致无限循环。

useEffect(() => {
  setCounter(counter + 1);
}, [counter]);

您可以通过使用功能更新来避免这种情况:

useEffect(() => {
  setCounter(old => old + 1);
}, []);

功能更新形式还允许将更新功能传递给其子级,同时仍然可以访问父级的状态。

function MyButton(props){
     // return <button onClick={()=>props.onClick(count+1)}>+1</button>;  // error as count is not exposed here
     return <button onClick={()=>props.onClick(n=>(n+1))}>+1</button>;
}
function Example() {
   const [count, setCount] = React.useState(0);
   return (<div><p>Counter: {count}</p>
                <MyButton onClick={setCount}/>
           </div>);
}
ReactDOM.render(<Example/>,document.querySelector("div"));