Preact如何获取当前正在渲染的函数组件实例
Preact获取当前激活函数组件实例的实现方案
Preact没有官方公开的、对标React __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner 或Svelte get_current_component() 的API,但存在生产环境完全可用的稳定实现方案,也是目前Preact生态内工具库通用的实现方式。
核心实现逻辑
Preact渲染函数组件、执行组件内hooks调用的整个同步周期内,会将当前正在渲染的组件实例暂存在内部作用域,你可以通过劫持Preact全局options上的生命周期钩子,在渲染流程中捕获当前组件实例,不需要依赖未导出的内部模块变量。
可直接使用的代码实现
import { options } from 'preact'; // 全局维护当前渲染栈顶的组件实例,兼容嵌套组件渲染场景 let currentActiveComponent = null; // 劫持组件开始渲染的钩子 const originalRenderHook = options.__r; options.__r = (vnode) => { if (originalRenderHook) originalRenderHook(vnode); // 仅拦截函数组件 if (typeof vnode.type === 'function') { const prevStackComponent = currentActiveComponent; currentActiveComponent = vnode._component; // 劫持渲染完成钩子,当前组件渲染结束后出栈 const originalDiffedHook = options.diffed; options.diffed = function restoreStack(vnode) { if (vnode._component === currentActiveComponent) { currentActiveComponent = prevStackComponent; options.diffed = originalDiffedHook; } if (originalDiffedHook) originalDiffedHook(vnode); }; } }; /** * 对标Svelte get_current_component()的工具方法 * 仅可在组件渲染阶段、hook同步执行阶段调用 */ export function getCurrentComponent() { if (!currentActiveComponent) { throw new Error('getCurrentComponent() can only be called during component render or hook execution'); } return currentActiveComponent; }
拿到组件实例后可访问的数据
拿到组件实例后,你可以直接读取所有需要的运行时数据:
- 组件当前props:直接访问实例的
props属性即可,是实时的最新值 - 组件hooks状态:所有hooks的状态、值存储在实例的
__hooks属性中:__hooks._list是按调用顺序排列的hook链表,每个hook节点的_value字段对应该hook保存的值,useState的状态、useRef的ref对象、useMemo/useCallback的缓存值都存在这里 - 副作用effects:
useEffect/useLayoutEffect注册的回调、依赖、清理函数存储在对应hook节点的_value字段,待执行的副作用队列存在__hooks._pendingEffects中 - 组件内部状态:函数组件无独立的this状态,所有状态均托管在hooks链表中;类组件的state存在实例的
state属性上
注意事项
- 该方案在Preact 10.x全版本的生产构建下稳定可用,
options、vnode的_component、组件实例的__hooks这些内部属性生产环境不会被压缩重命名,是Preact生态工具(如devtools、状态管理库)通用的依赖属性 - 不要在异步回调(如
setTimeout、Promise.then、事件回调)中调用getCurrentComponent(),异步逻辑执行时组件渲染流程已经结束,组件栈已经出栈,无法拿到正确的实例,行为和React、Svelte的同类API完全一致 - 不要尝试直接导入
preact/hooks内部的currentComponent变量,模块作用域隔离会导致你拿到的变量和Preact内部运行时使用的变量不是同一个引用,会出现取值错误 - Preact官方目前没有计划将该能力作为公开API暴露,因为属于运行时内部实现细节,但上述拦截方案经过生态多年验证,不会在小版本迭代中失效。
内容的提问来源于stack exchange,提问作者Aÿlo
相关产品推荐
相关产品推荐

