“反应已检测到挂钩的顺序发生了变化”,但是似乎按顺序调用了挂钩

Isa*_*aac 10 javascript typescript reactjs

我正在尝试使用ContextReducers通过React的钩子,并且遇到钩子顺序不恒定的问题。我的理解是,只要顺序useHook(…)保持不变,就可以在任何类型的控制流中调用返回的状态/更新函数/缩减器。否则,我将在FunctionComponent的最开始调用钩子。

我是Days在循环生成吗?还是缺少其他东西?

Warning: React has detected a change in the order of Hooks
called by Container. This will lead to bugs and errors if not fixed. For
more information, read the Rules of Hooks:
https://reactjs.org/docs/hooks-rules.html

   Previous render            Next render
   ------------------------------------------------------
1. useContext                 useContext
2. undefined                  useRef
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

的完整版本Container如下。从摘录Day是下方,并且具有从一个裁判react-dnduseDrop

Warning: React has detected a change in the order of Hooks
called by Container. This will lead to bugs and errors if not fixed. For
more information, read the Rules of Hooks:
https://reactjs.org/docs/hooks-rules.html

   Previous render            Next render
   ------------------------------------------------------
1. useContext                 useContext
2. undefined                  useRef
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

摘录DayEvent类似地使用useDrag钩子,也像此处一样在顶层也称为钩子)。

export const Container: FunctionComponent<Props> = () => {
  let events = useContext(State.StateContext)
  //let events: Array<Event.Event> = [] <- with this, no warning

  const getDaysEvents = (day: Event.Time, events: Array<Event.Event>) => {
    return events.map(e => {
      const isTodays = e.startTime.hasSame(day, "day")
      return isTodays && Event.Event({ dayHeight, event: e })
    })
  }

  let days = []
  for (let i = 0; i < 7; i++) {
    const day = DateTime.today().plus({ days: i })
    days.push(
      <Day key={day.toISO()} height={dayHeight} date={day}>
        {getDaysEvents(day, events)}
      </Day>
    )
  }
  return <div className="Container">{days}</div>
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*aix 45

由于使用了短路逻辑,我在编写的组件中遇到了同样的错误消息。

这导致了一个错误:

const x = useSelector(state => state.foo);
if (!x) { return ; }
const y = useSelector(state => state.bar);

Run Code Online (Sandbox Code Playgroud)

这是因为当x为真时,钩子列表的长度为 2,而当x为假时,钩子列表的长度为 1。

为了解决这个错误,我不得不在任何提前终止之前使用所有钩子。

const x = useSelector(state => state.foo);
const y = useSelector(state => state.bar);
if (!x) { return ; }

Run Code Online (Sandbox Code Playgroud)

  • 同样在这里,我做了 const x = 某事?0 : useMemo(); (4认同)

Oll*_*liM 9

写我的评论作为答案:

问题是Event.Event()即使它是React组件,您也要直接调用它。Container即使您希望将它们作为Event的一部分,这也会导致将函数内部的钩子调用视为的反应。

解决方案是使用JSX:

return isTodays && <Event.Event dayHeight={dayHeight} event={e} />

当您用生成的JS代码替换JSX时,为什么这样工作更清楚:

return isTodays && React.createElement(Event.Event, { dayHeight, event: e })

请参阅https://reactjs.org/docs/react-api.html#createelement。您永远都不想直接调用函数组件,react的工作原理是始终将要响应的组件的引用交给它,并让它在正确的时间调用函数。


ham*_*nia 5

由于其他原因而不是这个问题,当你收到这个 error

在此处输入图片说明

它实际上是由于钩子实现的任何不良做法而发生的

1 - 仅在顶层调用挂钩

不要在循环条件嵌套函数中调用 Hook 。相反,始终在 React 函数的顶层使用 Hooks

注意:useState首先在函数顶部实现钩子

2 - 仅从 React 函数调用钩子

不要从常规 JavaScript 函数调用 Hook

3 - 在测试过程中出错

如果在测试组件时遇到此错误,请注意设置自定义钩子的位置(替换到函数顶部)

最佳实践

使用eslint对你的代码进行 lint 避免出现React Hooks Rules错误

使用 npm 或 yarn 安装包

npm install eslint-plugin-react-hooks --save-dev
Run Code Online (Sandbox Code Playgroud)