React Forget 的局限

我曾经谈到我认为signalsWeb框架的未来。自那以后,我很高兴地欢迎Angular加入了Signals俱乐部。

令我惊讶的是,安德鲁·克拉克(Andrew Clark)在一条推文中写道,他认为React ForgetSignals是一个更好的方法。

React优化编译器,又名React Forget

React Forget是一个实验性项目,旨在通过自动生成等效的useMemouseCallback调用来改善React应用程序的渲染性能,以最小化重新渲染的成本,同时保留React的编程模型。

Memoizationsignals

对于大多数情况来说,signals不需要记忆。 React Forget自动在所有地方插入记忆,所以我可以理解为什么有人会认为 Memoizationsignals是相同的。

让我向你展示 Memoization方法失败而signals卓越的地方。

示例

让我们构建一个经典的单页应用程序,包含一个购买按钮和一个购物车。选择此示例是因为它展示了一个现实世界的场景,其中状态、变化和渲染被分离到不同的组件中:

  • 声明状态的地方(购物车内容)
  • 变异状态的地方(购买按钮)
  • 渲染状态的地方(购物车UI)
    使用Memoization和prop drilling的React
    要理解的关键是,我们需要将状态(以及setter)传递到需要它的组件中。

在我们的例子中,这是ShoppingCartBuyButton组件。这意味着我们必须通过许多层组件进行prop drilling才能到达那里(上下文是另一种方法,但结果相同)。

现在让我们看看当我们尝试改变购物车时会发生什么:

  • BuyButton有一个setCart setter,它使用购物车的新状态调用。
  • 调用setCart会使App组件失效。
  • React从App组件开始重新渲染。通常情况下,这会导致大多数子组件重新渲染,但让我们假设React Forget已经将Memoization最大化。在这种情况下,React仍然需要渲染AppShoppingCart之间的所有组件。在我们的简单情况中,只有HeaderUser,但在真实的应用程序中会有更多。

即使React Forget编译器Memoization了一切,它仍然无法避免的事实是,当状态发生变化时,它必须从状态存储的地方通过prop drilling一直传递到需要的地方。

重新渲染仅用于prop drilling的中间组件是一种浪费。

signals

现在让我们看看signals。数据流图与以前完全相同,只是现在我们不是传递状态,而是通过许多层组件传递信号到ShoppingCartBuyButton

现在让我们看看当我们尝试改变购物车时会发生什么。

  • BuyButton有一个setCart信号,它使用购物车的新状态调用。
  • 信号通知ShoppingCart更新购物车的状态。
    就是这样。

请注意,即使状态是在App组件中声明的,但App并不是重新渲染过程的一部分,而且所有通过prop drilling将其传递给ShoppingCart的组件也都不是。

这就是signals的强大之处所在。

signals > useMemo()

这就是我们说,通常情况下,signals不需要useMemo()的原因。signals使您能够仅对需要更新的UI执行精细的更新,从而跳过所有中间部分。

useMemo()无法跳过组件层次。在最好的情况下,useMemo()可以修剪组件树,使得需要访问的分支更少,但更新仍然需要我们通过这些分支进行。

结论

signalsMemoization可能是等效的,但实际上,signals要更高效得多,因为它们不受组件渲染树的限制。

它们存在于与组件树独立的平面上。

事实上,signals不需要Memoization,但在 React中的Memoization无法与signals的精确性相匹配。