对React Hooks的Capture value特性的理解
source link: https://www.daozhao.com/10075.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
对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'))
当我们点击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
也有依赖,它也有类似的问题,有时间改造下这个例子再看一下。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK