You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Does useEffect run after every render? Yes! By default, it runs both after the first render and after every update. (We will later talk about how to customize this.) Instead of thinking in terms of “mounting” and “updating”, you might find it easier to think that effects happen “after render”. React guarantees the DOM has been updated by the time it runs the effects.
useEffect 在每次 DOM 更新之后执行,准确的说,在上述例子中是 autoCount 在每次 DOM 更新后执行。而我们的第2个参数 [] 是执行条件,这样会导致只有第1次真的执行了 autoCount ,后面每次DOM更新都不会再执行。
我们的函数 APP 的执行过程是这样的:
执行 App 函数
a. 获取 count 最新的值
b. autoCount 函数进入 effects 队列
c. 返回VDOM
复现问题
从一个最简单的demo开始,计算按钮的点击次数:
这样肯定是没有问题的,点击按钮可以正常计数。如果这个时候我们将需求改一下,每秒钟要自动计数一次,那么代码就变成这样了:
这段看似正常的代码其实执行之后会发现有问题,自动计数只会统计到1,不会继续增加了。那么原因是什么呢? 是因为
autoUpdate
只执行了一次,这个函数中使用的count
是第一次执行的时候App
闭包里面的值,也就是 0 ,所以每一次执行都会是0+1=1
,结果永远是1。有些小伙伴这里可能不明白了,
update
函数不也是闭包里面吗,为啥里面取到的count
就能更新呢? 要回答这个问题就要理解 useEffect 的执行机制useEffect执行过程
不需要去看 useEffect 的源码,只需要根据官网的描述我们就可以理解其执行逻辑:
useEffect
在每次 DOM 更新之后执行,准确的说,在上述例子中是autoCount
在每次 DOM 更新后执行。而我们的第2个参数 [] 是执行条件,这样会导致只有第1次真的执行了autoCount
,后面每次DOM更新都不会再执行。我们的函数 APP 的执行过程是这样的:
App
函数a. 获取
count
最新的值b.
autoCount
函数进入effects
队列c. 返回VDOM
effects
中取出autoCount
函数,根据条件决定是否执行用一张图来表示1次
render
的过程如下:由于每一次
App
函数执行,都会读取新的count
并创建新的autoCount
,所以在新创建的autoCount
函数内部读取的count
值是最新的。然而我们定时更新不是定时执行最新的autoCount
,而是在第1次的count
内部不停执行repeat
函数,因此读取的count
值就永远是 1 。而
update
函数执行没问题的原因是,每次更新都执行了update
,所以总能取到最新的值。理解的关键是要跳出class组件的思维。 在传统的class写法中,是同一个方法多次执行,每次执行后的结果不同是因为
this
上的数据不同,比如render
方法。而在函数式组件中,组件内部声明的方法,如上例中update
,autoCount
等方法,每次执行App的时候都会声明一个新的,使用后就丢弃了。解决方法
那么如果确实要做定时更新逻辑呢? 如何解决? 只要能读取最新的 count 值就可以,不要用闭包内的变量,而是直接用 setState 的回调函数语法获取最新值就可以了。
The text was updated successfully, but these errors were encountered: