道招

对React Hooks的Capture value特性的理解

如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

对React Hooks的Capture value特性的理解

之前我的项目里面很多功能都是用的事件驱动,所以下面的实例也会更多地使用监听事件的回调函数。

我们先看下测试代码

const {useEffect ,useState, useRef, useMemo} = React;
const {render} = ReactDOM;
const eventBus = new EventEmitter();

function ListenButton() {
  const [started, setStarted] = useState(false);
  const [score, setScore] = useState(0);

  function onStartedClick() {
    setStarted(!started);
  }

  function onClick() {
    setScore(score + 1);
  }

  function onBouns() {
    setScore(score + 2);
  }

  const isWin = useMemo(() => {
    return started && score > 4
  }, [started, score])

  useEffect(() => {
    eventBus.on('bonus', onBouns);
  }, [])

  return (
    <div>
      <div>
        <p>started: { started ? 'Yes' : 'No'}</p>
        <p>score: { score }</p>
        <p>WIN: { isWin ? 'Yes' : 'No' }</p>
      </div>
      <button onClick={onStartedClick}>{started ? 'STOP' : 'START'}</button>
      <button onClick={onClick}>AddScore</button>
   </div>
  )
}

function EmitButton() {
  function emit() {
    eventBus.emit('bonus');
  }

  return (
    <button onClick={emit}>bonus</button>
  )
}

function App () {
  return (
    <div>
      <EmitButton />
      <ListenButton />
    </div>
  )
}
render( <App />, document.querySelector('#app'))

file

现状

当我们点击bonus按钮时直接在当前score的基础上加2分,首次点击时score从0变成2,再次点击呢? 还是2,因为在当时监听bonus事件时score的值为初始值0,而不是我们期望的最新值2

原因

这也就是我们常说的Capture Value特性,也有叫闭包陷阱的说法。

这是官方特意设置的机制,官方原文是:

This prevents bugs caused by the code assuming props and state don’t change;

(我们可以这么理解:防止因 React 认为 props 或者 state 没有变更而引起的 bug)

解决方案

怎样才能获得最新的score的值呢??? 方案一 加入依赖

  useEffect(() => {
    eventBus.on('bonus', onBouns);
  }, [score])

加入依赖性score,那样我们的onBouns方法就每次score变更时更新onBouns了。

方案二 用useRef

const scoreRef = useRef();
scoreRef.current = score;

function onBouns() {
  setScore(scoreRef.current + 2);
}

useRef可以用来存储任何可变数据,我们可以在每次score变更的同时重新赋值scoreRef.current,这样我们就借用useRef绕过了Capture Value特性。

总结

我们可以这样理解: 每次 Render 的内容都会形成一个快照并保留下来,因此当状态变更而 Rerender 时,就形成了 N 个 Render 状态,而每个 Render 状态都拥有自己固定不变的 Props 与 State。

有些时候(像上面的onBonus)可以比较简单在useEffect里面加入依赖,有的时候就比较麻烦了,我们只能依赖useRef暂时绕过这个问题了。

PS: useMemo也有依赖,它也有类似的问题,有时间改造下这个例子再看一下。

更新时间:
上一篇:WordPress上传图片出现“图像后期处理失败,请将其缩小到2500像素并重新上传”下一篇:浏览器滚动条hover时变粗、改变颜色

相关文章

Vue和React hooks实现Select批量选择、选中条数、全选、反选实现对比

批量选择、全选、反选这些功能使用频率还是很高的,下面直接看看Vue和React分别怎么实现吧。 Vue 在使用Vue的时候是很容易实现的,我们以下列数据格式为例: const data 阅读更多…

vue迁移react使用useReducer hooks还想支持回调?

鉴于目前有个任务是把手上的vue项目迁移到react,为了尽可能的降低期间造成的功能缺陷,很自然的就会想到使用一个方法一个方法的迁移,有的场景在vue中很自然,在react中,尤其是在使用react 阅读更多…

转译:使用react hooks优化回调函数在组件间的传递,useState,useReducer?

我们先看一下使用 useState hooks写的todoList组件,里面我们需要层层传递回调函数。 import React, { useState } from &quot;react& 阅读更多…

邮箱收件人组件成长历程(二)(React hooks升级版)

记得自己之前写过一篇 《邮箱收件人组件(vue版)成长历程(一)》 记得当时里面写到了自己使用的是可编辑div来进行输入的,同时提到 当时出于挑战自己和青铜的倔强,想试着换个方案,完全使用可编辑di 阅读更多…

react router页面跳转二次确认弹框及样式、业务逻辑自定义

我们在编辑页面时如果需要跳走通常会需要给用户提示,react router本身已经给了我们这样的功能,我们先看看怎么使用。 初见二次确认弹框 // App.jsx const App = 阅读更多…

改造富文本编辑器wangEditor成react组件

我们知道wangEditor常用的功能是editor实例的 txt.html() 和 txt.text() 方法,尤其是 txt.html() 方法,这是一个类似与jQuery常用的那种get和se 阅读更多…

关注道招网公众帐号
友情链接
消息推送
道招网关注互联网,分享IT资讯,前沿科技、编程技术,是否允许文章更新后推送通知消息。
允许
不用了