先要知道几点前提要点
- 在functional component中,每一次props的变化、执行setState操作都会导致组件方法重新执行。
- 基于1,组件方法执行后,所有的直接定义的const、let变量都会重新定义。
- 所以对于不需要变化的常量,一般用useRef封装起来。
常见的使用方法:
const a = useRef(initalValue);
在执行组件方法的时候,a不会被重新赋值。那么useRef在这里本质上干了什么呢?
useRef本质上是ReactCurrentDispatcher.current上的一个方法,这个方法接收一个初始值,返回一个对象,这个对象中只有一个current属性。
在执行组件方法的时候,这个current的值不会被重置,也就是说,每一次执行组件方法,用到的都是同一个值。
当然这里有一个问题,返回的这个对象为什么不会被重置?
应该是react用了一种时序的保存方法,在初始化时,将值记录在一个对象中;重复执行组件方法的时候,再从这个对象中取出来赋值到了a上。
下面看源码片段,这是初始化ref的源码:
useRef: function (initialValue) {
currentHookNameInDev = 'useRef';
mountHookTypesDev();
return mountRef(initialValue);
},
function mountRef(initialValue) {
var hook = mountWorkInProgressHook();
var ref = {
current: initialValue
};
{
Object.seal(ref);
}
hook.memoizedState = ref;
return ref;
}
附:Object.seal只是让ref里的key无法删除,value可以改变。
下面是更新ref(第二次以后执行组件方法)的代码片段:
useRef: function (initialValue) {
currentHookNameInDev = 'useRef';
updateHookTypesDev();
return updateRef(); // 可以注意到这里是update
},
这里mountHookTypesDev和updateHookTypesDev不重要。主要逻辑是mountRef和updateRef方法。
可以看到,updateRef其实就是返回了hook里记录的memoizedState
至于mountWorkInProgressHook和updateWorkInProgressHook,是两个比较复杂的方法。涉及到hook的本质,实际上useState也是用这个方式存储值的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。