😊

今更ながらReact17 → React18でつまづいた所

2025/01/21に公開

株式会社イルシルCTO 倉橋康熙です。
業務でReact17→React18のアップデートを行ったので備忘録に。

1. useHistoryは使えない

useHistoryは廃止されてしまったのでhistory.pushやhistory.replace、hisotry.location.pathname等は全て使えません。
useNavigation、useLocationを使いましょう

// react-douter-dom v5
const history = useHistory();
history.push("/")
history.replace("/")
history.location.pathname
<Redirect to="/"/>
// react-douter-dom v6
const navigation = useNavigate();
const location = useLocation()
navigation("/")
navigation("/", { replace: true })
location.pathname
<Navigate replace to="/"/>

2. useEffectの返り値や非同期に気をつける

React18へアップデートする際

TypeError: destroy is not a function

のように出ることがあります。

今回の場合は以下のようなuseEffectがあったからでした。

※頑張ってこのようにuseEffect使用してる箇所全部探しましょう

// useEffectの第一引数自体が非同期関数になってしまっている
useEffect(async() => {
  ...
})

// useEffectの返り値がundefinedか関数のどちらでもない場合
useEffect(() => {
  ...
  return someValue;
})

3. ルーティングの入れ子構造

以前までは以下のような形でルーティングしている部分がありました。

const RouteComponent = () => {
  ...
  return (
    <BrowserRouter>
      <Switch>
        ...
        <Route path="*">
          <SomeComponent />
        </Route>
      </Swich>
    </BrowserRouter>
  )
}

const SomeComponent = () => {
  ...
  return (
    <Switch>
      <Route ...
    </Swich>
  )
}

しかしreact-router-dom v6ではそのままでは入れ子構造にできずにuseLocationの返り値を渡す必要がありました。

const RouteComponent = () => {
  ...
  return (
    <BrowserRouter>
      <Routes>
        ...
        <Route path="*" element={ <SomeComponent />} />
      </Swich>
    </BrowserRouter>
  )
}

const SomeComponent = () => {
  ...
  const location = useLocation()
  return (
    <Routes location={location}>
      <Route ...
    </Swich>
  )
}

4. 循環参照にご注意を

特に心当たりがないのに以下のエラーが出る時は循環参照を疑いましょう。

ReferenceError: Cannot access 'XXX' before initialization

以上React18へのアップデートの際につまづいた点でした。

皆さんのご知見になればと思います🙇

株式会社イルシル

Discussion