共计 956 个字符,预计需要花费 3 分钟才能阅读完成。
???? 前言
本文引申与 Dan Abramov 的博文, How Are Function Components Different from Classes?, 感兴趣的同学可以直接看原文。
本文在 Dan 的文章的基础,做了一些自己的思考。
???? 两个组件有何不同
当点击 button,延迟 3s 后,两个组件都会在控制台打印 props.user 属性。咋一看没啥区别,但是如果在延迟的 3s 的之间,我们修改了 props.user 属性。class 组件会打印最新的值,而 function 组件打印的还是 旧值。
Dan 给出了一个在线的 Demo
这是因为,在 React 中 props 是不可变的。但是 this 不是,this 是一直是可变。
???? 如何在 class 组件中,打印出旧值?
我们可以组件 render 时,利用 javascript 的闭包特性,捕获 props。我们知道,在 javascript 中函数执行完成后,函数内部创建的变量,会被 javascript 的垃圾回收机制所回收。
但是如果在回调函数中,我们依赖了这个变量,这个变量就不会被回收。我们在 render 函数执行的时候,创建了 props 常量。并在定时器的 callback 中引用了它。它在定时器的 callback 执行完成前,会一直存在在内存中。所以我们在执行 callback 时,打印的依然是 旧的值。
⚛️从源码的角度进行分析
限于本人能力有限,react 的源码对于我来说实战有些困难????。我们将从 preact 源码,一窥究竟。
在 preact 中,会将组件实例的 props 属性作为参数,传入组件的 render 函数中。
当实例的 props 属性发生修改时,class 组件直接使用 this(组件的实例),所以可以直接获取组件 最新 的 props。而在函数组件中,之前的 props 参数,已经因为 javascript 闭包的特性,保存在内存之中,无法从外部进行修改。所以在定时器执行 callback 时,打印的还是旧值。
如果你在理解上还有些困难,可以尝试理解,以下简化的代码。说明了,为什么函数组件会打印 旧值。
⚓️如何在 funtion 组件中,打印出新值?
我们可以尝试利用 useRef。当然这种使用useRef 的方式,不是普遍的
✍️参考
- How Are Function Components Different from Classes?
- preact