“React 检测到 Hooks 的顺序发生了变化”但是 Hooks 似乎是按顺序调用的

新手上路,请多包涵

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

是我在循环中生成 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
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Container 的完整版本如下。下面是 Day 的摘录,并有来自 react-dnduseDrop 的参考。

 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>
}

摘录自 DayEvent 同样使用 useDrag 挂钩,也像此处一样在顶层调用)。

 const Day: FunctionComponent<DayProps> = ({ date, height, children }) => {
  const dispatch = useContext(State.DispatchContext)
  const [{ isOver, offset }, dropRef] = useDrop({
    // …uses the dispatch function within…
    // …
  })
  // …
}

原文由 Isaac 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

写下我的评论作为答案:

问题是您正在直接调用 Event.Event() ,即使它是一个反应组件。这导致 React 将函数内的挂钩调用视为 Container 的一部分,即使您想让它们成为 Event 的一部分。

解决方案是使用 JSX:

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

当您将 JSX 替换为生成的 JS 代码时,为什么这会更清楚:

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

请参阅 https://reactjs.org/docs/react-api.html#createelement 。你永远不想直接调用函数组件,react 的工作原理是你总是传递一个引用组件来 react 并让它在正确的时间调用函数。

原文由 OlliM 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

这导致了一个错误:

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

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

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

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

原文由 JamesFaix 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题