React Hooks-幕后发生了什么?

时间:2018-12-11 18:05:01

标签: javascript reactjs react-hooks

我一直在尝试React Hooks,它们确实简化了诸如存储状态之类的事情。但是,他们似乎通过魔术来做很多事情,我找不到关于它们实际工作方式的好文章。

看似神奇的第一件事是,每次调用setXXX方法时,调用useState()之类的函数如何导致功能组件的重新渲染?

当功能组件甚至没有能力在Mount / Unmount上运行代码时,诸如useEffect()之类的东西如何伪造componentDidMount?

useContext()如何真正获得对上下文的访问,甚至如何知道正在调用哪个组件?

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

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

数据,错误,加载和重试如何在组件更改时重新呈现?

抱歉,有很多问题,但是我想大多数问题可以归结为一个问题,即:

钩子后面的函数实际上如何访问正在调用它的功能/无状态组件,以便它可以记住重新渲染之间的内容并使用新数据启动重新渲染?

3 个答案:

答案 0 :(得分:7)

反应挂钩利用了组件的隐藏状态,它存储在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通过currentlyRenderedCompInstance访问当前呈现的组件实例令牌的方式,其他内置的钩子也可以执行此操作并维护该组件实例的状态。

答案 1 :(得分:3)

Dan Abramov在几天前创建了一篇博客文章,内容涉及以下内容:

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

第二部分专门介绍了有关useState之类的钩子的详细信息。

答案 2 :(得分:0)

我建议阅读https://eliav2.github.io/how-react-hooks-work/

它包含有关使用 React hook 时发生的事情的详细说明,并通过许多交互式示例进行演示。

注意 - 没有解释 React schduale 如何调用后期阶段,而是深入演示了 React 用于为后期阶段安排调用的规则是什么