React Hooks - 引擎盖下发生了啥?

Posted

技术标签:

【中文标题】React Hooks - 引擎盖下发生了啥?【英文标题】:React Hooks - What's happening under the hood?React Hooks - 引擎盖下发生了什么? 【发布时间】:2019-05-12 18:49:45 【问题描述】:

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

似乎很神奇的第一件事是,每次调用它返回的 setXXX 方法时,调用 useState() 之类的函数如何导致函数组件重新呈现?

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

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

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

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

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

对不起,很多问题,但我想大部分都可以总结为一个问题,即:

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

【问题讨论】:

【参考方案1】:

React hook 利用了组件的隐藏状态,它存储在 fiber 中,纤程是对应于组件实例的实体(从更广泛的意义上说,因为函数式组件不会将实例创建为类组件) .

它是 React 渲染器,它为钩子提供了对相应上下文、状态等的访问权限,顺便说一下,它是调用组件函数的 React 渲染器。因此它可以将组件实例与在组件函数内部调用的钩子函数相关联。

这个 sn-p 解释了它是如何工作的:

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 访问当前呈现的组件实例令牌,其他内置挂钩也可以做到这一点并维护此组件实例的状态。

【讨论】:

很好的回答埃斯图斯,谢谢。很遗憾我的问题被“搁置”了,因为我认为这可能对很多人有很大帮助。不幸的是,这些天这就是 Stack Overflow。 不客气。这不是什么大问题,只要答案适合你。其他用户仍然可以访问该问题。可能会随着时间的推移而关闭。【参考方案2】:

Dan Abramov 就在几天前创建了一篇博文,涵盖了这一点:

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

后半部分特别详细介绍了 useState 等钩子。

对于那些有兴趣深入了解一些实现细节的人,我在这里有一个相关的答案:How do react hooks determine the component that they are for?

【讨论】:

【参考方案3】:

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

它详细解释了使用 react hooks 时发生的事情,并通过许多交互式示例进行演示。

注意 - 这篇文章没有用技术术语解释 React 调度如何调用后期阶段,而是演示了 react 使用什么规则来调度后期阶段的调用。

【讨论】:

以上是关于React Hooks - 引擎盖下发生了啥?的主要内容,如果未能解决你的问题,请参考以下文章

Nuxt apollo 智能查询被调用了两次。引擎盖下会发生啥?

当我们声明静态变量时,编译器实际上做了啥?

如果找不到匹配项,replace 会做啥? (引擎盖下)

Python 是不是优化了引擎盖下的字典查找?

pydub append - 引擎盖下行为的澄清

Visual Studio - 引擎盖下(NPM/Typescript)