Upgrade to React 18
会社にて、ほとんどのサービスの React のバージョンをアップグレードするイベントを開催しました。フロントエンドエキスパートとして、エラーを報告を受け Q&A を作成するなどをしていたので、その立場からパッケージのアップグレードにどう取り組めば良いのか、実際に報告されたエラーとその対応方法についてまとめます。
React 18 アップグレードは怖くない
まず最初に React 18 へアップグレードすることは全く怖くありません。
少なくとも基本的なことをちゃんとやっていれば、どうすればいいか分からないといった状況にはならないと思います。
公式ドキュメントをちゃんと読む
公式ドキュメントはちゃんと読みましょう。
特に公式ドキュメントの 1 番上に書かれた、この変更を忘れたことによる報告が多々ありました。
import { createRoot } from "react-dom/client";const container = document.getElementById("app");const root = createRoot(container);root.render(<App tab="home" />);
エラーをちゃんと読む
エラー報告を受けた内 2 割程度は、エラーメッセージにどうような状況か詳細に書かれたものや、対応について書かれたドキュメントへのリンクを含むものでした。
エラーが出ても落ち着いて、メッセージを読みましょう。失敗しても慌てないというメンタルは大切です。
リポジトリをちゃんと整備する
React 以外の使用しているパッケージが古い、推奨されていない記述が残っていることによって発生しているエラー報告は多々ありました。
- Dependabot や renovate を導入し、パッケージはなるべく新しい状態を保ちましょう。
- Deprecated な記法はなるべく使わないようにしましょう。もし気付けないのであれば ESLint などで検知出来る仕組みを作るべきです。
- 使用しているライブラリには、ちゃんと興味を持ち、どのような利用が推奨されているのかなどを学んでおきましょう。
プルリクエストには余計な変更を入れない
React と一緒に react-router-dom など他のパッケージも上げようとしてしまい、移行が困難になっているケースがありました。
リポジトリがちゃんと整備されていなくても、プルリクエストをちゃんと小さくしようという努力をしていれば大きくつまずくことはないと思います。
- React 18 アップグレードと関係がない変更は別のプルリクエストで行うべきです。
- React 18 アップグレードと関係がある変更でも、分割できないか考えましょう。
- React 18 に関連してパッケージをアップグレードする際には、React 18 サポートをしつつ 17 をドロップしていないバージョンがあれば、そのパッケージのみを上げるプルリクエストをまず投げましょう。
エラー報告と対応
作成した Q&A を元に、報告されたエラーとその対応方法や未前に防ぐ方法について書きます。
Property ‘children’ does not exist
FC から children が削除されたことに起因している可能性があります。
Incorrect
const MyComponent: React.FC = () => {};return ( <MyComponent> <div>Child component</div> </MyComponent>);
Correct
const MyComponent = (props: { children: React.ReactNode }): JSX.Element => {};return ( <MyComponent> <div>Child component</div> </MyComponent>);
Children の型を書くのが面倒
@types/react から PropsWithChildren が export されています。
const MyComponent = ( props: PropsWithChildren<MyComponentProps>): JSX.Element => {};return ( <MyComponent> <div>Child component</div> </MyComponent>);
VFC を使うべきか
FC から children が削除されたことにより、React 18 から VFC は非推奨になりました。 そもそも VFC は、FC から props を削除するという破壊的変更を避けるために追加されたもので、FC の変更が行われた今となっては不要なものというわけです。
FC を使うべきか
個人的にもおすすめしませんし、React コミュニティとして FC を使わない流れがあります。
例えばfacebook/create-react-appでも、ジェネリクスを利用したジェネリックコンポーネントを扱えない、“component as namespace pattern”の型が複雑になる、defaultProps(既に defaultProps 自体が非推奨ですが)が上手く動作しないなどの理由により Typescript テンプレートから FC が削除されています。
SomeComponent cannot be used as a JSX component
使用しているライブラリが、@types/react の 17 系に依存している可能性があります。
まずは依存していないか、またどのライブラリが依存しているのかを調べましょう。
npm ls @types/react
依存しているライブラリのリリースノートを確認した上で問題がなさそうであれば、アップグレードしましょう。
yarn upgrade [some package] --latest
それでも治らない、またはアップグレードが困難である場合は package.json に次のような記述を加えて@types/react 18 を強制します。 バージョンの指定は現在利用している 18 系のものに書き換えてください。
"resolutions": { "@types/react": "18.0.12"}
この記述をした上で再度パッケージのインストールを実行してください。
yarn install
これを忘れたことによる治らないというエラー報告もありました。
error TS1005: ’,’ expected.
Typescript のバージョンが古く、export { type Hoge }といった記法をサポートしていない可能性があります。
Typescript のバージョンを上げてください。
yarn upgrade typescript --latest
BrowserRouter で型エラーが出る
パッケージによっては、主に FC などへの対応で型のアップグレードが必要です。
react-router-dom 5 の場合、@types/react-router-dom のバージョンを上げてください。
yarn upgrade @types/react-router-dom --latest
react-router-dom 6 の場合は、react-router-dom 内に型が含まれているので、react-router-dom のバージョンを上げてください。
ローカル環境を立ち上げるコマンドが失敗する
報告を受けた例では、webpack-cli のバージョンと@webpack-cli/serve の有無によって発生していました。
そもそも@webpack-cli/serve は不要でしたが、React 18 対応をする中で、いくつのもパッケージをインストールしたり、ロックファイルを再生成する中で webpack-cli のバージョンが上がりエラーとして露見したようです。webpack-cli を最新に上げれば解決します。
このような問題は、利用しているパッケージのメンテナンスの他、バージョンの指定を Pin dependencies にしておくことでも回避できると思います。