<?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>Provider</title>
	<atom:link href="https://techgrowup.net/tag/provider/feed/" rel="self" type="application/rss+xml" />
	<link>https://techgrowup.net</link>
	<description>エンジニアを強くする</description>
	<lastBuildDate>Thu, 01 May 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>Provider</title>
	<link>https://techgrowup.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>useContext超大全──React Context APIでグローバル状態をスマートに共有する</title>
		<link>https://techgrowup.net/react-usecontext/</link>
					<comments>https://techgrowup.net/react-usecontext/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[techgrowup]]></dc:creator>
		<pubDate>Thu, 01 May 2025 23:00:00 +0000</pubDate>
				<category><![CDATA[React]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Context API]]></category>
		<category><![CDATA[propsドリリング]]></category>
		<category><![CDATA[Provider]]></category>
		<category><![CDATA[useContext]]></category>
		<category><![CDATA[グローバルステート]]></category>
		<guid isPermaLink="false">https://techgrowup.net/?p=2841</guid>

					<description><![CDATA[はじめに React アプリが成長するにつれて、コンポーネント間で共通の値を渡す「props ドリリング」が増え、保守性が下がる課題に直面します。Context API と useContext フックは、この問題を標準 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">はじめに</h1>



<p class="wp-block-paragraph">React アプリが成長するにつれて、コンポーネント間で共通の値を渡す「props ドリリング」が増え、保守性が下がる課題に直面します。Context API と <code>useContext</code> フックは、この問題を標準機能だけで解決できる強力な仕組みです。本連載記事では公式ドキュメント <a rel="noopener" target="_blank" class="" href="https://react.dev/reference/react/useContext">https://react.dev/reference/react/useContext<span class="fa fa-external-link external-icon anchor-icon"></span></a> をベースに、<strong>基礎・設計・最適化・型安全・周辺ライブラリ</strong> まで 2 万文字超で徹底的に解説します。第一部では基本概念と最低限動くコード、スコープ設計、props ドリリングの解消フローをじっくり掘り下げます。</p>



<h2 class="wp-block-heading">Context API の全体像</h2>



<ul class="wp-block-list">
<li><code>React.createContext</code> で「箱」を作成</li>



<li><strong>Provider</strong> が値を注入</li>



<li><strong>useContext</strong> で最寄りの Provider から値を取得</li>



<li>Provider をネストすれば “局所グローバル” を作れる</li>
</ul>



<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="&lt;Context.Provider value={A}&gt;
  └─ &lt;ChildA /&gt;  ← useContext ⇒ A
      └─ &lt;Context.Provider value={B}&gt;
            └─ &lt;ChildB /&gt;  ← useContext ⇒ 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: #808080">&lt;</span><span style="color: #4EC9B0">Context.Provider</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: #4FC1FF">A</span><span style="color: #569CD6">}</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">ChildA</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span><span style="color: #D4D4D4">  ← useContext ⇒ A</span></span>
<span class="line"><span style="color: #D4D4D4">      └─ </span><span style="color: #808080">&lt;</span><span style="color: #4EC9B0">Context.Provider</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: #4FC1FF">B</span><span style="color: #569CD6">}</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">ChildB</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span><span style="color: #D4D4D4">  ← useContext ⇒ B</span></span></code></pre></div>



<p class="wp-block-paragraph">外側と内側で値が上書きされるため、テーマやロケールなど「場面に応じて変わる設定」を自然に切り替えられます。</p>



<h2 class="wp-block-heading">props ドリリング問題とContextの必要性</h2>



<h3 class="wp-block-heading">propsドリリングとは？</h3>



<p class="wp-block-paragraph">親→子→孫→ひ孫…と同じPropsをリレーして渡す状態。深いツリーでは可読性が悪化し、途中の中間コンポーネントが無関係のPropsを抱える。</p>



<h3 class="wp-block-heading">Contextで解決</h3>



<p class="wp-block-paragraph">Providerをルート付近に置き、任意の深さで直接<code>useContext</code>。不要な中継Propsが消え、各コンポーネントが必要な値だけを購読できます。</p>



<h3 class="wp-block-heading">具体例</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 App() {
  const user = { id: 1, name: 'Taro' };
  return &lt;Page user={user} /&gt;;
}
function Page({ user }) {             /* ← 中継だけ */
  return &lt;Sidebar user={user} /&gt;;
}
function Sidebar({ user }) {          /* ← 中継だけ */
  return &lt;UserProfile user={user} /&gt;;
}
function UserProfile({ user }) {
  return &lt;p&gt;{user.name}&lt;/p&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">App</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">user</span><span style="color: #D4D4D4"> = { </span><span style="color: #9CDCFE">id:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">name:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;Taro&#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: #4EC9B0">Page</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">user</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">user</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </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 style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Page</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">user</span><span style="color: #D4D4D4"> }) {             </span><span style="color: #6A9955">/* ← 中継だけ */</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: #4EC9B0">Sidebar</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">user</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">user</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </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 style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Sidebar</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">user</span><span style="color: #D4D4D4"> }) {          </span><span style="color: #6A9955">/* ← 中継だけ */</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: #4EC9B0">UserProfile</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">user</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">user</span><span style="color: #569CD6">}</span><span style="color: #D4D4D4"> </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 style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">UserProfile</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">user</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">p</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">user</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">p</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">;          </span><span style="color: #6A9955">/* ← 本当に必要なのはここだけ */</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Context を導入すると、中継 Props をすべて削除し、下記のようにシンプル化できます。</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 UserContext = createContext(null);
function App() {
  const user = { id: 1, name: 'Taro' };
  return (
    &lt;UserContext.Provider value={user}&gt;
      &lt;Page /&gt;
    &lt;/UserContext.Provider&gt;
  );
}
function UserProfile() {
  const user = useContext(UserContext);
  return &lt;p&gt;{user.name}&lt;/p&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">UserContext</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">createContext</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">App</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">user</span><span style="color: #D4D4D4"> = { </span><span style="color: #9CDCFE">id:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">name:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;Taro&#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>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #808080">&lt;</span><span style="color: #4EC9B0">UserContext.Provider</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">user</span><span style="color: #569CD6">}</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">Page</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: #4EC9B0">UserContext.Provider</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">UserProfile</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">user</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useContext</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">UserContext</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">p</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">user</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">p</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">Context の作成と Provider 実装</h2>



<h3 class="wp-block-heading">createContext の引数</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 ThemeContext = React.createContext('light'); // デフォルト値" 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">ThemeContext</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">React</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">createContext</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;light&#39;</span><span style="color: #D4D4D4">); </span><span style="color: #6A9955">// デフォルト値</span></span></code></pre></div>



<p class="wp-block-paragraph">1 引数めは <strong>フォールバック値</strong>。Provider がツリーになかった場合に限り返されるため、開発中の警告用や Storybook のダミー値として活用できます。</p>



<h3 class="wp-block-heading">Provider に渡す value</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="&lt;ThemeContext.Provider value=&quot;dark&quot;&gt;
  &lt;Toolbar /&gt;
&lt;/ThemeContext.Provider&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: #808080">&lt;</span><span style="color: #4EC9B0">ThemeContext.Provider</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;dark&quot;</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">Toolbar</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span></span>
<span class="line"><span style="color: #808080">&lt;/</span><span style="color: #4EC9B0">ThemeContext.Provider</span><span style="color: #808080">&gt;</span></span></code></pre></div>



<p class="wp-block-paragraph">ポイント</p>



<ul class="wp-block-list">
<li>Provider が再レンダーされると <strong>value の参照比較</strong>で下位ツリー全部が再レンダー</li>



<li><code>value</code> がオブジェクトなら <code>useMemo</code> で安定化必須</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 memoValue = useMemo(() =&gt; ({ theme, toggle }), [theme]);" 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">memoValue</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: #9CDCFE">theme</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">toggle</span><span style="color: #D4D4D4"> }), [</span><span style="color: #9CDCFE">theme</span><span style="color: #D4D4D4">]);</span></span></code></pre></div>



<h2 class="wp-block-heading">useContext の基本挙動</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 value = useContext(ThemeContext);" 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">value</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useContext</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ThemeContext</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>最も近い Provider</strong> の value を返す</li>



<li>Provider が見つからない場合は createContext 時のデフォルト値</li>



<li>複数回呼んでも React がキャッシュするためコストは低い</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>注意</strong>: <code>useContext</code> は必ず React のレンダーフェーズ内で呼ぶ。コールバックや条件分岐で早期 return する位置に入れるとルール違反。</p>
</blockquote>



<h2 class="wp-block-heading">スコープ設計：いつ Provider を分割すべきか</h2>



<figure class="wp-block-table"><div class="scrollable-table"><table class="has-fixed-layout"><thead><tr><th>ケース</th><th>1 Provider</th><th>複数 Provider</th></tr></thead><tbody><tr><td>テーマ、ロケールなど不変に近い設定</td><td>◯</td><td>△</td></tr><tr><td>頻繁に変わる値（カーソル座標等）</td><td>△</td><td>◯</td></tr><tr><td>複数ドメインデータ（Auth と Cart）</td><td>△</td><td>◯</td></tr></tbody></table></div></figure>



<p class="wp-block-paragraph">複数の値が同時に更新されるわけではない場合、それぞれ独立した Provider に分けることで再レンダー範囲を局所化できます。</p>



<h2 class="wp-block-heading">サンプル：Todo アプリでの Context 分離</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="const SettingsContext = createContext({
  showCompleted: true,
  toggleShow: () =&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">SettingsContext</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">createContext</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">showCompleted:</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">toggleShow</span><span style="color: #9CDCFE">:</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></code></pre></div>



<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="const AuthContext = createContext({
  user: null,
  login: () =&gt; {},
  logout: () =&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">AuthContext</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">createContext</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">user:</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 style="color: #DCDCAA">login</span><span style="color: #9CDCFE">:</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">logout</span><span style="color: #9CDCFE">:</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></code></pre></div>



<h3 class="wp-block-heading">3. Todo リスト</h3>



<p class="wp-block-paragraph">todo はサイズが大きく頻繁に変わるため、<strong>Context より useReducer + Context</strong> の複合パターンが適切です（第二部で詳細解説）。</p>



<h2 class="wp-block-heading">パフォーマンス最適化と再レンダー制御</h2>



<p class="wp-block-paragraph">Context API は便利ですが、<strong>Provider の <code>value</code> が変わるたびに配下すべての <code>useContext</code> 呼び出しが再レンダー</strong> されます。大規模ツリーでは深刻なパフォーマンス低下につながるため、次の 4 つの対策を組み合わせましょう。</p>



<h3 class="wp-block-heading">1. <code>useMemo</code> で value オブジェクトを安定化</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 SettingsProvider = ({ children }) =&gt; {
  const [showCompleted, setShowCompleted] = useState(true);
  const ctx = useMemo(
    () =&gt; ({ showCompleted, toggle: () =&gt; setShowCompleted(v =&gt; !v) }),
    [showCompleted]    // プリミティブのみ依存
  );
  return &lt;SettingsContext.Provider value={ctx}&gt;{children}&lt;/SettingsContext.Provider&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: #DCDCAA">SettingsProvider</span><span style="color: #D4D4D4"> = ({ </span><span style="color: #9CDCFE">children</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">showCompleted</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">setShowCompleted</span><span style="color: #D4D4D4">] = </span><span style="color: #DCDCAA">useState</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">true</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">ctx</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">showCompleted</span><span style="color: #D4D4D4">, </span><span style="color: #DCDCAA">toggle</span><span style="color: #9CDCFE">:</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">setShowCompleted</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">v</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</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">showCompleted</span><span style="color: #D4D4D4">]    </span><span style="color: #6A9955">// プリミティブのみ依存</span></span>
<span class="line"><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: #4EC9B0">SettingsContext.Provider</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">ctx</span><span style="color: #569CD6">}</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">children</span><span style="color: #569CD6">}</span><span style="color: #808080">&lt;/</span><span style="color: #4EC9B0">SettingsContext.Provider</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">オブジェクト内の参照が変わらなければ再レンダーは下位に波及しません。</p>



<h3 class="wp-block-heading">2. Context を分割する</h3>



<p class="wp-block-paragraph"><strong>更新頻度</strong> が異なる値を 1 つの Provider に詰め込むと、滅多に変わらない設定が毎回レンダーのトリガーになります。</p>



<ul class="wp-block-list">
<li><code>AuthContext</code> と <code>ThemeContext</code> を個別 Provider にする</li>



<li>パフォーマンスクリティカルな配列や Map は専用 Context へ切り出す</li>
</ul>



<h3 class="wp-block-heading">3. Context Selector パターン</h3>



<p class="wp-block-paragraph">ライブラリ <code>use-context-selector</code> を使うと、<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="import { createContext, useContextSelector } from 'use-context-selector';

const CountContext = createContext({ count: 0, inc: () =&gt; {} });

function CounterLabel() {
  const count = useContextSelector(CountContext, v =&gt; v.count);
  return &lt;span&gt;{count}&lt;/span&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">createContext</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">useContextSelector</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;use-context-selector&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">CountContext</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">createContext</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">count:</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">, </span><span style="color: #DCDCAA">inc</span><span style="color: #9CDCFE">:</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</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">CounterLabel</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: #DCDCAA">useContextSelector</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">CountContext</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">v</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">v</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">count</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">span</span><span style="color: #808080">&gt;</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">span</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">Provider の値がオブジェクト再生成されても <code>count</code> が変わらない限り <code>CounterLabel</code> は再レンダーされません。</p>



<h3 class="wp-block-heading">4. <code>memo</code> + <code>useContext</code> は要注意</h3>



<p class="wp-block-paragraph"><code>React.memo</code> でラップしても、Context 更新は強制的に渡ってくるため <strong>再レンダー抑止はできません</strong>。必要に応じ「コンテナ–プレゼンテーション分割」を行い、Context を読む部分をコンテナ、表示だけ行う部分を <code>memo</code> 化すると効果的です。</p>



<h2 class="wp-block-heading">useReducer と Context を組み合わせたグローバルストア</h2>



<p class="wp-block-paragraph">小規模アプリなら Redux などを導入せずに、<strong><code>useReducer</code> + Context</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="const TodoContext = createContext(null);

function todoReducer(state, action) {
  switch (action.type) {
    case 'add':
      return [...state, action.payload];
    case 'toggle':
      return state.map(t =&gt;
        t.id === action.id ? { ...t, done: !t.done } : t
      );
    default:
      return state;
  }
}

export function TodoProvider({ children }) {
  const [todos, dispatch] = useReducer(todoReducer, []);
  const ctx = useMemo(() =&gt; ({ todos, dispatch }), [todos]);
  return &lt;TodoContext.Provider value={ctx}&gt;{children}&lt;/TodoContext.Provider&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">TodoContext</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">createContext</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">null</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">todoReducer</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">state</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">action</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">switch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">action</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">type</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">case</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;add&#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">state</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">action</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">payload</span><span style="color: #D4D4D4">];</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">case</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;toggle&#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">state</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">map</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">=&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">id</span><span style="color: #D4D4D4"> === </span><span style="color: #9CDCFE">action</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">id</span><span style="color: #D4D4D4"> ? { ...</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">done:</span><span style="color: #D4D4D4"> !</span><span style="color: #9CDCFE">t</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">done</span><span style="color: #D4D4D4"> } : </span><span style="color: #9CDCFE">t</span></span>
<span class="line"><span style="color: #D4D4D4">      );</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">default</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">state</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>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">TodoProvider</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">children</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">todos</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">dispatch</span><span style="color: #D4D4D4">] = </span><span style="color: #DCDCAA">useReducer</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">todoReducer</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">ctx</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: #9CDCFE">todos</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">dispatch</span><span style="color: #D4D4D4"> }), [</span><span style="color: #9CDCFE">todos</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: #4EC9B0">TodoContext.Provider</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">ctx</span><span style="color: #569CD6">}</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">children</span><span style="color: #569CD6">}</span><span style="color: #808080">&lt;/</span><span style="color: #4EC9B0">TodoContext.Provider</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>dispatch({ type: 'add', payload })</code> で状態を更新し、<code>todos</code> を購読できます。Redux に比べてボイラープレートが少ないのが利点ですが、<strong>ミドルウェア機構</strong> や <strong>開発ツール</strong> が欲しくなった時点で Redux Toolkit へ移行する判断基準となります。</p>



<h2 class="wp-block-heading">型安全カスタムフックの作成（TypeScript）</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="export const SettingsContext =
  createContext&lt;SettingsCtx | undefined&gt;(undefined);

export function useSettings(): SettingsCtx {
  const ctx = useContext(SettingsContext);
  if (!ctx) {
    throw new Error('useSettings must be inside &lt;SettingsProvider&gt;');
  }
  return ctx;
}" 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">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SettingsContext</span><span style="color: #D4D4D4"> =</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">createContext</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">SettingsCtx</span><span style="color: #D4D4D4"> | </span><span style="color: #4EC9B0">undefined</span><span style="color: #D4D4D4">&gt;(</span><span style="color: #569CD6">undefined</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">useSettings</span><span style="color: #D4D4D4">(): </span><span style="color: #4EC9B0">SettingsCtx</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">ctx</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">useContext</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">SettingsContext</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #9CDCFE">ctx</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">throw</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Error</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;useSettings must be inside &lt;SettingsProvider&gt;&#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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">ctx</span><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>undefined</code> をコンテキスト型に含め、Provider 外使用をコンパイル時に検出</li>



<li>呼び出し側は <code>const { theme } = useSettings();</code> とシンプル</li>
</ul>



<h2 class="wp-block-heading">React 18 コンカレント特有の落とし穴</h2>



<p class="wp-block-paragraph">並列レンダーでは <strong>「旧ツリー」と「新ツリー」が同時に存在</strong> します。Context の値もレンダー単位でスナップショットされるため、更新が重なった場合は “数フレームだけ古いテーマで描画” のような一貫性揺らぎが起こり得ます。<br>対策:</p>



<ol class="wp-block-list">
<li><strong>Transition</strong> 内で Provider を更新し、旧ツリーが素早く置き換わるようにする</li>



<li><strong>非同期値（サーバフェッチ結果など）</strong> は <code>useSyncExternalStore</code> で同期を取る</li>
</ol>



<h2 class="wp-block-heading">Suspense for Data Fetching と Context</h2>



<p class="wp-block-paragraph">React 18 の <strong>サスペンス対応データフェッチライブラリ</strong>（TanStack Query, SWR v2 等）は、Context でキャッシュを共有する設計が主流です。</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="&lt;QueryClientProvider client={client}&gt;  // Provider
  &lt;App /&gt;
&lt;/QueryClientProvider&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: #808080">&lt;</span><span style="color: #4EC9B0">QueryClientProvider</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">client</span><span style="color: #D4D4D4">=</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">client</span><span style="color: #569CD6">}</span><span style="color: #808080">&gt;</span><span style="color: #D4D4D4">  // Provider</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #808080">&lt;</span><span style="color: #4EC9B0">App</span><span style="color: #D4D4D4"> </span><span style="color: #808080">/&gt;</span></span>
<span class="line"><span style="color: #808080">&lt;/</span><span style="color: #4EC9B0">QueryClientProvider</span><span style="color: #808080">&gt;</span></span></code></pre></div>



<p class="wp-block-paragraph">内部的に Provider の値が変わらないよう慎重に実装されているため、大量のデータを扱っても再レンダーが抑えられます。</p>



<h2 class="wp-block-heading">テストと Storybook パターン</h2>



<h3 class="wp-block-heading">単体テスト</h3>



<ul class="wp-block-list">
<li>Provider をラップしたテストユーティリティを作成</li>



<li><code>renderHook</code> でカスタムフックのみをテスト</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 wrapper = ({ children }) =&gt; &lt;AuthProvider&gt;{children}&lt;/AuthProvider&gt;;
const { result } = renderHook(() =&gt; useAuth(), { wrapper });" 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: #DCDCAA">wrapper</span><span style="color: #D4D4D4"> = ({ </span><span style="color: #9CDCFE">children</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: #4EC9B0">AuthProvider</span><span style="color: #808080">&gt;</span><span style="color: #569CD6">{</span><span style="color: #9CDCFE">children</span><span style="color: #569CD6">}</span><span style="color: #808080">&lt;/</span><span style="color: #4EC9B0">AuthProvider</span><span style="color: #808080">&gt;</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">result</span><span style="color: #D4D4D4"> } = </span><span style="color: #DCDCAA">renderHook</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">useAuth</span><span style="color: #D4D4D4">(), { </span><span style="color: #9CDCFE">wrapper</span><span style="color: #D4D4D4"> });</span></span></code></pre></div>



<h3 class="wp-block-heading">Storybook</h3>



<ul class="wp-block-list">
<li><code>decorators</code> で Provider を追加し、Context に基づく UI を再現</li>



<li>複数バリエーションを Template で切り替え、locale や theme を擬似表示</li>
</ul>



<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><code>Cannot read property 'xyz' of null</code></td><td>Provider がツリーに含まれていない</td><td>カスタムフックでundefinedチェック</td></tr><tr><td>遅延評価したい値が毎回変わる</td><td>Provider の value を毎レンダー生成</td><td><code>useMemo</code> で固定 or 値を分割Providerへ</td></tr><tr><td>子が不必要に再レンダー</td><td>value がオブジェクトリテラル</td><td><code>useMemo</code> + <code>useCallback</code> で参照安定化</td></tr></tbody></table></div></figure>



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



<p class="wp-block-paragraph">Context の基礎とスコープ設計、パフォーマンス最適化と useReducer 連携・型安全化・並列レンダーの留意点まで解説しました。ここまでを理解すれば、中小規模の React アプリなら Redux 等を導入せずとも十分スケーラブルな状態共有が可能です。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://techgrowup.net/react-usecontext/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Flutter開発入門49 Providerパターンを使ったシンプルな状態管理</title>
		<link>https://techgrowup.net/flutter-provider-pattern/</link>
					<comments>https://techgrowup.net/flutter-provider-pattern/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[techgrowup]]></dc:creator>
		<pubDate>Mon, 14 Oct 2024 03:36:08 +0000</pubDate>
				<category><![CDATA[Flutter]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Dart]]></category>
		<category><![CDATA[Pattern]]></category>
		<category><![CDATA[Provider]]></category>
		<category><![CDATA[アプリ開発]]></category>
		<guid isPermaLink="false">https://techgrowup.net/?p=1964</guid>

					<description><![CDATA[はじめに Flutterでアプリケーションを開発する際、状態管理は避けて通れない課題です。特に規模が大きくなるアプリでは、効率的に状態を管理し、UIとビジネスロジックを分離する設計が重要になります。そこで登場するのがPr [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">はじめに</h1>



<p class="wp-block-paragraph">Flutterでアプリケーションを開発する際、<strong>状態管理</strong>は避けて通れない課題です。特に規模が大きくなるアプリでは、効率的に状態を管理し、UIとビジネスロジックを分離する設計が重要になります。そこで登場するのが<strong>Providerパターン</strong>です。Flutterの<code>Provider</code>パッケージは、公式が推奨する状態管理の方法で、シンプルでありながら強力です。</p>



<p class="wp-block-paragraph">この記事では、Flutterの公式ドキュメントに基づき、<strong>Providerパターンによるシンプルな状態管理</strong>について解説します。初めてFlutterで状態管理を学ぶ方にも理解しやすいように、基本的な概念から実際のコード例まで紹介します。</p>



<h2 class="wp-block-heading">Providerパターンとは</h2>



<p class="wp-block-paragraph"><strong>Providerパターン</strong>は、Flutterでの状態管理を簡潔かつ効率的に行うための設計パターンです。<code>Provider</code>は依存性注入の仕組みを提供し、<strong>データの共有とUIの更新</strong>を容易にします。特に、状態が変わるたびにUIをリビルドする必要がある場合に便利です。</p>



<h3 class="wp-block-heading">Providerパターンの主な特徴</h3>



<ul class="wp-block-list">
<li><strong>簡単な実装</strong>：シンプルなAPIで、状態管理を導入しやすい。</li>



<li><strong>依存関係の注入</strong>：データを必要な場所に簡単に渡すことができる。</li>



<li><strong>自動的なUIの更新</strong>：状態が変わった時点で、必要なウィジェットのみが再レンダリングされる。</li>



<li><strong>グローバルに状態を共有</strong>：状態をどこからでもアクセス可能にし、コードの再利用性が向上。</li>
</ul>



<h2 class="wp-block-heading">Providerパターンの基本的な使い方</h2>



<h3 class="wp-block-heading">1. セットアップ</h3>



<p class="wp-block-paragraph">まず、<code>pubspec.yaml</code>ファイルに<code>provider</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="dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0" 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">dependencies</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">flutter</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">sdk</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">flutter</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">provider</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">^6.0.0</span></span></code></pre></div>



<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="flutter pub get" 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: #DCDCAA">flutter</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">pub</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">get</span></span></code></pre></div>



<h3 class="wp-block-heading">2. Providerの構造</h3>



<p class="wp-block-paragraph">Providerパターンでは、状態を管理するクラスと、そのクラスを使ってUIを更新する流れが基本です。大まかな構造は以下の通りです。</p>



<ul class="wp-block-list">
<li><strong>モデルクラス</strong>：状態を保持し、更新するメソッドを持つクラス。</li>



<li><strong>ChangeNotifier</strong>：状態の変更をリスナーに通知するためのクラス。モデルクラスは<code>ChangeNotifier</code>を継承します。</li>



<li><strong>Consumerウィジェット</strong>：状態を監視し、UIを更新するために使われるウィジェット。</li>
</ul>



<h2 class="wp-block-heading">シンプルなカウンターアプリの例</h2>



<h3 class="wp-block-heading">1. モデルクラスの作成</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="import 'package:flutter/foundation.dart';

class CounterModel with ChangeNotifier {
  int _count = 0;

  int get count =&gt; _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}" 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">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;package:flutter/foundation.dart&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterModel</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">with</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ChangeNotifier</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4"> _count = </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: #4EC9B0">int</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">get</span><span style="color: #D4D4D4"> count =&gt; _count;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">    _count++;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">notifyListeners</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></code></pre></div>



<p class="wp-block-paragraph">解説</p>



<ul class="wp-block-list">
<li><strong>ChangeNotifier</strong>：<code>with ChangeNotifier</code>を使うことで、リスナーに状態の変更を通知できます。</li>



<li><strong>notifyListeners()</strong>：状態が変更されたことを通知し、UIが自動的に更新される仕組みを提供します。</li>
</ul>



<h3 class="wp-block-heading">2. Providerを使ったウィジェットの構築</h3>



<p class="wp-block-paragraph">次に、<code>Provider</code>を使ってアプリケーション全体でこのモデルクラスを提供します。<code>Provider</code>で状態をラップし、<code>Consumer</code>ウィジェットを使ってUIを更新します。</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 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_model.dart'; // モデルクラスをインポート

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) =&gt; CounterModel(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterScreen(),
    );
  }
}

class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Counter App with Provider')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('You have pushed the button this many times:'),
            Consumer&lt;CounterModel&gt;(
              builder: (context, counter, child) {
                return Text(
                  '${counter.count}',
                  style: Theme.of(context).textTheme.bodySmall,
                );
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Provider.of&lt;CounterModel&gt;(context, listen: false).increment();
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}" 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">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;package:flutter/material.dart&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;package:provider/provider.dart&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;counter_model.dart&#39;</span><span style="color: #D4D4D4">; </span><span style="color: #6A9955">// モデルクラスをインポート</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">main</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">runApp</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">ChangeNotifierProvider</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      create: (context) =&gt; </span><span style="color: #4EC9B0">CounterModel</span><span style="color: #D4D4D4">(),</span></span>
<span class="line"><span style="color: #D4D4D4">      child: </span><span style="color: #4EC9B0">MyApp</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>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">MyApp</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">StatelessWidget</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">@override</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">Widget</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">build</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">BuildContext</span><span style="color: #D4D4D4"> context) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">MaterialApp</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      home: </span><span style="color: #4EC9B0">CounterScreen</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>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterScreen</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">StatelessWidget</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">@override</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">Widget</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">build</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">BuildContext</span><span style="color: #D4D4D4"> context) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Scaffold</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      appBar: </span><span style="color: #4EC9B0">AppBar</span><span style="color: #D4D4D4">(title: </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Counter App with Provider&#39;</span><span style="color: #D4D4D4">)),</span></span>
<span class="line"><span style="color: #D4D4D4">      body: </span><span style="color: #4EC9B0">Center</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">        child: </span><span style="color: #4EC9B0">Column</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          mainAxisAlignment: </span><span style="color: #4EC9B0">MainAxisAlignment</span><span style="color: #D4D4D4">.center,</span></span>
<span class="line"><span style="color: #D4D4D4">          children: [</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;You have pushed the button this many times:&#39;</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #4EC9B0">Consumer</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">CounterModel</span><span style="color: #D4D4D4">&gt;(</span></span>
<span class="line"><span style="color: #D4D4D4">              builder: (context, counter, child) {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">                  </span><span style="color: #CE9178">&#39;${</span><span style="color: #9CDCFE">counter</span><span style="color: #CE9178">.</span><span style="color: #9CDCFE">count</span><span style="color: #CE9178">}&#39;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                  style: </span><span style="color: #4EC9B0">Theme</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">of</span><span style="color: #D4D4D4">(context).textTheme.bodySmall,</span></span>
<span class="line"><span style="color: #D4D4D4">                );</span></span>
<span class="line"><span style="color: #D4D4D4">              },</span></span>
<span class="line"><span style="color: #D4D4D4">            ),</span></span>
<span class="line"><span style="color: #D4D4D4">          ],</span></span>
<span class="line"><span style="color: #D4D4D4">        ),</span></span>
<span class="line"><span style="color: #D4D4D4">      ),</span></span>
<span class="line"><span style="color: #D4D4D4">      floatingActionButton: </span><span style="color: #4EC9B0">FloatingActionButton</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">        onPressed: () {</span></span>
<span class="line"><span style="color: #D4D4D4">          </span><span style="color: #4EC9B0">Provider</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">of</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">CounterModel</span><span style="color: #D4D4D4">&gt;(context, listen: </span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        },</span></span>
<span class="line"><span style="color: #D4D4D4">        tooltip: </span><span style="color: #CE9178">&#39;Increment&#39;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        child: </span><span style="color: #4EC9B0">Icon</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">Icons</span><span style="color: #D4D4D4">.add),</span></span>
<span class="line"><span style="color: #D4D4D4">      ),</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">解説</p>



<ul class="wp-block-list">
<li><strong>ChangeNotifierProvider</strong>：<code>ChangeNotifier</code>を使って、状態をアプリ全体に提供するプロバイダです。<code>create</code>でインスタンスを生成します。</li>



<li><strong>Consumer</strong>：<code>Consumer</code>ウィジェットは、プロバイダの状態を監視し、状態が変わるたびにUIを更新します。</li>



<li><strong>Provider.of</strong>：<code>Provider.of&lt;CounterModel>(context)</code>で、プロバイダにアクセスし、状態を操作します。<code>listen: false</code>にすることで、状態が変わっても再ビルドされないようにします。</li>
</ul>



<h2 class="wp-block-heading">複雑な状態管理への拡張</h2>



<p class="wp-block-paragraph"><code>Provider</code>パターンは、シンプルなアプリから複雑なアプリまでスケーラブルに対応できます。例えば、以下のような機能を追加することが可能です。</p>



<h3 class="wp-block-heading">1. 複数のProviderを使用する</h3>



<p class="wp-block-paragraph"><code>MultiProvider</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="MultiProvider(
  providers: [
    ChangeNotifierProvider(create: (context) =&gt; CounterModel()),
    ChangeNotifierProvider(create: (context) =&gt; AuthModel()),
  ],
  child: MyApp(),
)" 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: #4EC9B0">MultiProvider</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">  providers: [</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">ChangeNotifierProvider</span><span style="color: #D4D4D4">(create: (context) =&gt; </span><span style="color: #4EC9B0">CounterModel</span><span style="color: #D4D4D4">()),</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">ChangeNotifierProvider</span><span style="color: #D4D4D4">(create: (context) =&gt; </span><span style="color: #4EC9B0">AuthModel</span><span style="color: #D4D4D4">()),</span></span>
<span class="line"><span style="color: #D4D4D4">  ],</span></span>
<span class="line"><span style="color: #D4D4D4">  child: </span><span style="color: #4EC9B0">MyApp</span><span style="color: #D4D4D4">(),</span></span>
<span class="line"><span style="color: #D4D4D4">)</span></span></code></pre></div>



<h3 class="wp-block-heading">2. 非同期処理との統合</h3>



<p class="wp-block-paragraph"><code>Provider</code>は非同期データにも対応可能です。例えば、APIリクエストを実行して、取得したデータをUIに反映することができます。<code>FutureProvider</code>や<code>StreamProvider</code>を使えば、非同期データを簡単に扱えます。</p>



<h2 class="wp-block-heading">Providerパターンのメリットとベストプラクティス</h2>



<h3 class="wp-block-heading">メリット</h3>



<ol class="wp-block-list">
<li><strong>シンプルなAPI</strong>：<code>Provider</code>の使い方は非常にシンプルで、導入が簡単。</li>



<li><strong>テストがしやすい</strong>：ビジネスロジックとUIが分離されているため、テストが容易。</li>



<li><strong>パフォーマンスが高い</strong>：状態が変更されたときに必要な部分だけをリビルドするため、パフォーマンスに優れています。</li>
</ol>



<h3 class="wp-block-heading">ベストプラクティス</h3>



<ul class="wp-block-list">
<li><strong>状態のロジックを分離する</strong>：ビジネスロジックはモデルクラスにまとめ、UIはUIに専念させる。</li>



<li><strong>Providerの適切な配置</strong>：アプリ全体で共有する必要がある状態は、<code>MaterialApp</code>の近くに配置し、ローカルな状態はより下層のウィジェットに配置する。</li>
</ul>



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



<p class="wp-block-paragraph">Flutterの<strong>Providerパターン</strong>は、シンプルかつ強力な状態管理方法を提供します。<code>ChangeNotifier</code>を使って状態を簡単に管理し、<code>Consumer</code>や<code>Provider.of</code>でUIに反映することで、効率的な状態管理が可能になります。また、複数のプロバイダや非同期処理も簡単に扱えるため、スケーラブルなアプリケーション開発が可能です。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://techgrowup.net/flutter-provider-pattern/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Flutter開発入門47 hooks_riverpodでのStreamProvider、NotifierProvider、StateNotifierProvider、ChangeNotifierProviderの使い方</title>
		<link>https://techgrowup.net/flutter-hooks-riverpod-each-provider/</link>
					<comments>https://techgrowup.net/flutter-hooks-riverpod-each-provider/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[techgrowup]]></dc:creator>
		<pubDate>Sat, 12 Oct 2024 05:12:49 +0000</pubDate>
				<category><![CDATA[Flutter]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Dart]]></category>
		<category><![CDATA[Hooks]]></category>
		<category><![CDATA[Provider]]></category>
		<category><![CDATA[Riverpod]]></category>
		<category><![CDATA[アプリ開発]]></category>
		<guid isPermaLink="false">https://techgrowup.net/?p=1955</guid>

					<description><![CDATA[はじめに hooks_riverpodは、Flutterアプリの開発において、強力で柔軟な状態管理を提供します。特に、非同期処理を扱うためのStreamProvider、状態を管理するためのNotifierProvide [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">はじめに</h1>



<p class="wp-block-paragraph"><strong><code>hooks_riverpod</code>は、Flutterアプリの開発において、強力で柔軟な状態管理を提供します。特に、非同期処理を扱うための<code>StreamProvider</code></strong>、状態を管理するための<code>NotifierProvider</code><strong>や</strong><code>StateNotifierProvider</code><strong>、および従来の<code>ChangeNotifier</code>に基づいた</strong><code>ChangeNotifierProvider</code>は、それぞれの場面で最適なソリューションを提供します。</p>



<p class="wp-block-paragraph">この記事では、<strong>StreamProvider、NotifierProvider、StateNotifierProvider、ChangeNotifierProvider</strong>の使い方について詳しく解説します。Flutter開発を効率化し、状態管理をよりシンプルにするための実践的な知識を提供します。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



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



<p class="wp-block-paragraph"><code>hooks_riverpod</code>は、<code>Riverpod</code>の状態管理機能と<code>Flutter Hooks</code>のフック機能を統合したライブラリです。Riverpodによる強力な状態管理に、Flutter Hooksを組み合わせることで、ウィジェットのライフサイクルに応じた簡潔な状態管理を実現します。</p>



<p class="wp-block-paragraph">この記事では、特に以下のプロバイダについて詳しく見ていきます。</p>



<ul class="wp-block-list">
<li><strong><code>StreamProvider</code></strong>：非同期データのストリームを管理。</li>



<li><strong><code>NotifierProvider</code></strong>：<code>Notifier</code>クラスをベースにした状態管理。</li>



<li><strong><code>StateNotifierProvider</code></strong>：<code>StateNotifier</code>を使って状態を管理する。</li>



<li><strong><code>ChangeNotifierProvider</code></strong>：従来の<code>ChangeNotifier</code>ベースの状態管理。</li>
</ul>



<p class="wp-block-paragraph">※<code>hooks_riverpod</code>が導入が済んでいない方は以下記事を確認してください。</p>



<figure class="wp-block-embed is-type-wp-embed is-provider-techgrowup wp-block-embed-techgrowup"><div class="wp-block-embed__wrapper">

<a target="_self" href="https://techgrowup.net/flutter-hooks-riverpod/" title="Flutter開発入門46 hooks_riverpodの使い方：効率的な状態管理を実現" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="90" src="https://techgrowup.net/wp-content/uploads/2024/10/flutter-hooks-riverpod-160x90.webp" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://techgrowup.net/wp-content/uploads/2024/10/flutter-hooks-riverpod-160x90.webp 160w, https://techgrowup.net/wp-content/uploads/2024/10/flutter-hooks-riverpod-1024x585.webp 1024w, https://techgrowup.net/wp-content/uploads/2024/10/flutter-hooks-riverpod-768x439.webp 768w, https://techgrowup.net/wp-content/uploads/2024/10/flutter-hooks-riverpod-120x68.webp 120w, https://techgrowup.net/wp-content/uploads/2024/10/flutter-hooks-riverpod-320x180.webp 320w, https://techgrowup.net/wp-content/uploads/2024/10/flutter-hooks-riverpod-376x212.webp 376w, https://techgrowup.net/wp-content/uploads/2024/10/flutter-hooks-riverpod.webp 1200w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">Flutter開発入門46 hooks_riverpodの使い方：効率的な状態管理を実現</div><div class="blogcard-snippet internal-blogcard-snippet">Flutterアプリでの状態管理に欠かせないhooks_riverpodを徹底解説。useProviderは廃止され、WidgetRefとref.watchを使った効率的な状態管理方法を解説します。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://techgrowup.net" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">techgrowup.net</div></div><div class="blogcard-date internal-blogcard-date"><div class="blogcard-post-date internal-blogcard-post-date">2024.10.12</div></div></div></div></a>
</div></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">StreamProviderの使い方</h2>



<p class="wp-block-paragraph"><code>StreamProvider</code>は、非同期でデータのストリームを提供する際に使用します。たとえば、リアルタイムに更新されるデータや、ストリームAPIのデータを扱う場合に便利です。</p>



<h3 class="wp-block-heading">例：StreamProviderでのリアルタイムカウント</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="final countStreamProvider = StreamProvider&lt;int&gt;((ref) {
  return Stream.periodic(const Duration(seconds: 1), (count) =&gt; count);
});

class HomeScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final asyncValue = ref.watch(countStreamProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('StreamProvider Example')),
      body: Center(
        child: asyncValue.when(
          data: (count) =&gt; Text('Count: $count'),
          loading: () =&gt; CircularProgressIndicator(),
          error: (err, stack) =&gt; Text('Error: $err'),
        ),
      ),
    );
  }
}" 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">final</span><span style="color: #D4D4D4"> countStreamProvider = </span><span style="color: #4EC9B0">StreamProvider</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4">&gt;((ref) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Stream</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">periodic</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Duration</span><span style="color: #D4D4D4">(seconds: </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">), (count) =&gt; count);</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">HomeScreen</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ConsumerWidget</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">@override</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">Widget</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">build</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">BuildContext</span><span style="color: #D4D4D4"> context, </span><span style="color: #4EC9B0">WidgetRef</span><span style="color: #D4D4D4"> ref) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">final</span><span style="color: #D4D4D4"> asyncValue = ref.</span><span style="color: #DCDCAA">watch</span><span style="color: #D4D4D4">(countStreamProvider);</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: #4EC9B0">Scaffold</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      appBar: </span><span style="color: #4EC9B0">AppBar</span><span style="color: #D4D4D4">(title: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;StreamProvider Example&#39;</span><span style="color: #D4D4D4">)),</span></span>
<span class="line"><span style="color: #D4D4D4">      body: </span><span style="color: #4EC9B0">Center</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">        child: asyncValue.</span><span style="color: #C586C0">when</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          data: (count) =&gt; </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Count: $</span><span style="color: #9CDCFE">count</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">          loading: () =&gt; </span><span style="color: #4EC9B0">CircularProgressIndicator</span><span style="color: #D4D4D4">(),</span></span>
<span class="line"><span style="color: #D4D4D4">          error: (err, stack) =&gt; </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Error: $</span><span style="color: #9CDCFE">err</span><span style="color: #CE9178">&#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>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">解説</p>



<ul class="wp-block-list">
<li><strong><code>StreamProvider</code></strong>：非同期ストリームをプロバイダとして提供し、UIにリアルタイムで反映できます。</li>



<li><strong><code>Stream.periodic</code></strong>：一定の間隔でデータを発行するストリームの生成方法です。</li>



<li><strong><code>asyncValue.when</code></strong>：<code>StreamProvider</code>の状態に応じて、データ・ローディング・エラーのそれぞれを表示します。</li>
</ul>



<h2 class="wp-block-heading">NotifierProviderの使い方</h2>



<p class="wp-block-paragraph"><code>NotifierProvider</code>は、<strong><code>Notifier</code>クラス</strong>に基づいたプロバイダで、<code>Notifier</code>を使って状態を管理し、それに応じてUIをリビルドする際に使用します。<code>Notifier</code>は、状態を持たせ、<code>notifyListeners</code>で更新するシンプルな仕組みです。</p>



<h3 class="wp-block-heading">例：NotifierProviderでカウンターを管理</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="class CounterNotifier extends Notifier&lt;int&gt; {
  @override
  int build() =&gt; 0;

  void increment() =&gt; state++;
}

final counterProvider = NotifierProvider&lt;CounterNotifier, int&gt;(() {
  return CounterNotifier();
});

class HomeScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('NotifierProvider Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Count: $count', style: const TextStyle(fontSize: 40)),
            ElevatedButton(
              onPressed: () =&gt; ref.read(counterProvider.notifier).increment(),
              child: const Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}" 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">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterNotifier</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Notifier</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4">&gt; {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">@override</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">build</span><span style="color: #D4D4D4">() =&gt; </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">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">() =&gt; state++;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">final</span><span style="color: #D4D4D4"> counterProvider = </span><span style="color: #4EC9B0">NotifierProvider</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">CounterNotifier</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4">&gt;(() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterNotifier</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">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">HomeScreen</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ConsumerWidget</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">@override</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">Widget</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">build</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">BuildContext</span><span style="color: #D4D4D4"> context, </span><span style="color: #4EC9B0">WidgetRef</span><span style="color: #D4D4D4"> ref) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">final</span><span style="color: #D4D4D4"> count = ref.</span><span style="color: #DCDCAA">watch</span><span style="color: #D4D4D4">(counterProvider);</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: #4EC9B0">Scaffold</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      appBar: </span><span style="color: #4EC9B0">AppBar</span><span style="color: #D4D4D4">(title: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;NotifierProvider Example&#39;</span><span style="color: #D4D4D4">)),</span></span>
<span class="line"><span style="color: #D4D4D4">      body: </span><span style="color: #4EC9B0">Center</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">        child: </span><span style="color: #4EC9B0">Column</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          mainAxisAlignment: </span><span style="color: #4EC9B0">MainAxisAlignment</span><span style="color: #D4D4D4">.center,</span></span>
<span class="line"><span style="color: #D4D4D4">          children: [</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Count: $</span><span style="color: #9CDCFE">count</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">, style: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">TextStyle</span><span style="color: #D4D4D4">(fontSize: </span><span style="color: #B5CEA8">40</span><span style="color: #D4D4D4">)),</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #4EC9B0">ElevatedButton</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">              onPressed: () =&gt; ref.</span><span style="color: #DCDCAA">read</span><span style="color: #D4D4D4">(counterProvider.notifier).</span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">(),</span></span>
<span class="line"><span style="color: #D4D4D4">              child: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Increment&#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>
<span class="line"><span style="color: #D4D4D4">        ),</span></span>
<span class="line"><span style="color: #D4D4D4">      ),</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">解説</p>



<ul class="wp-block-list">
<li><strong><code>Notifier</code></strong>：シンプルな状態管理クラスで、状態を管理し、変更があった際にリビルドをトリガーします。</li>



<li><strong><code>NotifierProvider</code></strong>：<code>Notifier</code>をプロバイダとして使用し、状態を管理します。</li>



<li><strong><code>ref.watch(counterProvider)</code></strong>：カウンターの現在の値を監視し、UIに反映します。</li>



<li><strong><code>ref.read(counterProvider.notifier).increment()</code></strong>：<code>Notifier</code>のメソッドを使って状態を変更します。</li>
</ul>



<h2 class="wp-block-heading">StateNotifierProviderの使い方</h2>



<p class="wp-block-paragraph"><code>StateNotifierProvider</code>は、<strong><code>StateNotifier</code>クラス</strong>を使って、状態を細かく管理したいときに便利です。<code>StateNotifier</code>は、状態を変更するためのメソッドを定義でき、状態の変更を安全に管理できます。</p>



<h3 class="wp-block-heading">例：StateNotifierProviderでカウンターを管理</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="class CounterStateNotifier extends StateNotifier&lt;int&gt; {
  CounterStateNotifier() : super(0);

  void increment() =&gt; state++;
}

final counterStateNotifierProvider =
    StateNotifierProvider&lt;CounterStateNotifier, int&gt;((ref) {
  return CounterStateNotifier();
});

class HomeScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterStateNotifierProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('StateNotifierProvider Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Count: $count', style: const TextStyle(fontSize: 40)),
            ElevatedButton(
              onPressed: () =&gt;
                  ref.read(counterStateNotifierProvider.notifier).increment(),
              child: const Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}" 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">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterStateNotifier</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">StateNotifier</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4">&gt; {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">CounterStateNotifier</span><span style="color: #D4D4D4">() : </span><span style="color: #569CD6">super</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">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">() =&gt; state++;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">final</span><span style="color: #D4D4D4"> counterStateNotifierProvider =</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">StateNotifierProvider</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">CounterStateNotifier</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4">&gt;((ref) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterStateNotifier</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">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">HomeScreen</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ConsumerWidget</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">@override</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">Widget</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">build</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">BuildContext</span><span style="color: #D4D4D4"> context, </span><span style="color: #4EC9B0">WidgetRef</span><span style="color: #D4D4D4"> ref) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">final</span><span style="color: #D4D4D4"> count = ref.</span><span style="color: #DCDCAA">watch</span><span style="color: #D4D4D4">(counterStateNotifierProvider);</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: #4EC9B0">Scaffold</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      appBar: </span><span style="color: #4EC9B0">AppBar</span><span style="color: #D4D4D4">(title: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;StateNotifierProvider Example&#39;</span><span style="color: #D4D4D4">)),</span></span>
<span class="line"><span style="color: #D4D4D4">      body: </span><span style="color: #4EC9B0">Center</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">        child: </span><span style="color: #4EC9B0">Column</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          mainAxisAlignment: </span><span style="color: #4EC9B0">MainAxisAlignment</span><span style="color: #D4D4D4">.center,</span></span>
<span class="line"><span style="color: #D4D4D4">          children: [</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Count: $</span><span style="color: #9CDCFE">count</span><span style="color: #CE9178">&#39;</span><span style="color: #D4D4D4">, style: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">TextStyle</span><span style="color: #D4D4D4">(fontSize: </span><span style="color: #B5CEA8">40</span><span style="color: #D4D4D4">)),</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #4EC9B0">ElevatedButton</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">              onPressed: () =&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                  ref.</span><span style="color: #DCDCAA">read</span><span style="color: #D4D4D4">(counterStateNotifierProvider.notifier).</span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">(),</span></span>
<span class="line"><span style="color: #D4D4D4">              child: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Increment&#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>
<span class="line"><span style="color: #D4D4D4">        ),</span></span>
<span class="line"><span style="color: #D4D4D4">      ),</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">解説</p>



<ul class="wp-block-list">
<li><strong><code>StateNotifier</code></strong>：状態を管理するためのクラスで、複雑なロジックにも対応できます。</li>



<li><strong><code>StateNotifierProvider</code></strong>：<code>StateNotifier</code>をプロバイダとして使用し、状態の管理を行います。</li>



<li><strong><code>state</code></strong>：現在の状態を保持するプロパティで、状態が更新されるとリビルドがトリガーされます。</li>
</ul>



<h2 class="wp-block-heading">ChangeNotifierProviderの使い方</h2>



<p class="wp-block-paragraph"><code>ChangeNotifierProvider</code>は、従来の<code>ChangeNotifier</code>ベースの状態管理を使いたい場合に有効です。<code>ChangeNotifier</code>は、<code>notifyListeners</code>メソッドを使って状態の更新を通知します。</p>



<h3 class="wp-block-heading">例：ChangeNotifierProviderでカウンターを管理</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="class CounterChangeNotifier extends ChangeNotifier {
  int _count = 0;
  int get count =&gt; _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

final counterChangeNotifierProvider =
    ChangeNotifierProvider&lt;CounterChangeNotifier&gt;((ref) {
  return CounterChangeNotifier();
});

class HomeScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final counter = ref.watch(counterChangeNotifierProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('ChangeNotifierProvider Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Count: ${counter.count}',
                style: const TextStyle(fontSize: 40)),
            ElevatedButton(
              onPressed: () =&gt; counter.increment(),
              child: const Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}" 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">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterChangeNotifier</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ChangeNotifier</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4"> _count = </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">get</span><span style="color: #D4D4D4"> count =&gt; _count;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">    _count++;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">notifyListeners</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>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">final</span><span style="color: #D4D4D4"> counterChangeNotifierProvider =</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">ChangeNotifierProvider</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">CounterChangeNotifier</span><span style="color: #D4D4D4">&gt;((ref) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterChangeNotifier</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">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">HomeScreen</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ConsumerWidget</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">@override</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">Widget</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">build</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">BuildContext</span><span style="color: #D4D4D4"> context, </span><span style="color: #4EC9B0">WidgetRef</span><span style="color: #D4D4D4"> ref) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">final</span><span style="color: #D4D4D4"> counter = ref.</span><span style="color: #DCDCAA">watch</span><span style="color: #D4D4D4">(counterChangeNotifierProvider);</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: #4EC9B0">Scaffold</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      appBar: </span><span style="color: #4EC9B0">AppBar</span><span style="color: #D4D4D4">(title: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;ChangeNotifierProvider Example&#39;</span><span style="color: #D4D4D4">)),</span></span>
<span class="line"><span style="color: #D4D4D4">      body: </span><span style="color: #4EC9B0">Center</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">        child: </span><span style="color: #4EC9B0">Column</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          mainAxisAlignment: </span><span style="color: #4EC9B0">MainAxisAlignment</span><span style="color: #D4D4D4">.center,</span></span>
<span class="line"><span style="color: #D4D4D4">          children: [</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Count: ${</span><span style="color: #9CDCFE">counter</span><span style="color: #CE9178">.</span><span style="color: #9CDCFE">count</span><span style="color: #CE9178">}&#39;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                style: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">TextStyle</span><span style="color: #D4D4D4">(fontSize: </span><span style="color: #B5CEA8">40</span><span style="color: #D4D4D4">)),</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #4EC9B0">ElevatedButton</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">              onPressed: () =&gt; counter.</span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">(),</span></span>
<span class="line"><span style="color: #D4D4D4">              child: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Increment&#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>
<span class="line"><span style="color: #D4D4D4">        ),</span></span>
<span class="line"><span style="color: #D4D4D4">      ),</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">解説</p>



<ul class="wp-block-list">
<li><strong><code>ChangeNotifier</code></strong>：リスナーに状態の変更を通知するためのクラスで、従来のFlutterの状態管理でよく使われます。</li>



<li><strong><code>ChangeNotifierProvider</code></strong>：<code>ChangeNotifier</code>をプロバイダとして使用し、<code>notifyListeners</code>でUIをリビルドします。</li>
</ul>



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



<p class="wp-block-paragraph">Flutterでの状態管理において、<strong><code>hooks_riverpod</code>は強力なツールです。今回紹介した<code>StreamProvider</code></strong>、<strong><code>NotifierProvider</code></strong>、<strong><code>StateNotifierProvider</code></strong>、および<code>ChangeNotifierProvider</code>を適切に使い分けることで、アプリケーションの規模に関わらず、効率的に状態を管理できます。それぞれのプロバイダは特定のユースケースに最適化されており、状態の再利用や非同期データの管理に役立ちます。</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://techgrowup.net/flutter-hooks-riverpod-each-provider/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Flutter開発入門18 依存性注入（DI）とは？効率的な状態管理</title>
		<link>https://techgrowup.net/flutter%e9%96%8b%e7%99%ba%e5%85%a5%e9%96%8018-%e4%be%9d%e5%ad%98%e6%80%a7%e6%b3%a8%e5%85%a5%ef%bc%88di%ef%bc%89%e3%81%a8%e3%81%af%ef%bc%9f%e5%8a%b9%e7%8e%87%e7%9a%84%e3%81%aa%e7%8a%b6%e6%85%8b/</link>
					<comments>https://techgrowup.net/flutter%e9%96%8b%e7%99%ba%e5%85%a5%e9%96%8018-%e4%be%9d%e5%ad%98%e6%80%a7%e6%b3%a8%e5%85%a5%ef%bc%88di%ef%bc%89%e3%81%a8%e3%81%af%ef%bc%9f%e5%8a%b9%e7%8e%87%e7%9a%84%e3%81%aa%e7%8a%b6%e6%85%8b/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[techgrowup]]></dc:creator>
		<pubDate>Fri, 13 Sep 2024 04:09:41 +0000</pubDate>
				<category><![CDATA[Flutter]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Dart]]></category>
		<category><![CDATA[DI]]></category>
		<category><![CDATA[GetIt]]></category>
		<category><![CDATA[Provider]]></category>
		<category><![CDATA[アプリ開発]]></category>
		<guid isPermaLink="false">https://techgrowup.net/?p=1800</guid>

					<description><![CDATA[はじめに 　Flutterアプリケーション開発において、依存性注入（Dependency Injection, DI）は、クリーンで拡張性の高いコードを書くために欠かせない設計手法です。DIを適切に導入することで、アプリ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">はじめに</h1>



<p class="wp-block-paragraph">　Flutterアプリケーション開発において、依存性注入（Dependency Injection, DI）は、クリーンで拡張性の高いコードを書くために欠かせない設計手法です。DIを適切に導入することで、アプリケーションのテストが容易になり、コードの保守性が向上します。本記事では、Flutterでの依存性注入の基本的な考え方と、その実践方法を解説します。特に、<code>Provider</code>や<code>GetIt</code>などの便利なパッケージを使った実装方法を中心に説明します。</p>



<h2 class="wp-block-heading">依存性注入（DI）とは？</h2>



<p class="wp-block-paragraph">　依存性注入とは、あるクラスが必要とする他のクラスやオブジェクト（依存性）を外部から提供する設計手法です。これにより、クラスが直接依存するインスタンスを自ら生成するのではなく、必要な依存性が注入されるため、クラスの柔軟性とテストのしやすさが向上します。</p>



<p class="wp-block-paragraph">　例えば、アプリのビジネスロジックを担当するクラス（サービスやリポジトリ）が、外部APIやデータベースとのやりとりを行う際、その依存するクラスを直接内部でインスタンス化すると、テストや保守が難しくなります。そこで、DIを使って、必要な依存性を外部から注入します。</p>



<h6 class="wp-block-heading">依存性注入のメリット</h6>



<ul class="wp-block-list">
<li><strong>モジュール化</strong>: クラスが特定の実装に強く依存しなくなるため、クラス間の依存性を緩和できます。</li>



<li><strong>テストが容易</strong>: 依存性を外部から注入することで、テスト時にモック（テスト用のオブジェクト）を使用できます。</li>



<li><strong>保守性が向上</strong>: クラスの実装が変更されても、注入される依存性を簡単に変更できるため、コードの保守が容易になります。</li>
</ul>



<h2 class="wp-block-heading">Flutterでの依存性注入の実装</h2>



<p class="wp-block-paragraph">　　Flutterでは、依存性注入を実現するためにいくつかの方法がありますが、代表的なのが<code>Provider</code>や<code>GetIt</code>といったパッケージを使った方法です。ここでは、それぞれの方法を紹介します。</p>



<h3 class="wp-block-heading">1. Providerを使った依存性注入</h3>



<p class="wp-block-paragraph">　<code>Provider</code>は、Flutterの状態管理と依存性注入をシンプルに実現できるパッケージです。<code>ChangeNotifier</code>や<code>ValueNotifier</code>といった状態管理クラスを用いることで、UIとビジネスロジックを効率的に連携できます。</p>



<p class="wp-block-paragraph">　まず、<code>pubspec.yaml</code>ファイルに<code>provider</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="dependencies:
  provider: ^6.0.0" 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">dependencies</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">provider</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">^6.0.0</span></span></code></pre></div>



<p class="wp-block-paragraph">　次に、<code>ChangeNotifier</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 'package:flutter/material.dart';
import 'package:provider/provider.dart';

// データの取得と管理を行うクラス
class CounterService with ChangeNotifier {
  int _counter = 0;

  int get counter =&gt; _counter;

  void increment() {
    _counter++;
    notifyListeners(); // 状態が変わったことを通知
  }
}

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) =&gt; CounterService(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dependency Injection with Provider'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'カウント数:',
              ),
              Consumer&lt;CounterService&gt;(
                builder: (context, counterService, child) {
                  return Text(
                    '${counterService.counter}',
                    style: TextStyle(fontSize: 40),
                  );
                },
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            Provider.of&lt;CounterService&gt;(context, listen: false).increment();
          },
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}
" 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">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;package:flutter/material.dart&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;package:provider/provider.dart&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// データの取得と管理を行うクラス</span></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterService</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">with</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ChangeNotifier</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4"> _counter = </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: #4EC9B0">int</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">get</span><span style="color: #D4D4D4"> counter =&gt; _counter;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">    _counter++;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">notifyListeners</span><span style="color: #D4D4D4">(); </span><span style="color: #6A9955">// 状態が変わったことを通知</span></span>
<span class="line"><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">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">main</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">runApp</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">ChangeNotifierProvider</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      create: (context) =&gt; </span><span style="color: #4EC9B0">CounterService</span><span style="color: #D4D4D4">(),</span></span>
<span class="line"><span style="color: #D4D4D4">      child: </span><span style="color: #4EC9B0">MyApp</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>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">MyApp</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">StatelessWidget</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">@override</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">Widget</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">build</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">BuildContext</span><span style="color: #D4D4D4"> context) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">MaterialApp</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      home: </span><span style="color: #4EC9B0">Scaffold</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">        appBar: </span><span style="color: #4EC9B0">AppBar</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          title: </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Dependency Injection with Provider&#39;</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">        ),</span></span>
<span class="line"><span style="color: #D4D4D4">        body: </span><span style="color: #4EC9B0">Center</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          child: </span><span style="color: #4EC9B0">Column</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">            mainAxisAlignment: </span><span style="color: #4EC9B0">MainAxisAlignment</span><span style="color: #D4D4D4">.center,</span></span>
<span class="line"><span style="color: #D4D4D4">            children: [</span></span>
<span class="line"><span style="color: #D4D4D4">              </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><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>
<span class="line"><span style="color: #D4D4D4">              </span><span style="color: #4EC9B0">Consumer</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">CounterService</span><span style="color: #D4D4D4">&gt;(</span></span>
<span class="line"><span style="color: #D4D4D4">                builder: (context, counterService, child) {</span></span>
<span class="line"><span style="color: #D4D4D4">                  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #CE9178">&#39;${</span><span style="color: #9CDCFE">counterService</span><span style="color: #CE9178">.</span><span style="color: #9CDCFE">counter</span><span style="color: #CE9178">}&#39;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                    style: </span><span style="color: #4EC9B0">TextStyle</span><span style="color: #D4D4D4">(fontSize: </span><span style="color: #B5CEA8">40</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>
<span class="line"><span style="color: #D4D4D4">              ),</span></span>
<span class="line"><span style="color: #D4D4D4">            ],</span></span>
<span class="line"><span style="color: #D4D4D4">          ),</span></span>
<span class="line"><span style="color: #D4D4D4">        ),</span></span>
<span class="line"><span style="color: #D4D4D4">        floatingActionButton: </span><span style="color: #4EC9B0">FloatingActionButton</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          onPressed: () {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #4EC9B0">Provider</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">of</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">CounterService</span><span style="color: #D4D4D4">&gt;(context, listen: </span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">          },</span></span>
<span class="line"><span style="color: #D4D4D4">          child: </span><span style="color: #4EC9B0">Icon</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">Icons</span><span style="color: #D4D4D4">.add),</span></span>
<span class="line"><span style="color: #D4D4D4">        ),</span></span>
<span class="line"><span style="color: #D4D4D4">      ),</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<h5 class="wp-block-heading">解説</h5>



<ul class="wp-block-list">
<li><strong><code>ChangeNotifierProvider</code></strong>: 依存性注入を行うためのProviderです。<code>CounterService</code>というクラスをグローバルに提供しています。</li>



<li><strong><code>Consumer</code></strong>: <code>Consumer</code>ウィジェットを使って、<code>CounterService</code>の状態をUIに反映させています。状態が変更されるたびにUIが再描画されます。</li>



<li><strong><code>notifyListeners()</code></strong>: <code>ChangeNotifier</code>クラスのメソッドで、状態が更新されたことをリスナーに通知します。</li>
</ul>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="flutter provider di video" width="1256" height="707" src="https://www.youtube.com/embed/LjkLlPaT2rU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<h3 class="wp-block-heading">2. <strong>GetItを使った依存性注入</strong></h3>



<p class="wp-block-paragraph">　　<code>GetIt</code>は、シンプルな依存性注入の実装を提供するパッケージです。シングルトンパターンを使ってインスタンスを管理するため、アプリのどこからでも簡単に依存性にアクセスできるのが特徴です。<code>GetIt</code>を使った依存性注入</p>



<p class="wp-block-paragraph">　まず、<code>pubspec.yaml</code>ファイルに<code>get_it</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="dependencies:
  get_it: ^7.7.0" 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">dependencies</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">get_it</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">^7.7.0</span></span></code></pre></div>



<p class="wp-block-paragraph">　次に、<code>GetIt</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 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';

// GetItを初期化する
GetIt locator = GetIt.instance;

void setupLocator() {
  locator.registerLazySingleton&lt;CounterService&gt;(() =&gt; CounterService());
}

// カウンターを管理するクラス
class CounterService {
  int _counter = 0;

  int get counter =&gt; _counter;

  void increment() {
    _counter++;
  }
}

void main() {
  setupLocator(); // GetItのセットアップ
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Dependency Injection with GetIt'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text('カウント数:'),
              Text(
                '${locator&lt;CounterService&gt;().counter}',
                style: TextStyle(fontSize: 40),
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            locator&lt;CounterService&gt;().increment();
          },
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}" 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">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;package:flutter/material.dart&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">import</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;package:get_it/get_it.dart&#39;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// GetItを初期化する</span></span>
<span class="line"><span style="color: #4EC9B0">GetIt</span><span style="color: #D4D4D4"> locator = </span><span style="color: #4EC9B0">GetIt</span><span style="color: #D4D4D4">.instance;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">setupLocator</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  locator.</span><span style="color: #DCDCAA">registerLazySingleton</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">CounterService</span><span style="color: #D4D4D4">&gt;(() =&gt; </span><span style="color: #4EC9B0">CounterService</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: #6A9955">// カウンターを管理するクラス</span></span>
<span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CounterService</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">int</span><span style="color: #D4D4D4"> _counter = </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: #4EC9B0">int</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">get</span><span style="color: #D4D4D4"> counter =&gt; _counter;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">    _counter++;</span></span>
<span class="line"><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">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">main</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">setupLocator</span><span style="color: #D4D4D4">(); </span><span style="color: #6A9955">// GetItのセットアップ</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">runApp</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">MyApp</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">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">MyApp</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">extends</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">StatelessWidget</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">@override</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #4EC9B0">Widget</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">build</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">BuildContext</span><span style="color: #D4D4D4"> context) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">MaterialApp</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">      home: </span><span style="color: #4EC9B0">Scaffold</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">        appBar: </span><span style="color: #4EC9B0">AppBar</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          title: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;Dependency Injection with GetIt&#39;</span><span style="color: #D4D4D4">),</span></span>
<span class="line"><span style="color: #D4D4D4">        ),</span></span>
<span class="line"><span style="color: #D4D4D4">        body: </span><span style="color: #4EC9B0">Center</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          child: </span><span style="color: #4EC9B0">Column</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">            mainAxisAlignment: </span><span style="color: #4EC9B0">MainAxisAlignment</span><span style="color: #D4D4D4">.center,</span></span>
<span class="line"><span style="color: #D4D4D4">            children: [</span></span>
<span class="line"><span style="color: #D4D4D4">              </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Text</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: #4EC9B0">Text</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #CE9178">&#39;${</span><span style="color: #DCDCAA">locator</span><span style="color: #CE9178">&lt;</span><span style="color: #4EC9B0">CounterService</span><span style="color: #CE9178">&gt;().</span><span style="color: #9CDCFE">counter</span><span style="color: #CE9178">}&#39;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                style: </span><span style="color: #4EC9B0">TextStyle</span><span style="color: #D4D4D4">(fontSize: </span><span style="color: #B5CEA8">40</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>
<span class="line"><span style="color: #D4D4D4">          ),</span></span>
<span class="line"><span style="color: #D4D4D4">        ),</span></span>
<span class="line"><span style="color: #D4D4D4">        floatingActionButton: </span><span style="color: #4EC9B0">FloatingActionButton</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">          onPressed: () {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">locator</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">CounterService</span><span style="color: #D4D4D4">&gt;().</span><span style="color: #DCDCAA">increment</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">          },</span></span>
<span class="line"><span style="color: #D4D4D4">          child: </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Icon</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">Icons</span><span style="color: #D4D4D4">.add),</span></span>
<span class="line"><span style="color: #D4D4D4">        ),</span></span>
<span class="line"><span style="color: #D4D4D4">      ),</span></span>
<span class="line"><span style="color: #D4D4D4">    );</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h5 class="wp-block-heading">解説</h5>



<ul class="wp-block-list">
<li><strong><code>GetIt</code></strong>: <code>GetIt</code>はシングルトンパターンでインスタンスを管理し、<code>locator</code>を使ってクラスのインスタンスにアクセスします。</li>



<li><strong><code>registerLazySingleton</code></strong>: クラスのインスタンスを遅延初期化するためのメソッドです。最初にアクセスされたときに初期化されます。</li>



<li><strong><code>locator&lt;CounterService>()</code></strong>: どこからでも<code>CounterService</code>のインスタンスにアクセスできます。</li>
</ul>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="flutter getit provider di" width="1256" height="707" src="https://www.youtube.com/embed/Xd9dwQ_69NU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<h3 class="wp-block-heading"><strong>依存性注入を使うべきタイミング</strong></h3>



<p class="wp-block-paragraph">　依存性注入は、アプリケーションが大規模になり、複数のサービスやリポジトリを扱う場合に非常に有効です。小規模なアプリでは、シンプルにクラス内でインスタンスを生成するだけで済むことが多いですが、テスト可能なコードを書きたい場合や複数の環境で同じクラスを使い回す場合には、DIの導入が推奨されます。</p>



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



<p class="wp-block-paragraph">　Flutterでの依存性注入は、アプリケーションをよりモジュール化し、テスト可能で保守しやすいコードを実現するために重要な設計パターンです。<code>Provider</code>や<code>GetIt</code>を使うことで、依存性注入をシンプルかつ効率的に実装することができます。これらのツールを使いこなすことで、Flutterアプリケーションの品質を一段と高めることができるでしょう。</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://techgrowup.net/flutter%e9%96%8b%e7%99%ba%e5%85%a5%e9%96%8018-%e4%be%9d%e5%ad%98%e6%80%a7%e6%b3%a8%e5%85%a5%ef%bc%88di%ef%bc%89%e3%81%a8%e3%81%af%ef%bc%9f%e5%8a%b9%e7%8e%87%e7%9a%84%e3%81%aa%e7%8a%b6%e6%85%8b/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
