1. ホーム
  2. javascript

[解決済み] "React has detected a change in the order of Hooks" しかし、Hookは順番に呼び出されているようだ

2022-02-18 13:16:44

質問

を使おうとしています。 ContextReducers をReactのフック経由で実行したところ、フックの順番が一定でないという問題が発生しました。私の理解では、フックの順番が一定であれば 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-dnd 's useDrop .

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

からの抜粋です。 Day ( Event は、同様に useDrag フックも、ここと同じようにトップレベルで呼び出されます)。

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

解決方法は?

私のコメントを回答として書き込む

問題は、あなたが Event.Event() は、reactコンポーネントであるにもかかわらず、直接、このコンポーネントにアクセスします。そのため、関数内のフックコールをreactの一部として扱ってしまいます。 Container の一部であることを意図しているにもかかわらず、そのようなことはありません。

解決策は、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に渡し、適切なタイミングで関数を呼び出すようにします。