【问题标题】:How does React links dependencies in `useEffect` hook to state?React 如何将 `useEffect` 挂钩中的依赖项链接到状态?
【发布时间】:2020-06-18 10:13:57
【问题描述】:

我认为 React 的“useState”钩子是如何工作的非常好。 State - 是映射到某个组件的值列表,还有 useState 调用的索引,它是请求状态值索引。当 React 渲染器遇到组件时,它会将其写入到 useState 可以访问的外部引用中,因此它通过 useState 调用索引从“当前”组件的状态列表中返回状态值。 但我不知道,React 如何识别“useEffect”中的依赖关系并将其链接到实际状态,这显然是数字和字符串等普通值。这是怎么做到的?

import React from 'react'

function Component() {
  const [plainString, setPlainString] = React.useState('Hello')
  const [anotherPlainString, setAnotherPlainString] = React.useState('Good bye')

  // update `plainString` after mount
  React.useEffect(() => {
    setPlainString('Updated Hello')
  }, [])

  // callback get triggered after `plainString` update!
  // but how it links dependency to state if its just 'Hello' string?
  React.useEffect(
    () => {
      console.log(plainString) // "Updated Hello"
    },
    [plainString]
  )

  return <h1>plainString</h1>
}

【问题讨论】:

  • 提示:状态变量没有链接到组件(本身) - 钩子是。这就是为什么钩子必须始终以相同的顺序调用并且不能有条件地调用(并且不能有条件依赖)
  • @Adam 好的。但是在实施中,我建议钩子也不能重新排序。实际上,它的工作原理是一样的,我已经测试过了。
  • 我的意思是说一旦安装给定组件的钩子就不能改变了。

标签: javascript reactjs


【解决方案1】:

这就是 React 维护钩子映射的方式。这只是为了给出一个钩子实现的想法。

const MyReact = (function() {
  let hooks = [],
    currentHook = 0 // array of hooks, and an iterator!
  return {
    render(Component) {
      const Comp = Component() // run effects
      Comp.render()
      currentHook = 0 // reset for next render
      return Comp
    },
    useEffect(callback, depArray) {
      const hasNoDeps = !depArray
      const deps = hooks[currentHook] // type: array | undefined
      const hasChangedDeps = deps ? !depArray.every((el, i) => el === deps[i]) : true
      if (hasNoDeps || hasChangedDeps) {
        callback()
        hooks[currentHook] = depArray
      }
      currentHook++ // done with this hook
    },
    useState(initialValue) {
      hooks[currentHook] = hooks[currentHook] || initialValue // type: any
      const setStateHookIndex = currentHook // for setState's closure!
      const setState = newState => (hooks[setStateHookIndex] = newState)
      return [hooks[currentHook++], setState]
    }
  }
})()

您可以在此处阅读有关 hooks 在 React 中如何工作的更多信息。

【讨论】:

    【解决方案2】:

    只是依赖数组中的值是否改变,它们甚至不必是有状态的。

    useEffect(() => {
    
    }, dependencyArray) // React loops over these values to check for changes
    

    你可以很容易地用随机数测试这个

    dependencyArray = [Math.random(), Math.random(), Math.random()]
    

    这很可能会在重新渲染时创建一个具有不同值的数组。

    如果第一次得到[0.1, 0.2, 0.3],下一次得到[0.1, 0.2, 0]会再次触发效果,因为数组中的值不一样。

    【讨论】:

    • 只是添加一点点细节——react 将钩子链接到组件(通过纤维魔法),所以它知道上次运行效果函数时这些依赖项的值,它有它们存储在内存中。它知道现在的值是什么(因为你已经提供了它们!)。所以这是一个简单的循环,并检查它们是否与上次调用该函数时相同。如果是,则不要调用该函数,如果否,则调用它(记忆)。这是所有goodness
    • 我明白了,效果回调在进一步的渲染中保持不变,它只是检查它之前收到的列表中的值和新的值。太简单!感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 2019-09-23
    • 2019-05-07
    • 1970-01-01
    • 2021-02-11
    • 2021-03-03
    • 2020-01-16
    相关资源
    最近更新 更多