Knowledge Center
技術情報などを公開しています
en ja zh
React入門 全12回シリーズ

Reactアプリの最適化と本番環境へのデプロイ(第12回)

By Author
image
Reactアプリケーションを完成させる最終段階では、パフォーマンスの最適化と本番環境へのデプロイが重要です。最適化により、ユーザー体験を向上させ、リソースの使用効率を高めます。デプロイにより、アプリケーションを公開し、広く利用可能にします。本連載の第12回では、Reactアプリケーションのパフォーマンス最適化のテクニックと、本番環境へのデプロイ方法をハンズオン形式で学びます。第1回で構築したReact開発環境、第2回のJSX、第3回のProps、第4回の`useState`、第5回のイベントハンドリング、第6回のリストレンダリング、第7回の`useEffect`、第8回のフォーム、第9回のReact Router、第10回のコンテキストAPI、第11回のカスタムフックの知識を基に、macOS環境で開発を進めます。本記事は、プログラミングの基礎知識を持つ読者を対象としています。

パフォーマンス最適化の基本

Reactアプリケーションのパフォーマンスを向上させるには、不必要なレンダリングを防ぎ、リソースの使用を最適化することが重要です。Reactはデフォルトで効率的なレンダリングを行いますが、以下のテクニックを活用することでさらに改善できます。

  1. メモ化(Memoization): React.memouseMemouseCallbackを使用して、コンポーネントや計算結果、関数の再生成を防ぎます。
  2. コード分割(Code Splitting): 必要なコードのみを動的に読み込むことで、初期ロード時間を短縮します。
  3. 不要なレンダリングの回避: コンポーネントの依存関係を適切に管理し、無駄な更新を減らします。

これらのテクニックを実際のコードで試します。

ハンズオン:メモ化による最適化

パフォーマンス最適化の基本を理解するため、第9回で作成したテーマ切り替えアプリケーションにメモ化を適用します。src/Home.jsReact.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.jstoggleTheme関数をメモ化します。

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)が起動している状態でブラウザのコンソールを確認します。テーマを切り替えると、HomeAboutのレンダリングログが抑制され、必要な場合にのみレンダリングされることがわかります。React.memouseCallbackにより、パフォーマンスが改善されています。

コード分割の実装

初期ロード時間を短縮するため、コード分割を適用します。ReactのlazySuspenseを使用して、コンポーネントを動的に読み込みます。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を指定します。ブラウザの開発者ツール(ネットワークタブ)で確認すると、HomeAboutが別々のチャンクとして必要に応じて読み込まれることがわかります。これにより、初期ロード時間が短縮されます。

ハンズオン:本番環境へのデプロイ

最適化を施したアプリケーションを本番環境にデプロイします。ここでは、Netlifyを使用したデプロイ手順を説明します。Netlifyは、静的サイトのホスティングに適しており、Create React Appとの統合が簡単です。

  1. ビルドの実行: プロジェクトディレクトリで以下のコマンドを実行し、本番用ビルドを生成します。
npm run build    

これにより、buildフォルダに最適化された静的ファイルが生成されます。

  1. Netlifyにデプロイ: Netlifyのウェブサイト(https://www.netlify.com)にアクセスし、アカウントを作成またはログインします。以下の手順を実行します。

    • 「New site from Git」を選択し、GitHubリポジトリにプロジェクトをプッシュ済みの場合はリポジトリを接続します。
    • ビルド設定で、ビルドコマンドをnpm run build、公開ディレクトリをbuildに設定します。
    • 「Deploy site」をクリックすると、アプリケーションがデプロイされ、ユニークなURLが発行されます。
  2. ローカルでのビルド確認: デプロイ前に、ビルドされたアプリケーションをローカルで確認するには、以下のコマンドを実行します。

npm install -g serve    
serve -s build    

ブラウザでhttp://localhost:3000にアクセスし、アプリケーションが正しく動作することを確認します。Netlifyにデプロイ後、発行されたURLでアプリケーションにアクセスし、テーマ切り替えやナビゲーションが期待通りに動作することを確認します。

ハンズオン:最適化の拡張

パフォーマンス最適化の効果をさらに実感するため、読者自身で機能を追加します。以下の課題を試してください。src/App.jsuseMemoを使用して、テーマに基づく計算結果をメモ化します。以下は一例です。

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開発に挑戦してください。

おすすめの記事