概述
useImperativeHandle用子组件安全地向父组件提供访问方法或者变量的句柄。通常和React.forwardRef配合使用。
源码分析
useImperactiveHandle同其他hooks 一样,在挂载和更新阶段是对应不同的方法,分别为:mountImperativeHandle和updateImperativeHandle
源码解读
mountImperativeHandle方法
js
function mountImperativeHandle(ref, create, deps) {
const effectDeps =
deps !== null && deps !== undefined ? deps.concat([ref]) : null;
let fiberFlags = UpdateEffect | Layout;
mountEffectImpl(
fiberFlags,
HookLayout,
imperativeHandleEffect.bind(null, create, ref),
effectDeps,
);
}
updateImperativeHandle方法
js
function updateImperativeHandle(ref, create, deps) {
const effectDeps =
deps !== null && deps !== undefined ? deps.concat([ref]) : null;
updateEffectImpl(
UpdateEffect,
HookLayout,
imperativeHandleEffect.bind(null, create, ref),
effectDeps,
);
}
可以明显看出,上面两个方法和effect的挂载更新几乎如出一辙,都是调用mountEffectImpl或updateEffectImpl进行处理,而且useImperativeHandle和useLayoutEffect使用的tag标记是一样的,因为useImperativeHandle的本质给ref参数赋值,而useLayoutEffect这个hook是在DOM挂载后、DOM绘制前调用,tag一致可以保证useImperativeHandle的调用时机也是这个时机。
另一方面,useRef这个hook也可以用于绑定DOM,这也遵守了相同规则。
和useLayoutEffect不同的是,useImperativeHandle会自动的将ref也作为依赖的一部分,并且通过bind方法对create回调方法进行了封装。当依赖发生变化时,便会调用imperativeHandleEffect方法,在其内对ref进行赋值。
其源码如下:
imperativeHandleEffect方法
js
function imperativeHandleEffect(create, ref) {
// 判断ref是否是函数
if (typeof ref === 'function') {
// 若ref是函数
const refCallback = ref;
// 先执行create方法
const inst = create();
// 然后将create方法的返回值作为ref的参数,执行ref函数
const refCleanup = refCallback(inst);// 拿到ref函数的返回值
// 返回一个函数,作为useImperative的清理函数
return () => {
// 判断,若ref的返回值是一个函数
if (typeof refCleanup === 'function') {
// 则在useImperativeHandle调用destroy时,执行对ref的清理
refCleanup();
} else {
// 否则再次调用ref函数,传值为null
refCallback(null);
}
};
} else if (ref !== null && ref !== undefined) {
// 若ref是一个对象,则其必然是一个{current:any}的对象,否则React会报错
const refObject = ref;
// 执行create方法,并将其返回值赋值给re.current
const inst = create();
refObject.current = inst;
// 清理函数就是将ref,current置为null
return () => {
refObject.current = null;
};
}
}
总结
useImperativeHandle的设计沿用了useLayoutEffect,其主要作用就是搭配React.forwardRef向父组件注入调用子组件的方法或数据。