【问题标题】:What's the idea behind useState functionality in ReactJS?ReactJS 中的 useState 功能背后的想法是什么?
【发布时间】:2020-09-02 15:23:54
【问题描述】:

我正在学习 ReactJS,我了解函数式编程的好处。但是,我有点担心实际的 useState 方法。如果我们假设一个变量会被改变,那么为什么首先声明它为 const 呢?

我发现我可以简单地使用let number = 4;,然后像这样<p>{number}</p> 渲染它。但是,我不能做的是仅通过更改它来自动重新渲染它,例如使用像 <p onClick={() => ++number }></p> 这样的 onClick 事件。为什么会这样?是否有我遗漏的特定原因为什么它是按原样实施的?我的意思是为什么开发人员决定如果值需要在更改时重新渲染,那么它必须是在 useState 功能的帮助下声明的 const 值?

我问这个是因为我怀疑我错过了这背后的一些好处,我想了解它们。

【问题讨论】:

  • 因为如果你只是增加一个局部变量,React 怎么知道应该更新虚拟 DOM,然后将更改应用到真实页面?我建议观看例如youtube.com/watch?v=AdNJ3fydeao 更好地了解正在发生的事情。
  • 但是我不能做的是通过更改它来自动重新渲染它因为单独的重新分配在 JS 中不会产生副作用(几乎在所有情况下)。如果在 JS 中无法实现特定功能,那么在 React/JSX 中也不可能,没有新的运算符/语法。
  • OP,你写的是类组件还是函数组件?如果没有useState,必须具有 flat out 状态的功能组件将无法工作,因为该组件每次重新渲染时都会重新生成其状态。函数组件中的useState 不会创建内部状态,而是对外部状态的内部引用。这就像其他函数式语言中的IORef。 IIRC 它启用了“全局”状态,同时还确保了原子性。这有点像使用redux而不使用redux。

标签: reactjs functional-programming


【解决方案1】:

该变量被声明为 const,因为您不能直接设置它。在 React 中,状态本身是不可变的。如果您使用 redux,您只能通过 setState(或您的情况下为 setNumber)或操作更改它。

但这是为什么呢?一开始可能看起来不必要的麻烦

首先,如果你的变量号发生变化,react 必须触发重新渲染。 如果状态是可变的,则需要数据绑定,因为如果设置了数字,则必须更新视图。

在 javascript 中,数据绑定适用于简单对象,但不适用于数组。例如,Vue.js 作为使用双向数据绑定的替代方案,在其早期版本中处理数组时遇到了很多麻烦。这就是为什么现在只有七种预定义的方法可以与数组交互(他们后来添加了这些方法来解决这个问题)。 Vue Js Array Methods

因此,将状态声明为 const 的一个简单原因是它更适用于数组。如果你看看你给出的例子,setNumber(number + 1) 并不比number++ 要多写。但是setState(newArray) 有效,newArray[i] = newElement 无效,因为由于 javascript 限制,这无法触发重新渲染。

其次,它是一个更好的设计理念。将您的组件视为一个函数,它将视图返回到状态。如果状态发生变化,您将获得新的视图。它简化了组件中属性之间的关系。如果允许您在渲染组件时更改状态,则会造成混乱。

【讨论】:

  • 感谢您的回答。正如我正确理解的那样,这背后的想法(至少一个(如果有多个))是封装重新渲染技术。在 C# 中,当类字段发生更改时,我曾经实现一个名为 INotifyPropertyChanged 的​​接口。订阅该事件将允许重绘视图。然而,在 WPF 中,这也是通过数据绑定自动完成的。所以在 ReactJS 中,如果我理解正确的话,状态事物是数据绑定的替代方案
【解决方案2】:

问题在于您将功能组件视为有状态的。但事实并非如此。它是一个函数,一旦你运行它,就是这样。

举个例子:

function useState() {
  let value = 1

  function setValue(v) {
    value = v
  }

  return [value, setValue]
}

function myFunction () {
  const [value, setValue] = useState();  // <----- we use const here

  return null
}

即使我们使用 const,value 变量也只存在于函数中,一旦函数返回就可以了。组件也是如此。

value 的实际值存储在一个完全不同的范围内,useEffect 可以访问。

如果您有兴趣,这里有一个 deep dive,关于 react 如何在内部工作

【讨论】:

  • 那么当其中的某些值发生变化时,整个组件是否会重新渲染?我是这么理解的。只是要求仔细检查。
【解决方案3】:

React 在渲染周期中工作,即声明某些状态,在“渲染阶段”计算 DOM(UI),然后在“提交阶段”刷新到实际的 DOM。

在每个循环中,状态都被认为是恒定的(JS 中的const 仅表示不能为变量分配新值,您可以使用letvar 轻松声明它,然后 react 就可以了相同)但为了反应的目的,状态是恒定的渲染周期。当通过其中一种状态更新方法进行更新时,react 会启动另一个渲染周期(更新状态、计算差异、提交到 DOM)并在必要时重新渲染。

这个过程很重要,也是外部状态突变被认为是反模式的原因,它违背了反应工作流程并导致错误代码或更糟的是,UI 没有按预期更新。

反应component lifecycle

但是,我不能做的是仅通过更改来自动重新渲染它 例如,使用像 &lt;p onClick={() =&gt; ++number }&gt;&lt;/p&gt; 这样的 onClick 事件。为什么会这样?

React 状态更新使用一个名为 reconciliation 的过程来确定发生了什么变化以及要重新渲染什么。用非常简单的术语来说,当 react 状态更新时,它会使用新的对象引用进行更新,因此浅层对象比较可以更快地检测到组件状态是否已更新。

声明状态并执行++number 只会更改值而不是引用,并且会被视为状态突变,反应中的反模式。

【讨论】:

    猜你喜欢
    • 2019-10-11
    • 2018-12-24
    • 2014-06-09
    • 1970-01-01
    • 2021-12-22
    • 2015-01-22
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    相关资源
    最近更新 更多