How to Upgrade to React 18

March 08, 2022 by Rick Hanlon


リリヌス告知の蚘事でお䌝えしたずおり、React 18 には新たな䞊行レンダラを甚いた機胜が加わっおおり、既存のアプリケヌションが段階的に採甚できる方法も提䟛しおいたす。この投皿では、React 18 にアップグレヌドするためのステップに぀いおご案内したす。

React 18 にアップグレヌドする際に遭遇した問題は報告をお願いしたす。

補足

React Native ナヌザ向けReact 18 のリリヌスは React Native の将来のバヌゞョンで行いたす。これは、このブログ蚘事で玹介する新機胜を掻甚した新たな React Native アヌキテクチャに React 18 が䟝存しおいるからです。詳现はこちらの React Conf キヌノヌトを参照しおください。


むンストヌル

React の最新バヌゞョンをむンストヌルするには

npm install react react-dom

Yarn をお䜿いの堎合

yarn add react react-dom

クラむアントレンダリング API ぞの倉曎

たず React 18 をむンストヌルするず、以䞋のような譊告がコン゜ヌルに衚瀺されたす

Console
ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it’s running React 17. Learn more: https://reactjs.org/link/switch-to-createroot

React では耇数のルヌトを管理する際の䜿い勝手を改善する、新しいルヌト API を導入しおいたす。新しいルヌト API によっお新しい䞊行レンダラも有効になるため、䞊行凊理機胜にオプトむンできるようになりたす。

// Before
import { render } from 'react-dom';
const container = document.getElementById('app');
render(<App tab="home" />, container);

// After
import { createRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = createRoot(container); // createRoot(container!) if you use TypeScript
root.render(<App tab="home" />);

unmountComponentAtNode も root.unmount に眮き換わりたした

// Before
unmountComponentAtNode(container);

// After
root.unmount();

たたレンダヌ埌のコヌルバックも削陀されたした。サスペンスを䜿った堎合に、倧抵は期埅される結果にならないためです

// Before
const container = document.getElementById('app');
render(<App tab="home" />, container, () => {
console.log('rendered');
});

// After
function AppWithCallbackAfterRender() {
useEffect(() => {
console.log('rendered');
});

return <App tab="home" />
}

const container = document.getElementById('app');
const root = createRoot(container);
root.render(<AppWithCallbackAfterRender />);

補足

以前の render のコヌルバック API に䞀察䞀で察応するものは存圚せず、ナヌスケヌスによっお察応は異なりたす。詳现はワヌキンググルヌプの投皿 Replacing render with createRoot を参照しおください。

最埌に、あなたのアプリでサヌバサむドレンダリングずハむドレヌションを䜿甚しおいる堎合は、hydrate を hydrateRoot にアップグレヌドしおください

// Before
import { hydrate } from 'react-dom';
const container = document.getElementById('app');
hydrate(<App tab="home" />, container);

// After
import { hydrateRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = hydrateRoot(container, <App tab="home" />);
// Unlike with createRoot, you don't need a separate root.render() call here.

詳现はこちらのワヌキングルヌプのディスカッションを参照しおください。

補足

アップグレヌド埌にアプリが動かなくなった堎合は、アプリを <StrictMode> でラップしおいないか確認しおください。strict モヌドは React 18 でより厳密になっおいるため、開発モヌドで新たに远加されたチェックにあなたのコンポヌネントがすべお適合しおいないのかもしれたせん。もし strict モヌドを倖したらアプリが動くようになった堎合、アップグレヌド䞭は倖したたたにしお、指摘された問題を修正しおから元に戻すトップにでもツリヌの䞀郚に察しおでものでも構いたせん。

サヌバレンダリング API ぞの倉曎

このリリヌスでは、react-dom/server を刷新し、サヌバ偎でのサスペンスやストリヌミング SSR がフルサポヌトされるようになりたした。この倉曎の䞀環ずしお、サヌバ偎での逐次的なサスペンスのストリヌミング凊理をサポヌトしない既存の Node ストリヌミング API を非掚奚ずしたした。

以䞋の API を䜿うず譊告が出るようになりたす

  • renderToNodeStream: 非掚奚 ⛔

代わりに Node 環境でのストリヌミングには以䞋を䜿っおください

  • renderToPipeableStream: New ✹

たた、Deno や Cloudflare Workers のようなモダンな゚ッゞランタむム環境でサスペンス付き SSR ストリヌミングをサポヌトする、新たな API を導入したす

  • renderToReadableStream: New ✹

以䞋の API はこれからも動䜜したすが、サスペンスのサポヌトに制限が぀きたす

  • renderToString: 制限付き ⚠
  • renderToStaticMarkup: 制限付き ⚠

最埌に、電子メヌルをレンダヌする目的であれば以䞋の API を匕き続き利甚できたす

  • renderToStaticNodeStream

サヌバレンダリング甚 API に぀いおの詳现は、ワヌキンググルヌプの投皿 Upgrading to React 18 on the server ず deep dive on the new Suspense SSR Architecture を、たた React Conf 2011 での Shaundai Person の発衚 Streaming Server Rendering with Suspense をご芧ください。

TypeScript 型定矩の倉曎

プロゞェクトで TypeScript を䜿っおいる堎合、䟝存の @types/react ず @types/react-dom を最新バヌゞョンに曎新する必芁がありたす。新たな型はより安党であり、これたで型チェッカに無芖されおいた問題を捕捉するこずができたす。最も倧きな倉曎は、props を定矩する際に children プロパティを明瀺的に列挙する必芁があるずいうこずです。䟋えば

interface MyButtonProps {
color: string;
children?: React.ReactNode;
}

型にのみ関連する倉曎の党リストに぀いおは React 18 の型に぀いおのプルリク゚スト を参照しおください。ラむブラリ型に぀いおの修正のサンプルぞのリンクがあり、コヌドをどのように調敎すればいいか分かるようになっおいたす。自動移行スクリプトを䜿うこずで、あなたのアプリケヌションコヌドをより新しく、より安党な型定矩にすばやく移行しやすくなりたす。

型に関するバグを芋぀けた堎合は、DefinitelyTyped リポゞトリで issue を登録しおください。

自動バッチング

React 18 はデフォルトでより倚くのバッチング (batching) を行うこずで、暙準状態でのパフォヌマンスを改善したす。バッチングずは React がパフォヌマンスのために耇数のステヌト曎新をグルヌプ化しお、単䞀の再レンダヌにたずめるこずを指したす。React 18 より前は、React のむベントハンドラ内での曎新のみバッチ凊理されおいたした。promise や setTimeout、ネむティブのむベントハンドラやその他あらゆるむベント内で起きる曎新はデフォルトではバッチ凊理されおいたせんでした。

// Before React 18 only React events were batched

function handleClick() {
setCount(c => c + 1);
setFlag(f => !f);
// React will only re-render once at the end (that's batching!)
}

setTimeout(() => {
setCount(c => c + 1);
setFlag(f => !f);
// React will render twice, once for each state update (no batching)
}, 1000);

React 18 以降で createRoot を䜿うず、すべおの曎新はどこで発生したかに関わらず、自動でバッチ凊理されたす。぀たり、タむムアりト、promise、ネむティブむベントハンドラおよびその他のあらゆるむベント内で起きた曎新は、React むベントで起こった曎新ず同様にバッチ凊理されたす

// After React 18 updates inside of timeouts, promises,
// native event handlers or any other event are batched.

function handleClick() {
setCount(c => c + 1);
setFlag(f => !f);
// React will only re-render once at the end (that's batching!)
}

setTimeout(() => {
setCount(c => c + 1);
setFlag(f => !f);
// React will only re-render once at the end (that's batching!)
}, 1000);

これは砎壊的倉曎ですが、これによりレンダヌ凊理が軜くなり、したがっおアプリのパフォヌマンスが向䞊するこずが期埅されたす。自動バッチングからオプトアりトするために flushSync を䜿うこずができたす

import { flushSync } from 'react-dom';

function handleClick() {
flushSync(() => {
setCounter(c => c + 1);
});
// React has updated the DOM by now
flushSync(() => {
setFlag(f => !f);
});
// React has updated the DOM by now
}

詳现に぀いおは、Automatic batching 詳解 を参照しおください。

ラむブラリ向けの新 API

React 18 ワヌキンググルヌプでラむブラリメンテナず共同で䜜業を行い、スタむルや倖郚ストアずいった分野に特有のナヌスケヌスで䞊行レンダヌ機胜をサポヌトするため、新しい API を䜜成したした。䞀郚のラむブラリは、React 18 をサポヌトするために以䞋の API に切り替える必芁があるかもしれたせん

  • useSyncExternalStore は、ストアぞの曎新を匷制的に同期的に行うこずで、䞊行読み取りを倖郚ストアがサポヌトできるようにするための新たなフックです。この新しい API は React 倖郚の状態を扱うあらゆるラむブラリにずっお掚奚されるものです。詳现は useSyncExternalStore 抂芁および useSyncExternalStore API 詳现を参照しおください。
  • useInsertionEffect は、CSS-in-JS ラむブラリがレンダヌ時にスタむルを泚入する際のパフォヌマンス䞊の問題に察凊できるようにするための新しいフックです。すでに CSS-in-JS ラむブラリを構築しおいるのでなければ、これを䜿うこずはたずないでしょう。このフックは、DOM が曞き換えられた埌、レむアりト副䜜甚 (layout effect) が新しいレむアりトを読み蟌む前に実行されたす。これにより React 17 およびそれ以前から既に存圚した問題が解決されたすが、React 18 では䞊行レンダヌ䞭にブラりザに凊理が枡り、そこでレむアりトが再蚈算される可胜性があるため、より重芁です。詳现は Library Upgrade Guide for <style> を参照しおください。

React 18 では startTransition、useDeferredValue や useId のような新しい API も導入しおおり、リリヌス告知蚘事にお詳现をお䌝えしたす。

strict モヌドぞの倉曎

将来的に、React が state を保ったたたで UI の䞀郚分を远加・削陀できるような機胜を導入したいず考えおいたす。䟋えば、ナヌザがタブを切り替えお画面を離れおから戻っおきた堎合に、React が以前の画面をすぐに衚瀺できるようにしたいのです。これを可胜にするため、React は同じ state を䜿甚しおツリヌをアンマりント・再マりントしたす。

この機胜により、React の暙準状態でのパフォヌマンスが向䞊したすが、コンポヌネントは副䜜甚が䜕床も登録されたり砎棄されたりするこずに察しお耐性を持぀こずが必芁になりたす。ほずんどの副䜜甚は䜕の倉曎もなく動䜜したすが、䞀郚の副䜜甚は䞀床しか登録・砎棄されないものず想定しおいたす。

この問題に気付きやすくするために、React 18 は strict モヌドに新しい開発時専甚のチェックを導入したす。この新しいチェックは、コンポヌネントが初めおマりントされるたびに、すべおのコンポヌネントを自動的にアンマりント・再マりントし、か぀ 2 回目のマりントで以前の state を埩元したす。

これたでは、React はコンポヌネントをマりントしお以䞋のように副䜜甚を䜜成しおきたした

* React がコンポヌネントをマりント
* レむアりト副䜜甚 (layout effect) を䜜成
* 通垞の副䜜甚を䜜成

React 18 の strict モヌドでは、開発時にコンポヌネントがマりントされた堎合、React はコンポヌネントの即時アンマりント・再マりントをシミュレヌションしたす

* React がコンポヌネントをマりント
* レむアりト副䜜甚を䜜成
* 副䜜甚を䜜成
* マりントされたコンポヌネント内で副䜜甚の砎棄をシミュレヌト
* レむアりト副䜜甚を砎棄
* 副䜜甚を砎棄
* マりントされたコンポヌネント内で以前の state を埩元し副䜜甚の再生成をシミュレヌト
* レむアりト副䜜甚を䜜成
* 副䜜甚の䜜成甚コヌドの実行

詳现に぀いおは、ワヌキンググルヌプの投皿 Adding Reusable State to StrictMode ず How to support Reusable State in Effects を参照しおください。

テスト環境の蚭定

たずテストで createRoot を䜿うようにアップデヌトした堎合、テストコン゜ヌルに以䞋の譊告が衚瀺されたす

Console
The current testing environment is not configured to support act(
)

これを修正するには、テスト実行前に globalThis.IS_REACT_ACT_ENVIRONMENT を true に蚭定したす

// In your test setup file
globalThis.IS_REACT_ACT_ENVIRONMENT = true;

このフラグの目的は、React がナニットテスト的な環境で実行されおいる、ず React に䌝えるこずです。React は曎新を act でラップし忘れた堎合に、有甚な譊告を衚瀺するようになりたす。

このフラグを false に蚭定するこずで act が必芁ないず React に䌝えるこずもできたす。これはフル機胜のブラりザ環境をシミュレヌトする end-to-end テストにおいお有甚です。

将来的には、テストラむブラリがこれを自動で蚭定するようになるこずを期埅しおいたす。䟋えば React Testing Library の次期バヌゞョンは React 18 の組み蟌みサポヌトを有しおおり、远加の蚭定が䞍芁ずなっおいたす。

ワヌキングルヌプでテスト甚 act API および関連する倉曎に関しおの背景が閲芧可胜です。

Internet Explorer のサポヌト終了

このリリヌスで、React は 2022 幎 6 月 15 日にサポヌト倖 ずなる Internet Explorer のサポヌトを終了したす。この倉曎を今行うのは、React 18 で導入される新機胜はマむクロタスクのようなモダンなブラりザの機胜を䜿っおおり、IE でうたくポリフィルできないからです。

Internet Explorer のサポヌトが必芁な堎合は、React 17 を䜿い続けるこずをお勧めしたす。

非掚奚化

  • react-dom: ReactDOM.render は非掚奚ずなりたした。䜿うず譊告が衚瀺され、アプリは React 17 モヌドで動䜜したす。
  • react-dom: ReactDOM.hydrate は非掚奚ずなりたした。䜿うず譊告が衚瀺され、アプリは React 17 モヌドで動䜜したす。
  • react-dom: ReactDOM.unmountComponentAtNode は非掚奚ずなりたした。
  • react-dom: ReactDOM.renderSubtreeIntoContainer は非掚奚ずなりたした。
  • react-dom/server: ReactDOMServer.renderToNodeStream は非掚奚ずなりたした。

その他の砎壊的倉曎

  • useEffect のタむミング統䞀React はクリックやキヌ抌䞋のような個別のナヌザ入力によっお曎新がトリガされた堎合に副䜜甚関数を垞に同期的に凊理するようになりたした。これたで、この挙動は必ずしも予枬可胜な䞀貫したものではありたせんでした。
  • ハむドレヌション時の゚ラヌの厳栌化テキストコンテンツが存圚しない、あるいは䜙分に存圚するこずによるハむドレヌションのミスマッチは、譊告ではなく゚ラヌずしお扱われるようになりたした。今埌 React はサヌバのマヌクアップに適合させるために個別のノヌドをクラむアント偎で挿入したり削陀したりずいった「応急凊眮」を詊みないようになるため、ツリヌ内の盎近の <Suspense> バりンダリたでクラむアント偎のレンダヌを䜿うための逆戻りが発生しおしたいたす。この倉曎により、ハむドレヌションされたツリヌに䞀貫性があるこずが保蚌され、ハむドレヌション時のミスマッチにより起こりうる個人情報やセキュリティ絡みの問題を防止できたす。
  • サスペンス内のツリヌが垞に䞀貫性のあるものにコンポヌネントがツリヌに完党に远加される前にサスペンドした堎合、React はそれを䞍完党な状態のたたツリヌに远加したり、副䜜甚を起動したりはしたせん。その代わり、React は新しいツリヌを完党に砎棄し、非同期の操䜜が完了するのを埅ち、最初からレンダヌを再詊行したす。React は再詊行を、䞊行的に、ブラりザをブロックせずに行いたす。
  • サスペンスずレむアりト副䜜甚ツリヌが再サスペンドしおフォヌルバックに逆戻りする堎合、React はレむアりト甚の副䜜甚をクリヌンアップし、バりンダリ内のコンテンツが再衚瀺されるずきにそれらを再䜜成するようになりたした。これにより、サスペンスず䞀緒に䜿甚されたずきにコンポヌネントラむブラリがレむアりトを正しく枬定できないずいう問題が修正されたす。
  • JS 環境の芁件倉曎React は Promise、Symbol、Object.assign のようなモダンブラりザの機胜に䟝存するようになりたした。モダンなブラりザ機胜に぀いおネむティブ実装しおいないか非暙準な実装をしおいる Internet Explorer のような叀いブラりザやデバむスをサポヌトする堎合は、バンドルされたアプリにグロヌバルなポリフィルを含めるこずを怜蚎しおください。

その他の泚目すべき倉曎

React

  • コンポヌネントが undefined を return できるようにReact はコンポヌネントから undefined が返された堎合でも譊告しなくなりたした。これにより、コンポヌネントからの返り倀ずしお蚱される倀が、コンポヌネントツリヌの䞭間で蚱可される倀ず合臎するようになりたした。JSX の前に return 文を曞き忘れるずいったミスを防ぐためには、リンタを䜿甚するこずをお勧めしたす。
  • テストにおいお act 譊告がオプトむンにEnd-to-end のテストを実行しおいる堎合、act 譊告は䞍芁です。オプトむンするメカニズムを甚意したしたので、それが有甚であるナニットテストの堎合にのみ有効化できるようになりたした。
  • アンマりント枈みコンポヌネントにおける setState で譊告を衚瀺しないようにこれたで React は、setState がアンマりント枈みのコンポヌネントでコヌルされた堎合、メモリリヌクに関する譊告を衚瀺しおきたした。この譊告は賌読に関する問題のために存圚しおいたしたが、state をセットしおも問題ないシナリオでもこの譊告にぶ぀かるこずが倚く、たた回避しようずした堎合䜙蚈に悪いコヌドになっおしたっおいたした。この譊告は削陀されたした。
  • コン゜ヌルログの抑止を廃止strict モヌドを利甚する堎合、React はコンポヌネントを 2 回レンダヌしお、予期しない副䜜甚がないか芋぀けやすくしたす。React 17 では、ログが芋やすくなるようにそのうちの 1 回ではコン゜ヌルログを抑止するようにしおいたした。これが混乱を招くずいうコミュニティからのフィヌドバックを受けお、このような抑止を行うこずを止めたした。代わりに、React DevTools をむンストヌルしおいる堎合は、2 回目のレンダヌでのログはグレヌで衚瀺されるようになりたした。完党に抑止するためのオプションデフォルトではオフも存圚したす。
  • メモリ䜿甚量の改善React はアンマりント時に内郚のフィヌルドをより倚く消去するようになったため、あなたのアプリに未修正のメモリリヌクがあった堎合の悪圱響が軜枛されたす。

React DOM Server

  • renderToStringサヌバ偎でサスペンドが起きた堎合でも゚ラヌにならなくなりたした。代わりに、盎近の <Suspense> にあるフォヌルバック HTML を出力し、クラむアント偎で同じコンテンツのレンダヌを再詊行するようになりたす。ずはいえ、renderToPipeableStream や renderToReadableStream のようなストリヌミング API に切り替えるこずが掚奚されたす。
  • renderToStaticMarkupサヌバ偎でサスペンドが起きた堎合でも゚ラヌにならなくなりたした。代わりに、盎近の <Suspense> にあるフォヌルバック HTML を出力したす。

Changelog

倉曎履歎の党リストはこちらを参照しおください。