React Hooks - 引擎盖下发生了什么?

React Hooks - What's happening under the hood?

我一直在试用 React Hooks,它们似乎确实简化了存储状态之类的事情。然而,它们似乎可以通过魔法做很多事情,我找不到一篇关于它们实际工作原理的好文章。

第一件似乎很神奇的事情是,每次调用 setXXX 方法时调用像 useState() 这样的函数会导致重新呈现功能组件 returns?

当功能组件甚至没有能力在 Mount/Unmount 上 运行 编码时,像 useEffect() 这样的东西如何伪造一个 componentDidMount?

useContext() 如何实际访问上下文以及它如何知道哪个组件正在调用它?

这甚至还没有开始涵盖所有已经出现的第 3 方挂钩,例如 useDataLoader,它允许您使用以下...

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

当数据、错误、加载和重试发生变化时如何重新渲染您的组件?

抱歉,问题很多,但我想大部分问题都可以归结为一个问题,即:

钩子背后的函数如何实际访问调用它的 functional/stateless 组件,以便它可以记住重新渲染之间的事情并使用新的重新渲染数据?

React hook利用了组件的隐藏状态,它存储在一个fiber中,一个fiber是一个对应组件实例的实体(广义上,因为功能组件不创建实例作为 class 个组件)。

是 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 如何通过 currentlyRenderedCompInstance 访问当前呈现的组件实例令牌类似,其他内置挂钩也可以执行此操作并维护此组件实例的状态。

Dan Abramov 在几天前创建了一个博客 post,其中介绍了以下内容:

https://overreacted.io/how-does-setstate-know-what-to-do/

后半部分专门介绍了有关 useState 等钩子的详细信息。

对于那些有兴趣深入了解一些实施细节的人,我在这里有一个相关的答案:

我会推荐阅读 https://eliav2.github.io/how-react-hooks-work/

它包括有关使用 React Hooks 时发生的事情的详细解释,并通过许多交互式示例进行演示。

注意 - 本文并未以技术术语解释 React 如何安排后续阶段的调用,而是演示了 React 用于安排后续阶段调用的规则。

Eliav Louski 给出的 URL in another answer 是迄今为止我遇到的最好的 React 解释。这个页面应该取代 React 的官方教程,因为它删除了 hooks 和 friends 的所有魔法。