Reactは、コンポーネントを利用して再利用性の高いコードを書ける強力なフロントエンドライブラリですが、日々更新されるエコシステムの中で、意外と知られていない便利な機能も多く存在します。この記事では、そんな「知ると役立つ」Reactの機能について、具体的なコード例を交えながらご紹介しようと思います。
1. React.memo
によるコンポーネントのレンダリング最適化
React.memo
は、コンポーネントが不必要に再レンダリングされるのを防ぐための機能です。通常、親コンポーネントが再レンダリングされると子コンポーネントも再レンダリングされますが、子コンポーネントが特に更新される必要がない場合でも再レンダリングされることがあります。React.memo
を使うことで、親コンポーネントが再レンダリングされても、子コンポーネントのプロパティに変更がない限り再レンダリングを抑制することができます。
import React from 'react';
// 普通の関数コンポーネント
const ExpensiveComponent = ({ value }) => {
console.log("ExpensiveComponentが再レンダリングされました!");
return <div>{value}</div>;
};
// React.memoを使ったメモ化
const MemoizedComponent = React.memo(ExpensiveComponent);
export default function App() {
const [count, setCount] = React.useState(0);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>増やす</button>
<MemoizedComponent value="メモ化された値" />
</div>
);
}
上記のコードでは、MemoizedComponent
がReact.memo
でラップされているため、count
が変わってもMemoizedComponent
は再レンダリングされません。これにより、パフォーマンスが向上します。
2. React.lazy
とSuspense
によるコード分割(Code Splitting)
Reactでは、React.lazy
とSuspense
を使うことで、必要な時にのみコンポーネントをロードする「遅延読み込み」が可能です。特に、アプリが大規模になると初回ロードの速度が遅くなりがちですが、React.lazy
を活用することで、特定のコンポーネントのみ遅延ロードし、パフォーマンス改善を図ることができます。
import React, { Suspense } from 'react';
// React.lazyを使用してコンポーネントを遅延読み込み
const LazyLoadedComponent = React.lazy(() => import('./LazyLoadedComponent'));
function App() {
return (
<div>
<h1>React.lazyとSuspenseの例</h1>
<Suspense fallback={<div>Loading...</div>}>
<LazyLoadedComponent />
</Suspense>
</div>
);
}
export default App;
この例では、LazyLoadedComponent
はSuspense
内でラップされています。これにより、LazyLoadedComponent
が読み込まれるまで"Loading..."
と表示され、読み込みが完了すると実際のコンポーネントがレンダリングされます。これを使うことで、アプリ全体の初期読み込みが軽くなり、ユーザーにとってより快適な体験を提供できます。
3. useCallback
とuseMemo
で無駄な計算を避ける
useCallback
とuseMemo
は、不要な再計算や関数の再生成を防ぐためのフックです。これにより、特に高コストな計算が行われる場合にパフォーマンスを最適化できます。
useCallback
の例
useCallback
は、依存する値が変わらない限り、同じ関数インスタンスを再利用します。
import React, { useState, useCallback } from 'react';
function App() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log('クリックされました!');
}, []);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>増やす</button>
<button onClick={handleClick}>クリック</button>
</div>
);
}
この例では、handleClick
はuseCallback
を使ってメモ化されています。count
が変わってもhandleClick
は再生成されないため、不要なレンダリングを防ぐことができます。
useMemo
の例
useMemo
は、依存する値が変わらない限り、計算結果をキャッシュするために使用します。
import React, { useState, useMemo } from 'react';
function App() {
const [count, setCount] = useState(0);
const [otherCount, setOtherCount] = useState(0);
const expensiveCalculation = useMemo(() => {
console.log("高コストな計算実行中...");
return count * 2;
}, [count]);
return (
<div>
<h1>カウント: {count}</h1>
<h1>高コストな計算結果: {expensiveCalculation}</h1>
<button onClick={() => setCount(count + 1)}>増やす</button>
<button onClick={() => setOtherCount(otherCount + 1)}>他のカウントを増やす</button>
</div>
);
}
上記では、count
が変わらない限りexpensiveCalculation
は再計算されません。このように、useMemo
を利用することで、特に高コストな処理を含むアプリケーションでのパフォーマンス向上が期待できます。
4. context
での値のリセット - resetContext
通常、ReactのContext API
を使ってデータをアプリ全体に渡すことができますが、コンテキストをリセットしたい場合、手動でリセットのコードを書く必要がありました。Reactの最新のアップデートで追加されたresetContext
を活用すると、シンプルにリセットできるようになります。
import React, { createContext, useContext, useState } from 'react';
const CounterContext = createContext();
const CounterProvider = ({ children }) => {
const [count, setCount] = useState(0);
const resetContext = () => {
setCount(0); // コンテキストの値をリセット
};
return (
<CounterContext.Provider value={{ count, setCount, resetContext }}>
{children}
</CounterContext.Provider>
);
};
const CounterDisplay = () => {
const { count, resetContext } = useContext(CounterContext);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={resetContext}>リセット</button>
</div>
);
};
function App() {
return (
<CounterProvider>
<CounterDisplay />
</CounterProvider>
);
}
export default App;
このコードでは、resetContext
関数によってコンテキスト内のcount
が0にリセットされます。これにより、コードの可読性が向上し、再利用性の高いコンテキストプロバイダを簡単に実装できます。