我一直在试用React Hooks,它们似乎简化了存储状态等操作。然而,他们似乎通过魔术做了很多事情,我找不到一篇关于他们实际工作方式的好文章。
看起来很神奇的第一件事就是每次调用它返回的setXXX方法时,调用像useState()这样的函数会导致重新渲染你的功能组件吗?
当功能组件甚至无法在Mount / Unmount上运行代码时,useEffect()之类的东西如何伪造componentDidMount?
useContext()实际上如何访问上下文,以及它如何知道哪个组件正在调用它?
而这甚至没有开始涵盖所有已经出现的第三方钩子,如useDataLoader,它允许您使用以下...
const { data, error, loading, retry } = useDataLoader(getData, id)
数据,错误,加载和重试如何在组件发生变化时重新渲染它们?
对不起,很多问题,但我想大多数问题可以归结为一个问题,即:
钩子后面的函数如何实际访问调用它的函数/无状态组件,以便它可以记住重新渲染之间的事情并启动使用新数据的重新渲染?
React hook利用组件的隐藏状态,它存储在fiber中,光纤是一个对应于组件实例的实体(在更广泛的意义上,因为功能组件不会将实例创建为类组件)。
它是React渲染器,它为钩子提供对相应上下文,状态等的访问。顺便说一下,它是调用组件函数的React渲染器。因此,它可以将组件实例与在组件函数内部调用的钩子函数相关联。
这段代码解释了它的工作原理:
let currentlyRenderedCompInstance;
const compStates = new Map(); // maps component instances to their states
const compInstances = new Map(); // maps component functions to instances
function useState(initialState) {
if (!compStates.has(currentlyRenderedCompInstance))
compStates.set(currentlyRenderedCompInstance, initialState);
return [
compStates.get(currentlyRenderedCompInstance) // state
val => compStates.set(currentlyRenderedCompInstance, val) // state setter
];
}
function render(comp, props) {
const compInstanceToken = Symbol('Renderer token for ' + comp.name);
if (!compInstances.has(comp))
compInstances.set(comp, new Set());
compInstances.get(comp).add(compInstanceToken);
currentlyRenderedCompInstance = compInstanceToken;
return {
instance: compInstanceToken,
children: comp(props)
};
}
与useState
如何通过qazxswpoi访问当前呈现的组件实例令牌类似,其他内置钩子也可以执行此操作并维护此组件实例的状态。
几天前Dan Abramov创建了一篇博文,内容涵盖:
currentlyRenderedCompInstance
下半部分详细介绍了像useState这样的钩子。