
パフォーマンス最適化の基本
Reactアプリケーションのパフォーマンスを向上させるには、不必要なレンダリングを防ぎ、リソースの使用を最適化することが重要です。Reactはデフォルトで効率的なレンダリングを行いますが、以下のテクニックを活用することでさらに改善できます。
- メモ化(Memoization):
React.memo
やuseMemo
、useCallback
を使用して、コンポーネントや計算結果、関数の再生成を防ぎます。 - コード分割(Code Splitting): 必要なコードのみを動的に読み込むことで、初期ロード時間を短縮します。
- 不要なレンダリングの回避: コンポーネントの依存関係を適切に管理し、無駄な更新を減らします。
これらのテクニックを実際のコードで試します。
ハンズオン:メモ化による最適化
パフォーマンス最適化の基本を理解するため、第9回で作成したテーマ切り替えアプリケーションにメモ化を適用します。src/Home.js
をReact.memo
でラップし、不要なレンダリングを防ぎます。Home.js
を以下のように編集します。
import React from 'react';
import { useTheme } from './ThemeContext';
function Home() {
const { theme } = useTheme();
console.log('Homeレンダリング');
return (
<div className={`content ${theme}`}>
<h2>ホーム</h2>
<p>テーマ切り替えをお試しください!</p>
</div>
);
}
export default React.memo(Home);
React.memo
は、Propsが変化しない限りコンポーネントの再レンダリングを防ぎます。About.js
も同様に編集します。
import React from 'react';
import { useTheme } from './ThemeContext';
function About() {
const { theme } = useTheme();
console.log('Aboutレンダリング');
return (
<div className={`content ${theme}`}>
<h2>アバウト</h2>
<p>コンテキストAPIでテーマを管理しています。</p>
</div>
);
}
export default React.memo(About);
次に、useCallback
を使用して、src/ThemeContext.js
のtoggleTheme
関数をメモ化します。
import React, { createContext, useContext, useState, useCallback } from 'react';
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = useCallback(() => {
setTheme((prev) => (prev === 'light' ? 'dark' : 'light'));
}, []);
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
return useContext(ThemeContext);
}
useCallback
は、依存配列(この場合は空)が変化しない限り同じ関数インスタンスを返します。これにより、toggleTheme
が原因で子コンポーネントが再レンダリングされるのを防ぎます。src/App.js
は第10回の状態を維持しますが、動作確認のためコンソールログを追加します。
import React from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import { ThemeProvider, useTheme } from './ThemeContext';
import Home from './Home';
import About from './About';
import './App.css';
function ThemeToggle() {
const { theme, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme}>
{theme === 'light' ? 'ダークモード' : 'ライトモード'}に切り替え
</button>
);
}
function App() {
const { theme } = useTheme();
console.log('Appレンダリング');
return (
<div className={`app-container ${theme}`}>
<h1>テーマ切り替えアプリケーション</h1>
<nav>
<Link to="/" style={{ margin: '0 10px' }}>
ホーム
</Link>
<Link to="/about" style={{ margin: '0 10px' }}>
アバウト
</Link>
</nav>
<ThemeToggle />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</div>
);
}
export default function Root() {
return (
<BrowserRouter>
<ThemeProvider>
<App />
</ThemeProvider>
</BrowserRouter>
);
}
開発サーバー(npm start
)が起動している状態でブラウザのコンソールを確認します。テーマを切り替えると、Home
やAbout
のレンダリングログが抑制され、必要な場合にのみレンダリングされることがわかります。React.memo
とuseCallback
により、パフォーマンスが改善されています。
コード分割の実装
初期ロード時間を短縮するため、コード分割を適用します。Reactのlazy
とSuspense
を使用して、コンポーネントを動的に読み込みます。App.js
を以下のように編集します。
import React, { Suspense, lazy } from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import { ThemeProvider, useTheme } from './ThemeContext';
import './App.css';
const Home = lazy(() => import('./Home'));
const About = lazy(() => import('./About'));
function ThemeToggle() {
const { theme, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme}>
{theme === 'light' ? 'ダークモード' : 'ライトモード'}に切り替え
</button>
);
}
function App() {
const { theme } = useTheme();
return (
<div className={`app-container ${theme}`}>
<h1>テーマ切り替えアプリケーション</h1>
<nav>
<Link to="/" style={{ margin: '0 10px' }}>
ホーム
</Link>
<Link to="/about" style={{ margin: '0 10px' }}>
アバウト
</Link>
</nav>
<ThemeToggle />
<Suspense fallback={<p>読み込み中...</p>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</div>
);
}
export default function Root() {
return (
<BrowserRouter>
<ThemeProvider>
<App />
</ThemeProvider>
</BrowserRouter>
);
}
lazy
でコンポーネントを動的にインポートし、Suspense
で読み込み中のフォールバックUIを指定します。ブラウザの開発者ツール(ネットワークタブ)で確認すると、Home
とAbout
が別々のチャンクとして必要に応じて読み込まれることがわかります。これにより、初期ロード時間が短縮されます。
ハンズオン:本番環境へのデプロイ
最適化を施したアプリケーションを本番環境にデプロイします。ここでは、Netlifyを使用したデプロイ手順を説明します。Netlifyは、静的サイトのホスティングに適しており、Create React Appとの統合が簡単です。
- ビルドの実行: プロジェクトディレクトリで以下のコマンドを実行し、本番用ビルドを生成します。
npm run build
これにより、build
フォルダに最適化された静的ファイルが生成されます。
-
Netlifyにデプロイ: Netlifyのウェブサイト(https://www.netlify.com)にアクセスし、アカウントを作成またはログインします。以下の手順を実行します。
- 「New site from Git」を選択し、GitHubリポジトリにプロジェクトをプッシュ済みの場合はリポジトリを接続します。
- ビルド設定で、ビルドコマンドを
npm run build
、公開ディレクトリをbuild
に設定します。 - 「Deploy site」をクリックすると、アプリケーションがデプロイされ、ユニークなURLが発行されます。
-
ローカルでのビルド確認: デプロイ前に、ビルドされたアプリケーションをローカルで確認するには、以下のコマンドを実行します。
npm install -g serve
serve -s build
ブラウザでhttp://localhost:3000
にアクセスし、アプリケーションが正しく動作することを確認します。Netlifyにデプロイ後、発行されたURLでアプリケーションにアクセスし、テーマ切り替えやナビゲーションが期待通りに動作することを確認します。
ハンズオン:最適化の拡張
パフォーマンス最適化の効果をさらに実感するため、読者自身で機能を追加します。以下の課題を試してください。src/App.js
にuseMemo
を使用して、テーマに基づく計算結果をメモ化します。以下は一例です。
import React, { Suspense, lazy, useMemo } from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import { ThemeProvider, useTheme } from './ThemeContext';
import './App.css';
const Home = lazy(() => import('./Home'));
const About = lazy(() => import('./About'));
function ThemeToggle() {
const { theme, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme}>
{theme === 'light' ? 'ダークモード' : 'ライトモード'}に切り替え
</button>
);
}
function App() {
const { theme } = useTheme();
const themeStyles = useMemo(() => ({
backgroundColor: theme === 'light' ? '#ffffff' : '#333333',
color: theme === 'light' ? '#000000' : '#ffffff',
}), [theme]);
return (
<div className="app-container" style={themeStyles}>
<h1>テーマ切り替えアプリケーション</h1>
<nav>
<Link to="/" style={{ margin: '0 10px' }}>
ホーム
</Link>
<Link to="/about" style={{ margin: '0 10px' }}>
アバウト
</Link>
</nav>
<ThemeToggle />
<Suspense fallback={<p>読み込み中...</p>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</div>
);
}
export default function Root() {
return (
<BrowserRouter>
<ThemeProvider>
<App />
</ThemeProvider>
</BrowserRouter>
);
}
このコードでは、useMemo
を使用してテーマに基づくスタイルオブジェクトをメモ化し、テーマが変化しない限り再計算を防ぎます。ブラウザで動作を確認し、開発者ツールのパフォーマンスタブを使用して、レンダリングの効率が向上していることを確認します。自分で他の最適化(例:リストの仮想化)やデプロイ先(例:Vercel)を試し、最適化とデプロイのスキルを深めてください。
次のステップに向けて
本記事では、Reactアプリケーションのパフォーマンス最適化と本番環境へのデプロイを学びました。メモ化やコード分割により、効率的で高速なアプリケーションを構築し、Netlifyで公開する方法を習得しました。本連載を通じて、Reactの基礎から応用までをハンズオン形式で学び、実際のプロジェクトに応用可能なスキルを身につけました。今後は、状態管理ライブラリ(例:Redux)やテストフレームワーク(例:Jest)を学ぶことで、さらに高度なReact開発に挑戦してください。