[React] StrictModeについて
はじめに
Reactアプリケーションを作成していると、コードが2回実行されます。(主に開発環境で)が、それは、ReactのStrictModeが機能していることが要因です。
StrictModeとは
React StrictModeは、コンポーネント内の実装問題を警告したり、予期せぬ動作の要因になりうる使用法を提示するためのモードです。これにより、対応できる問題を事前に発見することができます。
主に、以下のようなことが行われています。
- 純粋でない (impure) レンダーによって引き起こされるバグを見つけるために、レンダーを追加で1回行う
- コンポーネントは、エフェクトのクリーンアップし忘れによるバグを見つけるために、エフェクトの実行を追加で1回行う
- コンポーネントは、ref のクリーンアップし忘れによるバグを見つけるために、ref コールバックの実行を追加で1回行う
- コンポーネントが非推奨のAPIを使用していないかチェックします
StrictModeが適用されているReactアプリケーションのルートファイルでは、以下のようになっているかと思います。
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
// StrictModeを指定
<StrictMode>
<App />
</StrictMode>,
)
ちなみに、アプリケーション全体ではなく、一部のコンポーネント内でのみStrictModeを有効化したい場合は、以下のように設定することもできます。
import { StrictMode } from 'react';
function App() {
return (
<>
<Header />
<StrictMode>
<main>
<Sidebar />
<Content />
</main>
</StrictMode>
<Footer />
</>
);
}
こちらの例では、StrictModeでSidebarとContentを囲っていますが、適用されるのは、SidebarとContentに含まれている子コンポーネントも、適用範囲となります。
目的
StrictModeを使うことで、主に以下のような効果が期待できます。
- 副作用の実装が安全であることを確認する
- レンダリングが再実行可能であることを保証する
- バグの早期発見
1. 副作用の実装の安全性確認
副作用(Side Effects)とは、コンポーネントのメインの機能以外で発生する処理のことです。例えば、、、
APIからのデータフェッチ
DOM操作
タイマーの設定
イベントリスナーの登録
2. レンダリングの再実行可能性の保証
Reactコンポーネントは純粋関数であるべきで、同じ入力(props, state)に対して常に同じ出力(UI)を返すべきです。
// 良い例:再実行可能な純粋なコンポーネント
const UserProfile = ({ user }) => {
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
};
// 悪い例:外部状態に依存する不純なコンポーネント
const UserProfile = ({ user }) => {
// グローバル変数に依存
window.lastRenderedUser = user;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
};
これにより、以下の効果が期待できます。
- コンポーネントを複数回レンダリングしてテスト
- 不純な実装を検出
- 予期せぬ副作用を特定
3. バグの早期発見
Strict Modeは以下のような一般的なバグを開発段階で発見するのに役立ちます:
- メモリリーク
useEffect(() => {
const subscription = api.subscribe();
// クリーンアップを忘れると警告
}, []);
// 正しい実装
useEffect(() => {
const subscription = api.subscribe();
return () => subscription.unsubscribe();
}, []);
2.古いReact APIの使用
// 警告される古いAPI
componentWillMount() {
// ...
}
// 推奨される新しいAPI
useEffect(() => {
// ...
}, []);
3.競合状態(Race Conditions)
useEffect(() => {
let isSubscribed = true;
async function fetchData() {
const result = await api.getData();
if (isSubscribed) { // マウント状態をチェック
setData(result);
}
}
fetchData();
return () => {
isSubscribed = false;
};
}, []);
これらのメリットにより:
- 開発段階でのバグ発見が容易に
- コードの品質が向上
- メンテナンス性が向上
- ユーザー体験の向上
まとめ
Reactでコンポーネントが2回実行される理由は、主に副作用の安全性を確認するために行われます。
StrictModeが有効化されることで、予期しない動作を防ぎ、アプリケーションのパフォーマンスを向上させることが可能です。
Discussion