開発チーム一丸となり2022年6月中旬から7月末を開催期間として各プロダクトのReactをアップグレードしようという取り組みをしました。フロントエンドエキスパートとして、エラーを報告を受けQ&Aを作成するなどをしていたので、その立場からパッケージのアップグレードにどう取り組めば良いのか、実際に報告されたエラーとその対応方法についてまとめます。
まず最初に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以外の使用しているパッケージが古い、推奨されていない記述が残っていることによって発生しているエラー報告は多々ありました。
Reactと一緒にreact-router-domなど他のパッケージも上げようとしてしまい、移行が困難になっているケースがありました。
リポジトリがちゃんと整備されていなくても、プルリクエストをちゃんと小さくしようという努力をしていれば大きくつまずくことはないと思います。
作成したQ&Aを元に、報告されたエラーとその対応方法や未前に防ぐ方法について書きます。
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>
)
@types/reactからPropsWithChildrenがexportされています。
const MyComponent = (props: PropsWithChildren<MyComponentProps>): JSX.Element => {}
return (
<MyComponent>
<div>Child component</div>
</MyComponent>
)
FCからchildrenが削除されたことにより、React 18からVFCは非推奨になりました。 そもそもVFCは、FCからpropsを削除するという破壊的変更を避けるために追加されたもので、FCの変更が行われた今となっては不要なものというわけです。
個人的にもおすすめしませんし、ReactコミュニティとしてFCを使わない流れがあります。
例えばfacebook/create-react-appでも、ジェネリクスを利用したジェネリックコンポーネントを扱えない、"component as namespace pattern"の型が複雑になる、defaultProps(既にdefaultProps自体が非推奨ですが)が上手く動作しないなどの理由から、TypescriptテンプレートからFCが削除されています。
Ref: Remove React.FC from Typescript template #8177
使用しているライブラリが、@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
これを忘れたことによる治らないというエラー報告もありました。
Typescriptのバージョンが古く、export { type Hoge }といった記法をサポートしていない可能性があります。
Typescriptのバージョンを上げてください。
yarn upgrade typescript --latest
パッケージによっては、主に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にしておくことでも回避できると思います。