资讯专栏INFORMATION COLUMN

理解 React Hooks 的 Capture Value 特性

curlyCheng / 2769人阅读

摘要:在读了一些文章后,大致是找到自己总是掉坑的原因了没理解中的特性。通过这个示例,相信会比较容易地理解特性,并如何使用来暂时绕过它。在知道并理解这个特性后,有助于进一步熟悉了的运行机制,减少掉坑的次数。

由于刚使用 React hooks 不久,对它的脾气还拿捏不准,掉了很多次“坑”;这里的 “坑” 的意思并不是说 React hooks 的设计有问题,而是我在使用的时候,因为还没有跟上它的理念导致的一些问题。

在读了一些文章后,大致是找到自己总是掉坑的原因了 —— 没理解 React Hooks 中的 Capture Value 特性。

本文就以简单的示例来解释这个特性所产生的现象,对理解 Capture Value 特性做一个补充。

参考文章

Using the Effect Hook : 官方的 useEffect 使用教程,用例详实 ,附 useEffect - API文档

精读《useEffect 完全指南》:如果你想用好 Function Component 或者 Hooks,这篇文章几乎是必读的,因为没有人能猜到什么是 Capture Value,然而不能理解这个概念,Function Component 也不能用的顺手。

精读《Function VS Class 组件》 :以后在 React 中经常使用 Class 的写法,在 React Hooks 需要转换成函数式编程风格,这篇文章对比了两种写法上的差异;(这两种写法没有好坏之分,性能差距也几乎可以忽略,而且 React 会长期支持这两种写法)

1、状态值为什么不是最新的?

官方相关 issue:Why am I seeing stale props or state inside my function?

“这个 effects 取的值怎么不是最新的?!”这个疑惑可以说是在使用 React Hooks 时经常遇到的疑问。

在下列代码中,当你点击按钮 3s 后,alert 显示的数值却是 3s 前的 count 变量 —— 即无法获取最新的值,获取的值是过去某个时刻的:

import React, { useState, useCallback } from "react";
 import ReactDOM from "react-dom";
 
 function Example() {
   const [count, setCount] = useState(0);
 
   const handleAlertClick = useCallback(()=>{
     setTimeout(() => {
       alert("You clicked on: " + count);
     }, 3000)
   }, [count]);
 
   return (
     

You clicked {count} times

); } const rootElement = document.getElementById("root"); ReactDOM.render(, rootElement);
示例代码:https://codesandbox.io/s/k5pm...

具体操作步骤

当我们先点击 显示 按钮,在 3s 后(模拟耗时任务)会出现弹层

在这 3s 期间快速点击 增加 count 按钮

3s 后看到的弹层计数仍旧为 0.

2、解释

这是官方特意设置的机制,官方原文是:This prevents bugs caused by the code assuming props and state don’t change;(强行翻译一下,大概意思是:防止因 React 认为 props 或者 state 没有变更而引起的 bug

为了理解官方这么设定的意图,将上面代码稍微修改一下:

去掉 显示 count 按钮

增加一个 减少 count 的按钮

使用 useEffect 代替 useCallback,让每次更改 count 都会弹窗

...
useEffect(()=>{
    setTimeout(() => {
      alert("count: " + count);
    }, 3000)
  }, [count]);

  return (
    

You clicked {count} times

); } ...

我们先点击一次 增加 count,然后再紧接着点击一次 减少 count

如果不是按照官方的机制设置,那么我们看到的两次弹层显示的 count 数值都是 0 —— 很明显这不是我们想要的

还好实际情况不是这样,会先显示 1,然后显示 0

总结起来,这个现象其实就是文章 精读《useEffect 完全指南》 所提及的 Capture Value 特性(可以自行前往原文了解更多细节)

3、扩展:如何获取即刻的 count 变量

回到原来的问题,倔强如我,我就是想要在 3s 后获取的是此时此刻的 count 变量,而不是我 3s 前点击时的 count,该怎么操作?

官方给出的解决方案是,每次改变 count 的时候,将其放在 ref 类型的变量里即可。

修改一下原来的代码:

  const countRef = useRef(null);
  const handleAlertClick = useCallback(
    () => {
      setTimeout(() => {
        alert("You clicked on: " + countRef.current);
      }, 3000);
    },
    [count]
  );

  return (
    

You clicked {count} times

);

更改过后的代码运行后,3s 后 alert 显示的 count 变量就是你页面上所见到的样子了:

ref 类型的变量通常是用来存储 DOM 元素引用,但在 react hooks 中,它可以存放任何可变数据,就好比类实例属性一样,具体参考 Is there something like instance variables?

这等操作,其实就是借助 ref 类型变量绕过 Capture Value 特性来达到目的。

4、总结

援引文章 精读《useEffect 完全指南》 中对 Capture Value 概念的解释:每次 Render 的内容都会形成一个快照并保留下来,因此当状态变更而 Rerender 时,就形成了 N 个 Render 状态,而每个 Render 状态都拥有自己固定不变的 Props 与 State

通过这个示例,相信会比较容易地理解 Capture Value 特性,并如何使用 ref 来暂时绕过它。在知道并理解这个特性后,有助于进一步熟悉了 React Hooks 的运行机制,减少掉坑的次数。

这里罗列几篇文章,方便自检是否掌握了这个概念:

通过 React Hooks 声明式地使用 setInterval:文章采用循序渐进的示例来解释问题。探索如何让 setIntervalHooks 和谐地玩耍,为什么是这种方式,以及这种方式给你带来了什么新能力。

How to get the previous props or state?: 如何获取变更前的 props 和 state ?官网提供的 useRef 来解决,也有人针对它进行了封装(How to compare oldValues and newValues on React Hooks useEffect?)

下面的是我的公众号二维码图片,欢迎关注。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/109215.html

相关文章

  • 精读《Function VS Class 组件》

    摘要:未来可能成为官方之一。讨论地址是精读组件如果你想参与讨论,请点击这里,每周都有新的主题,周末或周一发布。前端精读帮你筛选靠谱的内容。 1. 引言 为什么要了解 Function 写法的组件呢?因为它正在变得越来越重要。 那么 React 中 Function Component 与 Class Component 有何不同? how-are-function-components-di...

    FWHeart 评论0 收藏0
  • 十个案例学会 React Hooks

    摘要:在线传递给的是而不是,返回值即是想要透传的数据了。所以函数组件在每次渲染的时候如果有传递函数的话都会重渲染子组件。在学会使用React Hooks之前,可以先看一下相关原理学习React Hooks 前言 在 React 的世界中,有容器组件和 UI 组件之分,在 React Hooks 出现之前,UI 组件我们可以使用函数,无状态组件来展示 UI,而对于容器组件,函数组件就显得无能为力,我...

    williamwen1986 评论0 收藏0
  • 精读《Vue3.0 Function API》

    摘要:拿到的都是而不是原始值,且这个值会动态变化。精读对于的与,笔者做一些对比。因此采取了作为优化方案只有当第二个依赖参数变化时才返回新引用。不需要使用等进行性能优化,所有性能优化都是自动的。前端精读帮你筛选靠谱的内容。 1. 引言 Vue 3.0 的发布引起了轩然大波,让我们解读下它的 function api RFC 详细了解一下 Vue 团队是怎么想的吧! 首先官方回答了几个最受关注的...

    voyagelab 评论0 收藏0
  • 【译】函数组件和类组件有什么不同?

    摘要:但是,你可能已经注意到,当你试图通过指定依赖数组来优化时,可能会遇到带有过时闭包的错误。这是否意味着闭包是问题所在我不这么认为。到目前为止,我所看到的所有情况下,过时的闭包问题都是由于错误地假设函数不更改或总是相同而发生的。 原文链接:https://overreacted.io/how-ar... 在很长一段时间内,标准答案是class components提供更多的特性(像sta...

    gself 评论0 收藏0
  • React函数式组件说到Hooks

    摘要:难道还不允许设计得对新人更友好了我们先把做成就是找骂啊这怎么怪到我们头上了事实是,即使在内部,也显然不是所有程序员都熟悉函数式编程的概念。 1.前言介绍 历史React在2013年开源,在2015引入函数式组件,不过在日常开发中经常被忽略。ReactJS Core Team 确实大部分成员都曾在推特上公开夸赞过对函数式编程 与 ML 系语言(或其特性)的优点:Sebastian 日常提...

    lavor 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<