【问题标题】:React Hooks - using useState vs just variablesReact Hooks - 使用 useState 与仅使用变量
【发布时间】:2020-02-03 17:45:23
【问题描述】:

React Hooks 为我们提供了 useState 选项,我经常看到 Hooks 与 Class-State 的比较。但是 Hooks 和一些常规变量呢?

例如,

function Foo() {
    let a = 0;
    a = 1;
    return <div>{a}</div>;
}

我没有使用 Hooks,它会给我同样的结果:

function Foo() {
    const [a, setA] = useState(0);
    if (a != 1) setA(1); // to avoid infinite-loop
    return <div>{a}</div>;
}

那么有什么区别呢?在这种情况下使用 Hooks 更加复杂......那么为什么要开始使用它呢?

【问题讨论】:

  • 您正在比较 2 个不同的事物。带有钩子的第二个函数具有更新数据的能力。第一个并没有真正做任何事情。你可以用let a = 1; return &lt;div&gt;{a}&lt;/div&gt; 初始化它,你会得到同样的结果。

标签: javascript node.js reactjs react-hooks


【解决方案1】:

原因是如果你useState 它会重新渲染视图。变量本身只会改变内存中的位,并且您的应用程序的状态可能与视图不同步。

比较这个例子:

function Foo() {
    const [a, setA] = useState(0);
    return <div onClick={() => setA(a + 1)}>{a}</div>;
}

function Foo() {
    let a = 0;
    return <div onClick={() => a + 1}>{a}</div>;
}

在这两种情况下,a 在点击时都会发生变化,但只有当您使用 useState 时,视图才能正确显示 a 的当前值。

【讨论】:

  • 谢谢!因此,如果我不需要渲染视图 - 只是一种将我的数据(道具)组织到某个数组中的方法 - 我可以使用 'let' 吗?它对我有用,我只想知道它是否可以接受。
  • @MosheNagar 如果您从 props 派生数据,建议使用局部变量而不是保持数据处于状态,因为组件无论如何都会在 prop 更改时重新呈现,因此视图将与数据同步。将它们置于状态只会导致不必要的重新渲染 - 首先是道具更改,然后是状态更改。
  • 另一种看待这个答案的方法是认为在第二种情况下,变量a 将在它完成执行后被垃圾收集,而在第一种情况下,因为它利用了@987654327 @它将保留a的值
  • 如果他不想重新渲染视图,他仍然可以使用useRef。如果他应该使用局部变量或 React 引用,问题仍然存在。例如。如果您需要清除超时,或者使用 axios 进行持续的 http 请求,您是否将超时或 axios 源存储在变量或 React ref 中?
  • @Tom 一般规则是对派生状态使用本地变量。对于其他任何事情,请使用useRef(如果您不想重新渲染)或useState(如果您想重新渲染)。在计时器的情况下,由于它们是副作用,它们应该在useEffect 钩子中启动。如果您只想将timerId 用于清理目的,您可以将其保存在handler 的局部变量中。如果您希望能够从组件中的其他位置清除计时器,您应该使用useRef。将timerId 存储在组件 的局部变量中是错误的,因为局部变量在每次渲染时都会“重置”。
【解决方案2】:

您的第一个示例之所以有效,是因为数据基本上永远不会改变。使用setState 的切入点是在状态挂起时重新渲染整个组件。因此,如果您的示例需要某种状态更改或管理,您将很快意识到更改值是必要的,并且要使用变量值更新视图,您将需要状态和重新渲染。

【讨论】:

    【解决方案3】:

    更新状态会使组件重新渲染,但局部值不会。

    在您的情况下,您在组件中呈现了该值。 这意味着,当值更改时,组件应该重新渲染以显示更新后的值。

    所以使用useState会比正常的本地值更好。

    function Foo() {
        let a = 0;
        a = 1; // there will be no re-render.
        return <div>{a}</div>;
    }
    
    function Foo() {
        const [a, setA] = useState(0);
        if (a != 1) setA(1); // re-render required
        return <div>{a}</div>;
    }
    

    【讨论】:

      【解决方案4】:
      function Foo() {
          const [a, setA] = useState(0);
          if (a != 1) setA(1); // to avoid infinite-loop
          return <div>{a}</div>;
      }
      

      等价于

      class Foo extends React.Component {
          constructor(props) {
              super(props);
              this.state = {
                  a: 0
              };
          }
          // ...
      }
      

      useState 返回的是两件事:

      1. 新的状态变量
      2. 该变量的设置器

      如果您调用setA(1),您将调用this.setState({ a: 1 }) 并触发重新渲染。

      【讨论】:

        【解决方案5】:

        局部变量将在每次渲染时重置,而状态将更新:

        function App() {
          let a = 0; // reset to 0 on render/re-render
          const [b, setB] = useState(0);
        
          return (
            <div className="App">
              <div>
                {a}
                <button onClick={() => a++}>local variable a++</button>
              </div>
              <div>
                {b}
                <button onClick={() => setB(prevB => prevB + 1)}>
                  state variable b++
                </button>
              </div>
            </div>
          );
        }
        

        【讨论】:

        • Local variables will get reset every render upon mutation whereas state will update。功能组件是正确的。类组件呢?
        • @NguyễnVănPhong 如果您指的是类属性,不,它们存在于组件生命周期之外。如果您指的是在 render 生命周期方法中声明的任何变量(例如),这些变量将在每次渲染时重新声明,就像在功能组件中一样。
        • 这是有道理的。 +1
        猜你喜欢
        • 1970-01-01
        • 2019-12-11
        • 1970-01-01
        • 2020-10-11
        • 2020-03-21
        • 2021-11-11
        • 2019-06-06
        • 1970-01-01
        • 2020-06-21
        相关资源
        最近更新 更多