代码之家  ›  专栏  ›  技术社区  ›  TrueWill

涉及先前状态的计算何时需要功能更新?

  •  0
  • TrueWill  · 技术社区  · 5 年前

    根据 documentation 对于 useState 反应钩:

    setState 并返回一个更新的值。

    如此给定

    const [count, setCount] = useState(initialCount);
    

    setCount(prevCount => prevCount + 1);
    

    我理解使用updater函数形式的原因 设置状态 ,因为可以批处理多个调用。然而

    使用状态

    所以我不清楚为什么上面的例子不能写成

    setCount(count + 1);
    

    Using the State Hook ).

    是否存在必须使用功能更新的情况

    (编辑:可能与 https://github.com/facebook/react/issues/14259 )

    0 回复  |  直到 5 年前
        1
  •  4
  •   Ryan Cogswell    5 年前

    在异步代码中仍然需要函数更新语法的主要场景是。想象一下 useEffect 使用效果

    下面的例子模拟了这个场景,通过一个按钮点击触发两个不同的异步进程,它们在不同的时间完成。一个按钮立即更新计数;一个按钮在不同时间触发两个异步增量而不使用函数更新语法(Naive按钮);最后一个按钮在不同时间触发两个异步增量而使用函数更新语法(Robust按钮)。

    您可以在CodeSandbox中使用它来查看效果。

    import React, { useState, useEffect } from "react";
    import ReactDOM from "react-dom";
    
    function App() {
      const [count, setCount] = useState(1);
      const [triggerAsyncIndex, setTriggerAsyncIndex] = useState(1);
      const [triggerRobustAsyncIndex, setTriggerRobustAsyncIndex] = useState(1);
      useEffect(
        () => {
          if (triggerAsyncIndex > 1) {
            setTimeout(() => setCount(count + 1), 500);
          }
        },
        [triggerAsyncIndex]
      );
      useEffect(
        () => {
          if (triggerAsyncIndex > 1) {
            setTimeout(() => setCount(count + 1), 1000);
          }
        },
        [triggerAsyncIndex]
      );
      useEffect(
        () => {
          if (triggerRobustAsyncIndex > 1) {
            setTimeout(() => setCount(prev => prev + 1), 500);
          }
        },
        [triggerRobustAsyncIndex]
      );
      useEffect(
        () => {
          if (triggerRobustAsyncIndex > 1) {
            setTimeout(() => setCount(prev => prev + 1), 1000);
          }
        },
        [triggerRobustAsyncIndex]
      );
      return (
        <div className="App">
          <h1>Count: {count}</h1>
          <button onClick={() => setCount(count + 1)}>Increment Count</button>
          <br />
          <button onClick={() => setTriggerAsyncIndex(triggerAsyncIndex + 1)}>
            Increment Count Twice Async Naive
          </button>
          <br />
          <button
            onClick={() => setTriggerRobustAsyncIndex(triggerRobustAsyncIndex + 1)}
          >
            Increment Count Twice Async Robust
          </button>
        </div>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    
    

    Edit Async state updates

    另一个可能需要功能更新的场景是,如果多个效果正在更新状态(即使是同步的)。一旦一个效果更新了状态,另一个效果就会看到过时的状态。在我看来,这种场景比异步场景更不可能出现(在大多数情况下,这似乎是一个糟糕的设计选择)。