React Hooks - 使用 useState 与仅使用变量

Posted

技术标签:

【中文标题】React Hooks - 使用 useState 与仅使用变量【英文标题】:React Hooks - using useState vs just variables 【发布时间】: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; 初始化它,你会得到同样的结果。 【参考方案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 返回的是两件事:

    新的状态变量 该变量的设置器

如果您调用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

以上是关于React Hooks - 使用 useState 与仅使用变量的主要内容,如果未能解决你的问题,请参考以下文章

React hooks的useState原理

React Hooks --- useState 和 useEffect

React Hooks:使用useState更新状态不会立即更新状态[重复]

使用 useState 和 useContext React Hooks 持久化 localStorage

极简hooks实现,与react的思路一样的useState

带有回调的 React Hooks useState [重复]