有条件地调用 React hook

She*_*aff 44 reactjs react-hooks

从react官方文档我们知道“React依赖于Hooks的调用顺序”。那么,如果我想有条件地调用它,那么为钩子“保留”一个位置有什么问题吗?

function Component({flag, depA, depB}) {

  if (flag) {
    // just "reserving a spot"
    useEffect(() => {}, [null, null])
  } else {
    useEffect(() => {
      // ... actual hook
    }, [depA, depB])
  }

  return <></>
}
Run Code Online (Sandbox Code Playgroud)

如果这有效,它也适用于吗useCallbackuseLayoutEffectuseMemouseImperativeHandle

我已经测试了所有这些,并且在更复杂的上下文中,即使 linter 抱怨,它似乎也能工作。我错过了什么吗?

PS:如果像这样看起来有点没用,那是因为最终目标是让钩子的主要部分延迟加载import(),在导入被触发和解决之前,只需为钩子保留位置即可。

Eve*_*ert 24

我今天刚好在想这个问题。我相信,虽然它“违反了规则”,但 React 无法区分两者之间的区别。

因此,虽然它违反了规则,但如果你有足够的理由,了解其中的风险,那么“规则”就只是教条。

React 通过计算调用次数基本上知道哪个 useEffect 钩子是哪个。有条件调用useEffect是不好的,特别是因为被调用的次数useEffect不能改变。

您的示例是有条件的,但 React 无法检测到它,因为在任何一种情况下您都调用它一次。

然而,你提到的例子似乎不需要这个。有充分的理由以“正常”方式做事,因为正如您从其他评论者那里看到的那样,这会导致混乱和惊喜,而我们不喜欢惊喜 =)

如果您延迟加载某些功能,只需让您的钩子在准备useEffect时调用该函数即可。


Ham*_*oja 20

我的解决方案是这样的,它适用于所有钩子,但是最好在必要时使用它,因为它可能会导致混乱和惊讶

const ConditionalEffect1 = () => {
  useEffect(() => {}, [])
  return null
}

const ConditionalEffect2 = ({depA, depB}) => {
  useEffect(() => {}, [depA, depB])
  return null
}

const Component = ({ flag, depA, depB }) => {
  return flag 
          ? <ConditionalEffect1 /> 
          : <ConditionalEffect2 depA={depA} depB={depB} />
}

Run Code Online (Sandbox Code Playgroud)


Rob*_*ell 12

您不能有条件地调用 useEffect,因为这违反了挂钩规则,您可以执行以下操作:

  useEffect(() => {
    if (flag) {
      console.log("do something");
    } else {
      console.log("do something else");
    }
  }, [depA, depB]);
Run Code Online (Sandbox Code Playgroud)