<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>useCallback</title>
	<atom:link href="https://techgrowup.net/tag/usecallback/feed/" rel="self" type="application/rss+xml" />
	<link>https://techgrowup.net</link>
	<description>エンジニアを強くする</description>
	<lastBuildDate>Wed, 30 Apr 2025 23:00:00 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1</generator>

<image>
	<url>https://techgrowup.net/wp-content/uploads/2021/05/hp-icon-150x150.png</url>
	<title>useCallback</title>
	<link>https://techgrowup.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>useMemo徹底ガイド──Reactアプリの再計算コストを劇的に減らす最適化テクニック</title>
		<link>https://techgrowup.net/react-usememo/</link>
					<comments>https://techgrowup.net/react-usememo/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[techgrowup]]></dc:creator>
		<pubDate>Wed, 30 Apr 2025 23:00:00 +0000</pubDate>
				<category><![CDATA[React]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[useCallback]]></category>
		<category><![CDATA[useMemo]]></category>
		<category><![CDATA[パフォーマンス]]></category>
		<category><![CDATA[メモ化]]></category>
		<category><![CDATA[依存配列]]></category>
		<category><![CDATA[再レンダー最適化]]></category>
		<guid isPermaLink="false">https://techgrowup.net/?p=2838</guid>

					<description><![CDATA[useMemoとは何か useMemo は指定した計算式をメモ化（キャッシュ）し、依存配列が変わらない限り再実行をスキップするReactフックです。たとえば数千件のリストを高コストなフィルタリングやソートで描画する場合、 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">useMemoとは何か</h2>



<p class="wp-block-paragraph"><code>useMemo</code> は指定した計算式をメモ化（キャッシュ）し、<strong>依存配列が変わらない限り再実行をスキップ</strong>するReactフックです。たとえば数千件のリストを高コストなフィルタリングやソートで描画する場合、入力が変わらなければ同じ結果を再計算するのはムダです。<code>useMemo</code> を使えば計算を一度だけ行い、次回レンダーではキャッシュ済みの値を返すため描画が高速化します。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import { useMemo } from 'react';

function ExpensiveList({ items, query }) {
  const filtered = useMemo(() =&gt; {
    return items.filter(item =&gt; item.name.includes(query));
  }, [items, query]); // itemsかqueryが変わったときだけ再計算

  return filtered.map(item =&gt; &lt;li key={item.id}&gt;{item.name}&lt;/li&gt;);
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">useMemo</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;react&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">ExpensiveList</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">items</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">query</span><span style="color: #D4D4D4"> }) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">filtered</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useMemo</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">items</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">filter</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">item</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">item</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">includes</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">query</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">  }, [</span><span style="color: #9CDCFE">items</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">query</span><span style="color: #D4D4D4">]); </span><span style="color: #6A9955">// itemsかqueryが変わったときだけ再計算</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">filtered</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">map</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">item</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">li</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">key</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">item</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">id</span><span style="color: #569CD6">}</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">item</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #569CD6">}</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">li</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h2 class="wp-block-heading">基本シグネチャ</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const memoizedValue = useMemo(() =&gt; compute(expensive), [deps]);" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">memoizedValue</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useMemo</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">compute</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">expensive</span><span style="color: #D4D4D4">), [</span><span style="color: #9CDCFE">deps</span><span style="color: #D4D4D4">]);</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>第1引数</strong>：メモ化したい関数（副作用を含まない純粋関数が望ましい）。</li>



<li><strong>第2引数</strong>：依存配列。ここに列挙した値が変わった場合のみ計算し直す。</li>
</ul>



<p class="wp-block-paragraph">依存配列を空配列 <code>[]</code> にするとマウント時に一回だけ実行。<code>undefined</code> を渡すと毎レンダー実行＝メモ化無効なので注意。</p>



<h2 class="wp-block-heading">useMemoが効く典型シナリオ</h2>



<h3 class="wp-block-heading">1. データ変換・重い計算</h3>



<ul class="wp-block-list">
<li>数学的シミュレーションの結果</li>



<li>JSONデータのディープコピーや正規化</li>



<li>Markdown → HTML 変換など CPUコストが高い処理</li>
</ul>



<h3 class="wp-block-heading">2. フィルタ・ソート・検索</h3>



<p class="wp-block-paragraph">リストの要素数が数百〜数千を超える場合、<code>Array.prototype.filter</code> や <code>sort</code> を毎レンダー走らせるとフレーム落ちの原因になります。</p>



<h3 class="wp-block-heading">3. JSX生成コスト削減</h3>



<p class="wp-block-paragraph">巨大リストを map で JSX に展開するとき、その戻り値をメモ化すると描画コストを下げられます（React 18の並列レンダーでも効果的）。</p>



<h2 class="wp-block-heading">useCallbackとの違い</h2>



<figure class="wp-block-table"><div class="scrollable-table"><table class="has-fixed-layout"><thead><tr><th>観点</th><th>useMemo</th><th>useCallback</th></tr></thead><tbody><tr><td>目的</td><td><strong>値</strong>をメモ化</td><td><strong>関数参照</strong>をメモ化</td></tr><tr><td>戻り値</td><td>計算結果そのもの</td><td>メモ化済みの関数</td></tr><tr><td>主要用途</td><td>高コストの計算結果を保持</td><td>子コンポーネントへ渡すハンドラの参照固定</td></tr></tbody></table></div></figure>



<p class="wp-block-paragraph">内部実装では <code>useCallback(fn, deps)</code> は <code>useMemo(() =&gt; fn, deps)</code> と同等です。しかし意味づけが異なるため、値なら <code>useMemo</code>、関数なら <code>useCallback</code> を使うと読みやすくなります。</p>



<h2 class="wp-block-heading">実践シナリオ別コード例</h2>



<h3 class="wp-block-heading">例1：検索フィルタリング</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="function SearchableTable({ rows }) {
  const [keyword, setKeyword] = useState('');
  const visibleRows = useMemo(() =&gt; {
    const lower = keyword.toLowerCase();
    return rows.filter(r =&gt; r.name.toLowerCase().includes(lower));
  }, [rows, keyword]);
  return (
    &lt;&gt;
      &lt;input value={keyword} onChange={e =&gt; setKeyword(e.target.value)} /&gt;
      &lt;ul&gt;{visibleRows.map(r =&gt; &lt;li key={r.id}&gt;{r.name}&lt;/li&gt;)}&lt;/ul&gt;
    &lt;/&gt;
  );
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">SearchableTable</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4"> }) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> [</span><span style="color: #4FC1FF">keyword</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">setKeyword</span><span style="color: #D4D4D4">] = </span><span style="color: #DCDCAA">useState</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">visibleRows</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useMemo</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">lower</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">keyword</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">toLowerCase</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">filter</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">r</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">r</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">toLowerCase</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">includes</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">lower</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">  }, [</span><span style="color: #9CDCFE">rows</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">keyword</span><span style="color: #D4D4D4">]);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #808080">&lt;&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">input</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">keyword</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">onChange</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">setKeyword</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">target</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4">)</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">ul</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">visibleRows</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">map</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">r</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">li</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">key</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">r</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">id</span><span style="color: #569CD6">}</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">r</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">name</span><span style="color: #569CD6">}</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">li</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">)</span><span style="color: #569CD6">}</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">ul</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #808080">&lt;/&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<ul class="wp-block-list">
<li>rows が巨大でも <code>keyword</code> が変わらなければ再計算なし</li>



<li>入力ごとにフィルタされても実用レベルのパフォーマンス</li>
</ul>



<h3 class="wp-block-heading">例2：高コスト画像処理</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="function Preview({ file }) {
  const thumbnail = useMemo(() =&gt; {
    return file ? createThumbnail(file) : null; // Canvas処理など重い関数
  }, [file]);
  return thumbnail ? &lt;img src={thumbnail} /&gt; : null;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Preview</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">file</span><span style="color: #D4D4D4"> }) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">thumbnail</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useMemo</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">file</span><span style="color: #D4D4D4"> ? </span><span style="color: #DCDCAA">createThumbnail</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">file</span><span style="color: #D4D4D4">) : </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">; </span><span style="color: #6A9955">// Canvas処理など重い関数</span></span>
<span class="line"><span style="color: #D4D4D4">  }, [</span><span style="color: #9CDCFE">file</span><span style="color: #D4D4D4">]);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">thumbnail</span><span style="color: #D4D4D4"> ? </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">img</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">src</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">thumbnail</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span><span style="color: #D4D4D4"> : </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h3 class="wp-block-heading">例3：ソート済みキャッシュ</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const sorted = useMemo(
  () =&gt; [...items].sort((a, b) =&gt; a.date - b.date),
  [items]
);" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">sorted</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useMemo</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">  () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> [...</span><span style="color: #9CDCFE">items</span><span style="color: #D4D4D4">].</span><span style="color: #DCDCAA">sort</span><span style="color: #D4D4D4">((</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">b</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4"> - </span><span style="color: #9CDCFE">b</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">date</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">  [</span><span style="color: #9CDCFE">items</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">);</span></span></code></pre></div>



<p class="wp-block-paragraph">イミュータブルデータならシャローコピーしてソートし、<code>items</code> が同一参照の間は再計算されません。</p>



<h2 class="wp-block-heading">依存配列設計のコツ</h2>



<ol class="wp-block-list">
<li><strong>リストやオブジェクトは参照が変わる条件を把握</strong>
<ul class="wp-block-list">
<li>Redux/Context でステートが再生成されると参照が毎回変わる ⇒ 先に<code>useSelector(shallowEqual)</code>などで固定化</li>
</ul>
</li>



<li><strong>不要な依存を追加しない</strong>
<ul class="wp-block-list">
<li>計算結果に影響しない値を含めると再実行が増える</li>
</ul>
</li>



<li><strong>入れ忘れはバグの温床</strong>
<ul class="wp-block-list">
<li>ESLintの<code>react-hooks/exhaustive-deps</code>ルールを有効化し、自動検出する</li>
</ul>
</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="// NG: setState関数は安定参照のため依存不要
useMemo(() =&gt; compute(state, setState), [state, setState]); 
// OK
useMemo(() =&gt; compute(state), [state]);" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// NG: setState関数は安定参照のため依存不要</span></span>
<span class="line"><span style="color: #DCDCAA">useMemo</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">compute</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">setState</span><span style="color: #D4D4D4">), [</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">setState</span><span style="color: #D4D4D4">]); </span></span>
<span class="line"><span style="color: #6A9955">// OK</span></span>
<span class="line"><span style="color: #DCDCAA">useMemo</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">compute</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">), [</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">]);</span></span></code></pre></div>



<h2 class="wp-block-heading">パフォーマンス測定と検証</h2>



<h3 class="wp-block-heading">Profiler API</h3>



<ol class="wp-block-list">
<li>React DevTools を開き「Profiler」タブを選択</li>



<li>録画して操作 ⇒ 再計算が走る場所を特定</li>



<li><code>useMemo</code>導入後にレンダー時間が短縮されているか確認</li>
</ol>



<h3 class="wp-block-heading">console.time計測</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const result = useMemo(() =&gt; {
  console.time('expensive');
  const v = heavy();
  console.timeEnd('expensive');
  return v;
}, [deps]);" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">result</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useMemo</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">time</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;expensive&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">v</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">heavy</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">timeEnd</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;expensive&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">v</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}, [</span><span style="color: #9CDCFE">deps</span><span style="color: #D4D4D4">]);</span></span></code></pre></div>



<p class="wp-block-paragraph">メモ化の前後で時間を比較し、効果を数字で把握します。</p>



<h2 class="wp-block-heading">よくある落とし穴</h2>



<figure class="wp-block-table"><div class="scrollable-table"><table class="has-fixed-layout"><thead><tr><th>症状</th><th>原因</th><th>対策</th></tr></thead><tbody><tr><td>メモ化しているのに速くならない</td><td>計算自体が軽い／依存が毎回変わる</td><td>メモ化を外す or 依存を安定化</td></tr><tr><td>stale data（古い値を参照）</td><td>依存配列に必要な変数がない</td><td>ESLintルールで検出＋修正</td></tr><tr><td>メモリリーク</td><td>大きな配列・Mapをキャッシュして解放しない</td><td>必要に応じて <code>useMemo</code> を解除</td></tr></tbody></table></div></figure>



<h2 class="wp-block-heading">useMemoを使わない方がいい場合</h2>



<ul class="wp-block-list">
<li><strong>計算コスト &lt; メモ化管理コスト</strong></li>



<li><strong>UIがほぼ静的</strong>：再レンダー回数が少ない</li>



<li><strong>依存が頻繁に変わる</strong>：キャッシュがほぼ活きない</li>
</ul>



<p class="wp-block-paragraph">最適化は「必要になったら測定して導入」が鉄則です。</p>



<h2 class="wp-block-heading"><code>useMemo</code> と Suspense / Concurrent Features</h2>



<p class="wp-block-paragraph">React 18 の並列レンダーでは、<code>useMemo</code>のキャッシュが中断と再開をまたいで保持されるため、長い計算でもUIスレッドをブロックしにくくなっています。<strong>ただしメモ化対象関数は同期的に実行</strong>されるため、CPU負荷の高い処理はWeb Workerや<code>useTransition</code>と組み合わせるとさらに快適です。</p>



<h2 class="wp-block-heading">まとめ</h2>



<p class="wp-block-paragraph"><code>useMemo</code> は</p>



<ol class="wp-block-list">
<li><strong>高コスト計算の結果をキャッシュ</strong>し</li>



<li><strong>依存配列が変わるまで再利用</strong>し</li>



<li><strong>不要な再レンダーを抑制</strong></li>
</ol>



<p class="wp-block-paragraph">というシンプルながら強力な最適化手段です。ただし「とりあえず入れる」は逆効果。まずはプロファイリングでボトルネックを特定し、効果が見込める箇所にのみ導入するのがベストプラクティスです。正しい依存配列と計算粒度を意識し、快適なReact UIを届けましょう。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://techgrowup.net/react-usememo/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ReactのuseCallback徹底ガイド──依存配列・再レンダリング制御・パフォーマンス最適化の基本と応用</title>
		<link>https://techgrowup.net/react-usecallback/</link>
					<comments>https://techgrowup.net/react-usecallback/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[techgrowup]]></dc:creator>
		<pubDate>Sun, 27 Apr 2025 23:00:00 +0000</pubDate>
				<category><![CDATA[React]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Hooks]]></category>
		<category><![CDATA[useCallback]]></category>
		<category><![CDATA[パフォーマンス]]></category>
		<category><![CDATA[依存配列]]></category>
		<category><![CDATA[再レンダリング]]></category>
		<category><![CDATA[再利用]]></category>
		<category><![CDATA[最適化]]></category>
		<guid isPermaLink="false">https://techgrowup.net/?p=2827</guid>

					<description><![CDATA[はじめに Reactの関数コンポーネントで副作用や再レンダリング制御を扱う際、useCallback フックはしばしば「面倒くさい」「よくわからない」と敬遠されがちです。しかし、大規模アプリのパフォーマンスチューニングや [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">はじめに</h1>



<p class="wp-block-paragraph">Reactの関数コンポーネントで副作用や再レンダリング制御を扱う際、<code>useCallback</code> フックはしばしば「面倒くさい」「よくわからない」と敬遠されがちです。しかし、大規模アプリのパフォーマンスチューニングや、子コンポーネントへのコールバック関数渡しを正しく行うためには不可欠な存在です。本記事では基礎から依存配列の書き方、内部動作、注意点、具体的な活用シーンまでを解説します。</p>



<h2 class="wp-block-heading">useCallbackとは？</h2>



<p class="wp-block-paragraph"><code>useCallback</code> は「関数をメモ化（キャッシュ）する」ための React フックです。コンポーネントが再レンダーされるたびに新しい関数インスタンスを生成すると、子コンポーネントに渡したコールバックが”変化”とみなされ、不要な再レンダーにつながります。これを防ぐのが <code>useCallback</code> です。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const memoizedHandler = useCallback(() =&gt; {
  console.log('クリックされました');
}, [依存値1, 依存値2]);" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">memoizedHandler</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useCallback</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">log</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;クリックされました&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}, [</span><span style="color: #9CDCFE">依存値1</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">依存値2</span><span style="color: #D4D4D4">]);</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>第1引数</strong>：メモ化したい関数</li>



<li><strong>第2引数</strong>：依存配列。ここに入れた値が変わると新しく関数を作り直す</li>
</ul>



<h2 class="wp-block-heading">基本シグネチャと戻り値</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="function useCallback&lt;T extends (...args: any[]) =&gt; any&gt;(
  callback: T,
  deps: DependencyList
): T;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">useCallback</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">T</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> (...</span><span style="color: #9CDCFE">args</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">any</span><span style="color: #D4D4D4">[]) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">any</span><span style="color: #D4D4D4">&gt;(</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">callback</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">T</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">deps</span><span style="color: #D4D4D4">: </span><span style="color: #4EC9B0">DependencyList</span></span>
<span class="line"><span style="color: #D4D4D4">): </span><span style="color: #4EC9B0">T</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>T</strong>：任意の関数型</li>



<li><strong>DependencyList</strong>：<code>any[]</code> 型の配列</li>



<li><strong>戻り値</strong>：渡した <code>callback</code> と同じ型の“メモ化された関数”</li>
</ul>



<p class="wp-block-paragraph">内部では React が Hook ごとに前回の <code>callback</code> 参照を保持し、<code>deps</code> が完全一致する限り同じ関数を返します。</p>



<h2 class="wp-block-heading">依存配列の正しい書き方</h2>



<p class="wp-block-paragraph">依存配列を適切に指定しないと、次のような問題が起きます。</p>



<figure class="wp-block-table"><div class="scrollable-table"><table class="has-fixed-layout"><thead><tr><th>誤り</th><th>症状</th></tr></thead><tbody><tr><td>依存配列を空にする (<code>[]</code>)</td><td>最新の外部変数を参照できない （stale closure）</td></tr><tr><td>依存を省略 (<code>undefined</code>)</td><td>毎回新しい関数が作られ、効果なし</td></tr><tr><td>必要な依存を含めない</td><td>古い値を使い続ける</td></tr></tbody></table></div></figure>



<p class="wp-block-paragraph"><strong>例：カウントを依存に含めないと古い値を参照する</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="function Counter() {
  const [count, setCount] = useState(0);

  const handler = useCallback(() =&gt; {
    console.log(count); // 依存にcountを含めないと常に0が表示
  }, []); 

  return &lt;button onClick={handler}&gt;ログ出力&lt;/button&gt;;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Counter</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> [</span><span style="color: #4FC1FF">count</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">setCount</span><span style="color: #D4D4D4">] = </span><span style="color: #DCDCAA">useState</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">handler</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useCallback</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">log</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">count</span><span style="color: #D4D4D4">); </span><span style="color: #6A9955">// 依存にcountを含めないと常に0が表示</span></span>
<span class="line"><span style="color: #D4D4D4">  }, []); </span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">button</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">onClick</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">handler</span><span style="color: #569CD6">}</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">ログ出力</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">button</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">上記では <code>count</code> が変わっても <code>handler</code> 内の <code>count</code> は初回のまま。依存配列には常に<strong>最新のcount</strong>を正しく指定しましょう。</p>



<h2 class="wp-block-heading">useCallbackとuseMemoの違い</h2>



<ul class="wp-block-list">
<li><strong>useCallback</strong>：関数をメモ化する</li>



<li><strong>useMemo</strong>：関数の戻り値（任意の値）をメモ化する</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const memoizedValue = useMemo(() =&gt; computeExpensive(a, b), [a, b]);
const memoizedHandler = useCallback(() =&gt; doSomething(a, b), [a, b]);" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">memoizedValue</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useMemo</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">computeExpensive</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">b</span><span style="color: #D4D4D4">), [</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">b</span><span style="color: #D4D4D4">]);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">memoizedHandler</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useCallback</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">doSomething</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">b</span><span style="color: #D4D4D4">), [</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">b</span><span style="color: #D4D4D4">]);</span></span></code></pre></div>



<p class="wp-block-paragraph"><code>useCallback(fn, deps)</code> は <code>useMemo(() =&gt; fn, deps)</code> のエイリアスと考えることもできますが、可読性の観点から関数キャッシュには <code>useCallback</code> を使うのが一般的です。</p>



<ol class="wp-block-list">
<li>コンポーネント初回レンダー</li>



<li><code>useCallback</code> が新しい関数を生成し返却</li>



<li>次回レンダー
<ul class="wp-block-list">
<li><code>deps</code> が同じ → 前回の関数を再利用</li>



<li><code>deps</code> が変わった → 新しい関数を生成</li>
</ul>
</li>



<li>子コンポーネントへ渡す際、関数参照の変化を検出してレンダー制御できる</li>
</ol>



<p class="wp-block-paragraph">この仕組みを利用し、<code>React.memo</code> と組み合わせることで子コンポーネントの再レンダーを抑制できます。</p>



<h2 class="wp-block-heading">子コンポーネントの最適化例</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const Child = React.memo(({ onAction }) =&gt; {
  console.log('Child render');
  return &lt;button onClick={onAction}&gt;アクション&lt;/button&gt;;
});

function Parent() {
  const [count, setCount] = useState(0);

  const handleAction = useCallback(() =&gt; {
    console.log('Action!');
  }, []); // 依存なし → 再レンダー時も同じ参照

  return (
    &lt;&gt;
      &lt;p&gt;Count: {count}&lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(c =&gt; c + 1)}&gt;増やす&lt;/button&gt;
      &lt;Child onAction={handleAction} /&gt;
    &lt;/&gt;
  );
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">Child</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">React</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">memo</span><span style="color: #D4D4D4">(({ </span><span style="color: #9CDCFE">onAction</span><span style="color: #D4D4D4"> }) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">log</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Child render&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">button</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">onClick</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">onAction</span><span style="color: #569CD6">}</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">アクション</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">button</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Parent</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> [</span><span style="color: #4FC1FF">count</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">setCount</span><span style="color: #D4D4D4">] = </span><span style="color: #DCDCAA">useState</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">handleAction</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useCallback</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">log</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Action!&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  }, []); </span><span style="color: #6A9955">// 依存なし → 再レンダー時も同じ参照</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #808080">&lt;&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">p</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">Count: </span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">count</span><span style="color: #569CD6">}</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">p</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">button</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">onClick</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #D4D4D4">() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">setCount</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">c</span><span style="color: #D4D4D4"> + </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">)</span><span style="color: #569CD6">}</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">増やす</span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">button</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #808080">&lt;</span><span style="color: #4EC9B0">Child</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">onAction</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">handleAction</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #808080">&lt;/&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<ul class="wp-block-list">
<li><code>Parent</code> が再レンダーされても <code>handleAction</code> は同じ参照</li>



<li><code>Child</code> は Props が変わらないとレンダーされないため高速</li>
</ul>



<h2 class="wp-block-heading">使わないほうがいいケース</h2>



<ul class="wp-block-list">
<li><strong>軽量コンポーネント／関数</strong><br>関数の生成コストよりReactのレンダーコストのほうが低い場合</li>



<li><strong>短命な値</strong><br>毎回異なる依存配列を生成すると逆効果</li>



<li><strong>過度のメモ化</strong><br>コードが複雑になり可読性や保守性が低下</li>
</ul>



<p class="wp-block-paragraph"><strong>判断基準</strong>：<br>パフォーマンス問題が「本当に関数参照の変化」に起因しているかプロファイラで確認しましょう。</p>



<h2 class="wp-block-heading">複数フックとの連携パターン</h2>



<h3 class="wp-block-heading">useCallback + useEffect</h3>



<p class="wp-block-paragraph">エフェクト内で関数を参照する場合、依存配列に含めないと stale closure が起きます。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="function Search({ query }) {
  const [results, setResults] = useState([]);
  const fetchResults = useCallback(async () =&gt; {
    const res = await fetch(`/api?q=${query}`);
    setResults(await res.json());
  }, [query]);

  useEffect(() =&gt; {
    fetchResults();
  }, [fetchResults]); // fetchResults を正しく依存に含める

  return /* 結果表示 */;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Search</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">query</span><span style="color: #D4D4D4"> }) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> [</span><span style="color: #4FC1FF">results</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">setResults</span><span style="color: #D4D4D4">] = </span><span style="color: #DCDCAA">useState</span><span style="color: #D4D4D4">([]);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">fetchResults</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useCallback</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">res</span><span style="color: #D4D4D4"> = </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">fetch</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`/api?q=</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">query</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">setResults</span><span style="color: #D4D4D4">(</span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">res</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">json</span><span style="color: #D4D4D4">());</span></span>
<span class="line"><span style="color: #D4D4D4">  }, [</span><span style="color: #9CDCFE">query</span><span style="color: #D4D4D4">]);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">useEffect</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">fetchResults</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">  }, [</span><span style="color: #9CDCFE">fetchResults</span><span style="color: #D4D4D4">]); </span><span style="color: #6A9955">// fetchResults を正しく依存に含める</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #6A9955">/* 結果表示 */</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h3 class="wp-block-heading">useCallback + useMemo</h3>



<p class="wp-block-paragraph">関数による計算結果をさらにメモ化したい場合</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const expensiveCompute = useCallback((x) =&gt; heavyCalc(x), []);
const memoizedResult = useMemo(() =&gt; expensiveCompute(input), [input, expensiveCompute]);" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">expensiveCompute</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useCallback</span><span style="color: #D4D4D4">((</span><span style="color: #9CDCFE">x</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">heavyCalc</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">x</span><span style="color: #D4D4D4">), []);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">memoizedResult</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useMemo</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">expensiveCompute</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">input</span><span style="color: #D4D4D4">), [</span><span style="color: #9CDCFE">input</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">expensiveCompute</span><span style="color: #D4D4D4">]);</span></span></code></pre></div>



<p class="wp-block-paragraph"><code>useCallback</code> でメモ化された関数をテストする際は、<code>renderHook</code> と <code>act</code> を使うと楽です。</p>



<h2 class="wp-block-heading">コールバック関数のテスト</h2>



<p class="wp-block-paragraph"><code>useCallback</code> でメモ化された関数をテストする際は、<code>renderHook</code> と <code>act</code> を使うと楽です。</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import { renderHook, act } from '@testing-library/react-hooks';

test('fetchResults が更新時に変化する', async () =&gt; {
  const { result, rerender } = renderHook(
    ({ query }) =&gt; useCallback(/*…*/, [query]),
    { initialProps: { query: 'a' } }
  );
  const first = result.current;
  rerender({ query: 'b' });
  expect(result.current).not.toBe(first);
});" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">renderHook</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">act</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;@testing-library/react-hooks&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">test</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;fetchResults が更新時に変化する&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> { </span><span style="color: #4FC1FF">result</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">rerender</span><span style="color: #D4D4D4"> } = </span><span style="color: #DCDCAA">renderHook</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">    ({ </span><span style="color: #9CDCFE">query</span><span style="color: #D4D4D4"> }) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">useCallback</span><span style="color: #D4D4D4">(</span><span style="color: #6A9955">/*…*/</span><span style="color: #D4D4D4">, [</span><span style="color: #9CDCFE">query</span><span style="color: #D4D4D4">]),</span></span>
<span class="line"><span style="color: #D4D4D4">    { </span><span style="color: #9CDCFE">initialProps:</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">query:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;a&#39;</span><span style="color: #D4D4D4"> } }</span></span>
<span class="line"><span style="color: #D4D4D4">  );</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">first</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">result</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">current</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">rerender</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">query:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;b&#39;</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">expect</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">result</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">current</span><span style="color: #D4D4D4">).</span><span style="color: #9CDCFE">not</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">toBe</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">first</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span></code></pre></div>



<h2 class="wp-block-heading">パフォーマンス計測とベンチマーク</h2>



<ul class="wp-block-list">
<li><strong>Profiler API</strong> で実際のレンダー回数を計測</li>



<li><strong>React DevTools</strong> のProfilerタブでコールバック関数生成の影響を見る</li>



<li><code>useCallback</code> 無し / 有りでどれだけ再レンダーが減るかを数値で比較</li>
</ul>



<h2 class="wp-block-heading">よくある誤解とQ&amp;A</h2>



<ol class="wp-block-list">
<li><strong>「depsが空なら一度だけ実行される」</strong><br>→ <code>useCallback</code> では「関数参照が一度だけ生成される」。 <code>useEffect([], …)</code> とは別。</li>



<li><strong>「関数を渡すだけで最適化される」</strong><br>→ 子コンポーネントも <code>React.memo</code> などで参照比較しなければ効果なし。</li>



<li><strong>「常に使えば良い」</strong><br>→ 過度のメモ化は逆効果。必要な箇所だけに絞りましょう。</li>
</ol>



<h2 class="wp-block-heading">まとめ</h2>



<p class="wp-block-paragraph"><code>useCallback</code> は関数インスタンスの再生成を防ぎ、再レンダーを制御する強力なフックです。依存配列の正確な管理、<code>React.memo</code> との併用、過度なメモ化の回避などポイントを押さえれば、アプリ全体のパフォーマンスが向上します。まずはパフォーマンスプロファイリングを行い、本当に必要な箇所だけに導入してみてください。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://techgrowup.net/react-usecallback/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
