React Hooks - 发生了什么?

82

我一直在尝试使用React Hooks,它们似乎确实简化了像存储状态这样的事情。然而,它们似乎通过魔法完成了很多事情,我找不到关于它们如何工作的好文章。

第一件看起来像魔法的事情是,调用像useState()这样的函数会在每次调用它返回的setXXX方法时重新渲染您的函数组件吗?

像useEffect()这样的东西如何模拟componentDidMount,当函数式组件甚至没有能力在挂载/卸载时运行代码?

useContext()如何实际获取访问上下文的权限,甚至如何知道哪个组件在调用它?

这甚至还没有涉及所有已经出现的第三方钩子,比如useDataLoader,它允许您使用以下内容...

const { data, error, loading, retry } = useDataLoader(getData, id)

当数据、错误、加载和重试状态发生变化时,它们如何重新渲染组件?

非常抱歉,问题比较多,但我认为它们大部分可以归纳为一个问题,即:

钩子函数背后的函数实际上是如何获得调用它的函数/无状态组件的访问权限,以便在重新渲染时记住状态并使用新数据进行重新渲染?

4个回答

72

React Hook利用组件的隐藏状态,它存储在fiber内部,Fiber是对组件实例的对应实体(在更广义上,因为函数组件不像类组件一样创建实例)。

是React渲染器给了Hook访问相应上下文、状态等的权限,并且顺带调用了组件函数。所以可以将组件实例与在组件函数内部调用的Hook函数相关联。

以下代码片段解释了其工作原理:

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通过currentlyRenderedCompInstance访问当前呈现的组件实例标记,其他内置的hooks也可以这样做,并为该组件实例维护状态。


10
很棒的回答,Estus,谢谢。可惜我的问题被“搁置”了,我认为它可能会对很多人有很大帮助。不幸的是,这就是如今的 Stack Overflow。 - jonhobbs
1
不用谢。这不是什么大问题,只要答案对您有帮助就好了。这个问题仍然可以被其他用户访问。可能随着时间的推移会重新打开。 - Estus Flask
1
人性得到恢复 - Konrad
所以这个 'fiber' 对象是组件的真实实例。在背后,它是一种类组件,其中 This 是不可访问的,而你只能编写 render 方法。看起来相当受限。我总是将东西附加到 This 对象上,比如控制其他东西的大型对象,或者预先计算或缓存的东西,我以后想要使用。 - OsamaBinLogin

15

3
我建议阅读 https://eliav2.github.io/how-react-hooks-work/,它详细解释了在使用React Hooks时发生的事情,并用许多交互式示例进行演示。
请注意 - 该文章没有用技术术语解释React如何安排后续阶段的调用,而是演示了React用于安排后续阶段调用的规则。

0

Eliav Louski提供的另一个答案中的URL是我目前为止遇到的最好的React解释。这个页面应该取代React官方教程,因为它消除了所有钩子和相关内容的魔法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接