{"componentChunkName":"component---src-templates-blog-post-js","path":"/javascript/React-Next.js-완전정복-현대적-프론트엔드-개발-가이드/","result":{"data":{"site":{"siteMetadata":{"title":"Bottlehs Tech Blog","description":"웹·앱·AI 개발자 전병훈(bottlehs)의 기술 블로그. AI·LLM, JavaScript·Vue, Spring Boot, 알고리즘, 블록체인 실무 가이드를 다룹니다","siteUrl":"https://www.bottlehs.dev","author":{"name":"Jeon Byung Hun","summary":"개발을 즐기는 bottlehs - Engineer, MS, AI, FE, BE, OS, IOT, Blockchain, 설계, 테스트"},"social":{"github":"bottlehs","codepen":"bottlehs"}}},"markdownRemark":{"id":"a256bb65-5a79-57a5-b586-e2f3d50b4419","excerpt":"React와 Next.js 완전정복 - 현대적 프론트엔드 개발 실전 가이드 React는 현재 가장 인기 있는 프론트엔드 라이브러리이며, Next.js는 React 기반의 풀스택 프레임워크로 빠르게 성장하고 있다. 2024년 기준 React 생태계는 Hooks, Server…","html":"<h1 id=\"react와-nextjs-완전정복---현대적-프론트엔드-개발-실전-가이드\" style=\"position:relative;\"><a href=\"#react%EC%99%80-nextjs-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5---%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C\" aria-label=\"react와 nextjs 완전정복   현대적 프론트엔드 개발 실전 가이드 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>React와 Next.js 완전정복 - 현대적 프론트엔드 개발 실전 가이드</h1>\n<p>React는 현재 가장 인기 있는 프론트엔드 라이브러리이며, Next.js는 React 기반의 풀스택 프레임워크로 빠르게 성장하고 있다. 2024년 기준 React 생태계는 Hooks, Server Components, Suspense 등 혁신적인 기능들로 무장했다. 이 글은 React와 Next.js를 활용한 현대적 프론트엔드 개발의 모든 것을 실전 예제와 함께 다룬다.</p>\n<h2 id=\"1-react-hooks-심화\" style=\"position:relative;\"><a href=\"#1-react-hooks-%EC%8B%AC%ED%99%94\" aria-label=\"1 react hooks 심화 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. React Hooks 심화</h2>\n<h3 id=\"1-1-usestate와-usereducer-고급-활용\" style=\"position:relative;\"><a href=\"#1-1-usestate%EC%99%80-usereducer-%EA%B3%A0%EA%B8%89-%ED%99%9C%EC%9A%A9\" aria-label=\"1 1 usestate와 usereducer 고급 활용 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1-1. useState와 useReducer 고급 활용</h3>\n<h4 id=\"usestate의-함수형-업데이트\" style=\"position:relative;\"><a href=\"#usestate%EC%9D%98-%ED%95%A8%EC%88%98%ED%98%95-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8\" aria-label=\"usestate의 함수형 업데이트 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>useState의 함수형 업데이트</h4>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useCallback <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// ❌ 잘못된 사용: 클로저 문제</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">Counter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>count<span class=\"token punctuation\">,</span> setCount<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">increment</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// 여러 번 호출 시 예상과 다르게 동작</span>\n    <span class=\"token function\">setCount</span><span class=\"token punctuation\">(</span>count <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">setCount</span><span class=\"token punctuation\">(</span>count <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// count는 여전히 0</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>increment<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>Count<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>count<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// ✅ 올바른 사용: 함수형 업데이트</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">Counter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>count<span class=\"token punctuation\">,</span> setCount<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> increment <span class=\"token operator\">=</span> <span class=\"token function\">useCallback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">setCount</span><span class=\"token punctuation\">(</span>prev <span class=\"token operator\">=></span> prev <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">setCount</span><span class=\"token punctuation\">(</span>prev <span class=\"token operator\">=></span> prev <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 이전 값을 기반으로 업데이트</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>increment<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>Count<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>count<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h4 id=\"usereducer로-복잡한-상태-관리\" style=\"position:relative;\"><a href=\"#usereducer%EB%A1%9C-%EB%B3%B5%EC%9E%A1%ED%95%9C-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC\" aria-label=\"usereducer로 복잡한 상태 관리 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>useReducer로 복잡한 상태 관리</h4>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useReducer<span class=\"token punctuation\">,</span> useCallback <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">Todo</span> <span class=\"token punctuation\">{</span>\n  id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n  text<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n  completed<span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">type</span> <span class=\"token class-name\">TodoAction</span> <span class=\"token operator\">=</span>\n  <span class=\"token operator\">|</span> <span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">'ADD_TODO'</span><span class=\"token punctuation\">;</span> text<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span> <span class=\"token punctuation\">}</span>\n  <span class=\"token operator\">|</span> <span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">'TOGGLE_TODO'</span><span class=\"token punctuation\">;</span> id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span> <span class=\"token punctuation\">}</span>\n  <span class=\"token operator\">|</span> <span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">'DELETE_TODO'</span><span class=\"token punctuation\">;</span> id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span> <span class=\"token punctuation\">}</span>\n  <span class=\"token operator\">|</span> <span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">'CLEAR_COMPLETED'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">TodoState</span> <span class=\"token punctuation\">{</span>\n  todos<span class=\"token operator\">:</span> Todo<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n  filter<span class=\"token operator\">:</span> <span class=\"token string\">'all'</span> <span class=\"token operator\">|</span> <span class=\"token string\">'active'</span> <span class=\"token operator\">|</span> <span class=\"token string\">'completed'</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> initialState<span class=\"token operator\">:</span> TodoState <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  todos<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  filter<span class=\"token operator\">:</span> <span class=\"token string\">'all'</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">todoReducer</span><span class=\"token punctuation\">(</span>state<span class=\"token operator\">:</span> TodoState<span class=\"token punctuation\">,</span> action<span class=\"token operator\">:</span> TodoAction<span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> TodoState <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'ADD_TODO'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">...</span>state<span class=\"token punctuation\">,</span>\n        todos<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n          <span class=\"token operator\">...</span>state<span class=\"token punctuation\">.</span>todos<span class=\"token punctuation\">,</span>\n          <span class=\"token punctuation\">{</span>\n            id<span class=\"token operator\">:</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            text<span class=\"token operator\">:</span> action<span class=\"token punctuation\">.</span>text<span class=\"token punctuation\">,</span>\n            completed<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span>\n          <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">]</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">case</span> <span class=\"token string\">'TOGGLE_TODO'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">...</span>state<span class=\"token punctuation\">,</span>\n        todos<span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>todos<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span>todo <span class=\"token operator\">=></span>\n          todo<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> action<span class=\"token punctuation\">.</span>id\n            <span class=\"token operator\">?</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>todo<span class=\"token punctuation\">,</span> completed<span class=\"token operator\">:</span> <span class=\"token operator\">!</span>todo<span class=\"token punctuation\">.</span>completed <span class=\"token punctuation\">}</span>\n            <span class=\"token operator\">:</span> todo\n        <span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">case</span> <span class=\"token string\">'DELETE_TODO'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">...</span>state<span class=\"token punctuation\">,</span>\n        todos<span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>todos<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span>todo <span class=\"token operator\">=></span> todo<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> action<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">case</span> <span class=\"token string\">'CLEAR_COMPLETED'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">...</span>state<span class=\"token punctuation\">,</span>\n        todos<span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>todos<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span>todo <span class=\"token operator\">=></span> <span class=\"token operator\">!</span>todo<span class=\"token punctuation\">.</span>completed<span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">TodoApp</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>state<span class=\"token punctuation\">,</span> dispatch<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useReducer</span><span class=\"token punctuation\">(</span>todoReducer<span class=\"token punctuation\">,</span> initialState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> addTodo <span class=\"token operator\">=</span> <span class=\"token function\">useCallback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>text<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">'ADD_TODO'</span><span class=\"token punctuation\">,</span> text <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> toggleTodo <span class=\"token operator\">=</span> <span class=\"token function\">useCallback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> type<span class=\"token operator\">:</span> <span class=\"token string\">'TOGGLE_TODO'</span><span class=\"token punctuation\">,</span> id <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> filteredTodos <span class=\"token operator\">=</span> state<span class=\"token punctuation\">.</span>todos<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span>todo <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">.</span>filter <span class=\"token operator\">===</span> <span class=\"token string\">'active'</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token operator\">!</span>todo<span class=\"token punctuation\">.</span>completed<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">.</span>filter <span class=\"token operator\">===</span> <span class=\"token string\">'completed'</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> todo<span class=\"token punctuation\">.</span>completed<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>input\n        type<span class=\"token operator\">=</span><span class=\"token string\">\"text\"</span>\n        onKeyPress<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>key <span class=\"token operator\">===</span> <span class=\"token string\">'Enter'</span> <span class=\"token operator\">&amp;&amp;</span> e<span class=\"token punctuation\">.</span>currentTarget<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token function\">addTodo</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>currentTarget<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            e<span class=\"token punctuation\">.</span>currentTarget<span class=\"token punctuation\">.</span>value <span class=\"token operator\">=</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span>\n          <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span>\n        placeholder<span class=\"token operator\">=</span><span class=\"token string\">\"할 일 입력...\"</span>\n      <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>filteredTodos<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span>todo <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n          <span class=\"token operator\">&lt;</span>div key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>todo<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n            <span class=\"token operator\">&lt;</span>input\n              type<span class=\"token operator\">=</span><span class=\"token string\">\"checkbox\"</span>\n              checked<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>todo<span class=\"token punctuation\">.</span>completed<span class=\"token punctuation\">}</span>\n              onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">toggleTodo</span><span class=\"token punctuation\">(</span>todo<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n            <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n            <span class=\"token operator\">&lt;</span>span<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>todo<span class=\"token punctuation\">.</span>text<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>span<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"1-2-useeffect와-의존성-배열-완벽-이해\" style=\"position:relative;\"><a href=\"#1-2-useeffect%EC%99%80-%EC%9D%98%EC%A1%B4%EC%84%B1-%EB%B0%B0%EC%97%B4-%EC%99%84%EB%B2%BD-%EC%9D%B4%ED%95%B4\" aria-label=\"1 2 useeffect와 의존성 배열 완벽 이해 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1-2. useEffect와 의존성 배열 완벽 이해</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useEffect<span class=\"token punctuation\">,</span> useState<span class=\"token punctuation\">,</span> useRef <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">DataFetcher</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> userId <span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> userId<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>data<span class=\"token punctuation\">,</span> setData<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>loading<span class=\"token punctuation\">,</span> setLoading<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> abortControllerRef <span class=\"token operator\">=</span> <span class=\"token generic-function\"><span class=\"token function\">useRef</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span>AbortController <span class=\"token operator\">|</span> <span class=\"token keyword\">null</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// 이전 요청 취소</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>abortControllerRef<span class=\"token punctuation\">.</span>current<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      abortControllerRef<span class=\"token punctuation\">.</span>current<span class=\"token punctuation\">.</span><span class=\"token function\">abort</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token comment\">// 새로운 AbortController 생성</span>\n    abortControllerRef<span class=\"token punctuation\">.</span>current <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">AbortController</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> signal <span class=\"token operator\">=</span> abortControllerRef<span class=\"token punctuation\">.</span>current<span class=\"token punctuation\">.</span>signal<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/api/users/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>userId<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> signal <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>res <span class=\"token operator\">=></span> res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>data <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>signal<span class=\"token punctuation\">.</span>aborted<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token function\">setData</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">catch</span><span class=\"token punctuation\">(</span>err <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">.</span>name <span class=\"token operator\">!==</span> <span class=\"token string\">'AbortError'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Fetch error:'</span><span class=\"token punctuation\">,</span> err<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// 클린업 함수: 컴포넌트 언마운트 또는 userId 변경 시 실행</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      abortControllerRef<span class=\"token punctuation\">.</span>current<span class=\"token operator\">?.</span><span class=\"token function\">abort</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>userId<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// userId가 변경될 때만 재실행</span>\n  \n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>loading<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>data<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>No data<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">{</span><span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"1-3-커스텀-hooks-패턴\" style=\"position:relative;\"><a href=\"#1-3-%EC%BB%A4%EC%8A%A4%ED%85%80-hooks-%ED%8C%A8%ED%84%B4\" aria-label=\"1 3 커스텀 hooks 패턴 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1-3. 커스텀 Hooks 패턴</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect<span class=\"token punctuation\">,</span> useCallback<span class=\"token punctuation\">,</span> useRef <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// API 호출을 위한 커스텀 Hook</span>\n<span class=\"token keyword\">function</span> <span class=\"token generic-function\"><span class=\"token function\">useFetch</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span>url<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> options<span class=\"token operator\">?</span><span class=\"token operator\">:</span> RequestInit<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>data<span class=\"token punctuation\">,</span> setData<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token generic-function\"><span class=\"token function\">useState</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">null</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>loading<span class=\"token punctuation\">,</span> setLoading<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>error<span class=\"token punctuation\">,</span> setError<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token generic-function\"><span class=\"token function\">useState</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span>Error <span class=\"token operator\">|</span> <span class=\"token keyword\">null</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> abortControllerRef <span class=\"token operator\">=</span> <span class=\"token generic-function\"><span class=\"token function\">useRef</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span>AbortController <span class=\"token operator\">|</span> <span class=\"token keyword\">null</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> refetch <span class=\"token operator\">=</span> <span class=\"token function\">useCallback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>abortControllerRef<span class=\"token punctuation\">.</span>current<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      abortControllerRef<span class=\"token punctuation\">.</span>current<span class=\"token punctuation\">.</span><span class=\"token function\">abort</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    abortControllerRef<span class=\"token punctuation\">.</span>current <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">AbortController</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> signal <span class=\"token operator\">=</span> abortControllerRef<span class=\"token punctuation\">.</span>current<span class=\"token punctuation\">.</span>signal<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">setError</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>url<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>options<span class=\"token punctuation\">,</span> signal <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">async</span> res <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>res<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">HTTP error! status: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>res<span class=\"token punctuation\">.</span>status<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>data <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>signal<span class=\"token punctuation\">.</span>aborted<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token function\">setData</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">catch</span><span class=\"token punctuation\">(</span>err <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">.</span>name <span class=\"token operator\">!==</span> <span class=\"token string\">'AbortError'</span> <span class=\"token operator\">&amp;&amp;</span> <span class=\"token operator\">!</span>signal<span class=\"token punctuation\">.</span>aborted<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token function\">setError</span><span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          <span class=\"token function\">setLoading</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>url<span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">refetch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      abortControllerRef<span class=\"token punctuation\">.</span>current<span class=\"token operator\">?.</span><span class=\"token function\">abort</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>refetch<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">,</span> loading<span class=\"token punctuation\">,</span> error<span class=\"token punctuation\">,</span> refetch <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 사용 예시</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">UserProfile</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> userId <span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> userId<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">,</span> loading<span class=\"token punctuation\">,</span> error<span class=\"token punctuation\">,</span> refetch <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token generic-function\"><span class=\"token function\">useFetch</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span>User<span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span>\n    <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/api/users/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>userId<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>loading<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Error<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>error<span class=\"token punctuation\">.</span>message<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>data<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>No data<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>h1<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>data<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h1<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>refetch<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>새로고침<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 로컬 스토리지 동기화 Hook</span>\n<span class=\"token keyword\">function</span> <span class=\"token generic-function\"><span class=\"token function\">useLocalStorage</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span>key<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> initialValue<span class=\"token operator\">:</span> <span class=\"token constant\">T</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>storedValue<span class=\"token punctuation\">,</span> setStoredValue<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token generic-function\"><span class=\"token function\">useState</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span><span class=\"token constant\">T</span><span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> item <span class=\"token operator\">=</span> window<span class=\"token punctuation\">.</span>localStorage<span class=\"token punctuation\">.</span><span class=\"token function\">getItem</span><span class=\"token punctuation\">(</span>key<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">return</span> item <span class=\"token operator\">?</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> initialValue<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">return</span> initialValue<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> setValue <span class=\"token operator\">=</span> <span class=\"token function\">useCallback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>value<span class=\"token operator\">:</span> <span class=\"token constant\">T</span> <span class=\"token operator\">|</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>val<span class=\"token operator\">:</span> <span class=\"token constant\">T</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token constant\">T</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> valueToStore <span class=\"token operator\">=</span> value <span class=\"token keyword\">instanceof</span> <span class=\"token class-name\"><span class=\"token builtin\">Function</span></span> \n        <span class=\"token operator\">?</span> <span class=\"token function\">value</span><span class=\"token punctuation\">(</span>storedValue<span class=\"token punctuation\">)</span> \n        <span class=\"token operator\">:</span> value<span class=\"token punctuation\">;</span>\n      <span class=\"token function\">setStoredValue</span><span class=\"token punctuation\">(</span>valueToStore<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      window<span class=\"token punctuation\">.</span>localStorage<span class=\"token punctuation\">.</span><span class=\"token function\">setItem</span><span class=\"token punctuation\">(</span>key<span class=\"token punctuation\">,</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>valueToStore<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">,</span> storedValue<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">[</span>storedValue<span class=\"token punctuation\">,</span> setValue<span class=\"token punctuation\">]</span> <span class=\"token keyword\">as</span> <span class=\"token keyword\">const</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 사용 예시</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">Settings</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>theme<span class=\"token punctuation\">,</span> setTheme<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useLocalStorage</span><span class=\"token punctuation\">(</span><span class=\"token string\">'theme'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'light'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>select value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>theme<span class=\"token punctuation\">}</span> onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setTheme</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>option value<span class=\"token operator\">=</span><span class=\"token string\">\"light\"</span><span class=\"token operator\">></span>Light<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>option<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>option value<span class=\"token operator\">=</span><span class=\"token string\">\"dark\"</span><span class=\"token operator\">></span>Dark<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>option<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>select<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"1-4-usememo와-usecallback-최적화\" style=\"position:relative;\"><a href=\"#1-4-usememo%EC%99%80-usecallback-%EC%B5%9C%EC%A0%81%ED%99%94\" aria-label=\"1 4 usememo와 usecallback 최적화 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1-4. useMemo와 useCallback 최적화</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useMemo<span class=\"token punctuation\">,</span> useCallback<span class=\"token punctuation\">,</span> memo <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">Product</span> <span class=\"token punctuation\">{</span>\n  id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n  name<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n  price<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n  category<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProductList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> products<span class=\"token punctuation\">,</span> filter<span class=\"token punctuation\">,</span> onProductClick <span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n  products<span class=\"token operator\">:</span> Product<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n  filter<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">onProductClick</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// 필터링된 제품 목록을 메모이제이션</span>\n  <span class=\"token keyword\">const</span> filteredProducts <span class=\"token operator\">=</span> <span class=\"token function\">useMemo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Filtering products...'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> products<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span>product <span class=\"token operator\">=></span>\n      product<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">.</span><span class=\"token function\">toLowerCase</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span>filter<span class=\"token punctuation\">.</span><span class=\"token function\">toLowerCase</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>products<span class=\"token punctuation\">,</span> filter<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// 정렬된 제품 목록</span>\n  <span class=\"token keyword\">const</span> sortedProducts <span class=\"token operator\">=</span> <span class=\"token function\">useMemo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>filteredProducts<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span><span class=\"token function\">sort</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>a<span class=\"token punctuation\">,</span> b<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> a<span class=\"token punctuation\">.</span>price <span class=\"token operator\">-</span> b<span class=\"token punctuation\">.</span>price<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>filteredProducts<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// 총 가격 계산</span>\n  <span class=\"token keyword\">const</span> totalPrice <span class=\"token operator\">=</span> <span class=\"token function\">useMemo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> sortedProducts<span class=\"token punctuation\">.</span><span class=\"token function\">reduce</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>sum<span class=\"token punctuation\">,</span> product<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> sum <span class=\"token operator\">+</span> product<span class=\"token punctuation\">.</span>price<span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>sortedProducts<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>총 <span class=\"token punctuation\">{</span>sortedProducts<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">}</span>개 제품<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>총 가격<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>totalPrice<span class=\"token punctuation\">.</span><span class=\"token function\">toLocaleString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>원<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>sortedProducts<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span>product <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n        <span class=\"token operator\">&lt;</span>ProductItem\n          key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>product<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span>\n          product<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>product<span class=\"token punctuation\">}</span>\n          onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>onProductClick<span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 메모이제이션된 자식 컴포넌트</span>\n<span class=\"token keyword\">const</span> ProductItem <span class=\"token operator\">=</span> <span class=\"token function\">memo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> product<span class=\"token punctuation\">,</span> onClick <span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n  product<span class=\"token operator\">:</span> Product<span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">onClick</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> handleClick <span class=\"token operator\">=</span> <span class=\"token function\">useCallback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">onClick</span><span class=\"token punctuation\">(</span>product<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>product<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">,</span> onClick<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>handleClick<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>h3<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>product<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h3<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>product<span class=\"token punctuation\">.</span>price<span class=\"token punctuation\">.</span><span class=\"token function\">toLocaleString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>원<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h2 id=\"2-react-server-components와-nextjs-14-app-router\" style=\"position:relative;\"><a href=\"#2-react-server-components%EC%99%80-nextjs-14-app-router\" aria-label=\"2 react server components와 nextjs 14 app router permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2. React Server Components와 Next.js 14 App Router</h2>\n<h3 id=\"2-1-server-components-vs-client-components\" style=\"position:relative;\"><a href=\"#2-1-server-components-vs-client-components\" aria-label=\"2 1 server components vs client components permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2-1. Server Components vs Client Components</h3>\n<p>Next.js 13+에서는 기본적으로 모든 컴포넌트가 Server Component다. 클라이언트 기능이 필요할 때만 <code class=\"language-text\">'use client'</code> 지시어를 사용한다.</p>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token comment\">// app/components/ServerComponent.tsx</span>\n<span class=\"token comment\">// Server Component (기본값)</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> db <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/lib/db'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">ServerComponent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// 서버에서 직접 데이터베이스 접근</span>\n  <span class=\"token keyword\">const</span> data <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> db<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span><span class=\"token string\">'SELECT * FROM products'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>h1<span class=\"token operator\">></span>Server Component<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h1<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>data<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span>item <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n          <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>item<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">{</span>item<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// app/components/ClientComponent.tsx</span>\n<span class=\"token string\">'use client'</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 클라이언트 컴포넌트로 명시</span>\n\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">ClientComponent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>count<span class=\"token punctuation\">,</span> setCount<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setCount</span><span class=\"token punctuation\">(</span>count <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        Count<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>count<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"2-2-nextjs-14-app-router-구조\" style=\"position:relative;\"><a href=\"#2-2-nextjs-14-app-router-%EA%B5%AC%EC%A1%B0\" aria-label=\"2 2 nextjs 14 app router 구조 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2-2. Next.js 14 App Router 구조</h3>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">app/\n  layout.tsx          # 루트 레이아웃\n  page.tsx            # 홈 페이지\n  loading.tsx         # 로딩 UI\n  error.tsx           # 에러 UI\n  not-found.tsx       # 404 페이지\n  \n  products/\n    layout.tsx        # products 레이아웃\n    page.tsx          # /products 페이지\n    [id]/\n      page.tsx        # /products/[id] 동적 라우트\n      loading.tsx      # 로딩 UI\n      error.tsx        # 에러 UI\n    \n  api/\n    users/\n      route.ts        # API 라우트</code></pre></div>\n<h3 id=\"2-3-app-router-실전-예제\" style=\"position:relative;\"><a href=\"#2-3-app-router-%EC%8B%A4%EC%A0%84-%EC%98%88%EC%A0%9C\" aria-label=\"2 3 app router 실전 예제 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2-3. App Router 실전 예제</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token comment\">// app/layout.tsx</span>\n<span class=\"token keyword\">import</span> <span class=\"token keyword\">type</span> <span class=\"token punctuation\">{</span> Metadata <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'next'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Inter <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'next/font/google'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token string\">'./globals.css'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> inter <span class=\"token operator\">=</span> <span class=\"token function\">Inter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> subsets<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'latin'</span><span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> metadata<span class=\"token operator\">:</span> Metadata <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  title<span class=\"token operator\">:</span> <span class=\"token string\">'My App'</span><span class=\"token punctuation\">,</span>\n  description<span class=\"token operator\">:</span> <span class=\"token string\">'Next.js 14 App Router Example'</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">RootLayout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  children<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n  children<span class=\"token operator\">:</span> React<span class=\"token punctuation\">.</span>ReactNode<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>html lang<span class=\"token operator\">=</span><span class=\"token string\">\"ko\"</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>body className<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>inter<span class=\"token punctuation\">.</span>className<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>nav<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>a href<span class=\"token operator\">=</span><span class=\"token string\">\"/\"</span><span class=\"token operator\">></span>Home<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>a<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>a href<span class=\"token operator\">=</span><span class=\"token string\">\"/products\"</span><span class=\"token operator\">></span>Products<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>a<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>nav<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>children<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>body<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>html<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// app/products/page.tsx</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Suspense <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> ProductList <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/components/ProductList'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> ProductListSkeleton <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/components/ProductListSkeleton'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">ProductsPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>h1<span class=\"token operator\">></span>Products<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h1<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>Suspense fallback<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>ProductListSkeleton <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>ProductList <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Suspense<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// app/products/[id]/page.tsx</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> notFound <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'next/navigation'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> db <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/lib/db'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">ProductPageProps</span> <span class=\"token punctuation\">{</span>\n  params<span class=\"token operator\">:</span> <span class=\"token builtin\">Promise</span><span class=\"token operator\">&lt;</span><span class=\"token punctuation\">{</span> id<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span> <span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">ProductPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> params <span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> ProductPageProps<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> id <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> params<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> product <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> db<span class=\"token punctuation\">.</span>product<span class=\"token punctuation\">.</span><span class=\"token function\">findUnique</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    where<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> id<span class=\"token operator\">:</span> <span class=\"token function\">parseInt</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>product<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">notFound</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>h1<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>product<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h1<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>product<span class=\"token punctuation\">.</span>description<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span>가격<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>product<span class=\"token punctuation\">.</span>price<span class=\"token punctuation\">.</span><span class=\"token function\">toLocaleString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>원<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// app/products/[id]/loading.tsx</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">Loading</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>제품 정보를 불러오는 중<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// app/products/[id]/error.tsx</span>\n<span class=\"token string\">'use client'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">Error</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  error<span class=\"token punctuation\">,</span>\n  reset<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n  error<span class=\"token operator\">:</span> Error <span class=\"token operator\">&amp;</span> <span class=\"token punctuation\">{</span> digest<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">reset</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>error<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>h2<span class=\"token operator\">></span>문제가 발생했습니다<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h2<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">reset</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>다시 시도<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"2-4-streaming과-suspense\" style=\"position:relative;\"><a href=\"#2-4-streaming%EA%B3%BC-suspense\" aria-label=\"2 4 streaming과 suspense permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2-4. Streaming과 Suspense</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token comment\">// app/dashboard/page.tsx</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Suspense <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> RevenueChart <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/components/RevenueChart'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> SalesTable <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/components/SalesTable'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> StatsCards <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/components/StatsCards'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">DashboardPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>h1<span class=\"token operator\">></span>대시보드<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h1<span class=\"token operator\">></span>\n      \n      <span class=\"token punctuation\">{</span><span class=\"token comment\">/* 즉시 렌더링 */</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>Suspense fallback<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>StatsCardsSkeleton <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>StatsCards <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Suspense<span class=\"token operator\">></span>\n      \n      <span class=\"token punctuation\">{</span><span class=\"token comment\">/* 병렬 로딩 */</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>div style<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> display<span class=\"token operator\">:</span> <span class=\"token string\">'grid'</span><span class=\"token punctuation\">,</span> gridTemplateColumns<span class=\"token operator\">:</span> <span class=\"token string\">'1fr 1fr'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>Suspense fallback<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>ChartSkeleton <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>RevenueChart <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Suspense<span class=\"token operator\">></span>\n        \n        <span class=\"token operator\">&lt;</span>Suspense fallback<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>TableSkeleton <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>SalesTable <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Suspense<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// app/components/RevenueChart.tsx</span>\n<span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">RevenueChart</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// 느린 데이터베이스 쿼리</span>\n  <span class=\"token keyword\">await</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\"><span class=\"token builtin\">Promise</span></span><span class=\"token punctuation\">(</span>resolve <span class=\"token operator\">=></span> <span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span>resolve<span class=\"token punctuation\">,</span> <span class=\"token number\">2000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> data <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetchRevenueData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>차트 렌더링<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"3-데이터-페칭과-상태-관리\" style=\"position:relative;\"><a href=\"#3-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%8E%98%EC%B9%AD%EA%B3%BC-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC\" aria-label=\"3 데이터 페칭과 상태 관리 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3. 데이터 페칭과 상태 관리</h2>\n<h3 id=\"3-1-react-query-tanstack-query-완전-정리\" style=\"position:relative;\"><a href=\"#3-1-react-query-tanstack-query-%EC%99%84%EC%A0%84-%EC%A0%95%EB%A6%AC\" aria-label=\"3 1 react query tanstack query 완전 정리 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3-1. React Query (TanStack Query) 완전 정리</h3>\n<p>React Query는 서버 상태 관리를 위한 강력한 라이브러리다.</p>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token comment\">// app/providers.tsx</span>\n<span class=\"token string\">'use client'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> QueryClient<span class=\"token punctuation\">,</span> QueryClientProvider <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@tanstack/react-query'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> ReactQueryDevtools <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@tanstack/react-query-devtools'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">Providers</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> children <span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> children<span class=\"token operator\">:</span> React<span class=\"token punctuation\">.</span>ReactNode <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>queryClient<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span>\n    <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span>\n      <span class=\"token keyword\">new</span> <span class=\"token class-name\">QueryClient</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        defaultOptions<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n          queries<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n            staleTime<span class=\"token operator\">:</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 1분</span>\n            gcTime<span class=\"token operator\">:</span> <span class=\"token number\">5</span> <span class=\"token operator\">*</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 5분 (이전 cacheTime)</span>\n            refetchOnWindowFocus<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n            retry<span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>QueryClientProvider client<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>queryClient<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>children<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>ReactQueryDevtools initialIsOpen<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>QueryClientProvider<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// hooks/useProducts.ts</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useQuery<span class=\"token punctuation\">,</span> useMutation<span class=\"token punctuation\">,</span> useQueryClient <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@tanstack/react-query'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">Product</span> <span class=\"token punctuation\">{</span>\n  id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n  name<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n  price<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 제품 목록 조회</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">useProducts</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token function\">useQuery</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    queryKey<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'products'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">queryFn</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> res <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'/api/products'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>res<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to fetch products'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> <span class=\"token builtin\">Promise</span><span class=\"token operator\">&lt;</span>Product<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 단일 제품 조회</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">useProduct</span><span class=\"token punctuation\">(</span>id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token function\">useQuery</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    queryKey<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'products'</span><span class=\"token punctuation\">,</span> id<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">queryFn</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> res <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/api/products/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>id<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>res<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to fetch product'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> <span class=\"token builtin\">Promise</span><span class=\"token operator\">&lt;</span>Product<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    enabled<span class=\"token operator\">:</span> <span class=\"token operator\">!</span><span class=\"token operator\">!</span>id<span class=\"token punctuation\">,</span> <span class=\"token comment\">// id가 있을 때만 실행</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 제품 생성</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">useCreateProduct</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> queryClient <span class=\"token operator\">=</span> <span class=\"token function\">useQueryClient</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token function\">useMutation</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    mutationFn<span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span>newProduct<span class=\"token operator\">:</span> Omit<span class=\"token operator\">&lt;</span>Product<span class=\"token punctuation\">,</span> <span class=\"token string\">'id'</span><span class=\"token operator\">></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> res <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'/api/products'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n        method<span class=\"token operator\">:</span> <span class=\"token string\">'POST'</span><span class=\"token punctuation\">,</span>\n        headers<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> <span class=\"token string-property property\">'Content-Type'</span><span class=\"token operator\">:</span> <span class=\"token string\">'application/json'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        body<span class=\"token operator\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>newProduct<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>res<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to create product'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> <span class=\"token builtin\">Promise</span><span class=\"token operator\">&lt;</span>Product<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">onSuccess</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// 제품 목록 캐시 무효화</span>\n      queryClient<span class=\"token punctuation\">.</span><span class=\"token function\">invalidateQueries</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> queryKey<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'products'</span><span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 제품 업데이트</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">useUpdateProduct</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> queryClient <span class=\"token operator\">=</span> <span class=\"token function\">useQueryClient</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token function\">useMutation</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token function-variable function\">mutationFn</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> id<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>updates <span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> Partial<span class=\"token operator\">&lt;</span>Product<span class=\"token operator\">></span> <span class=\"token operator\">&amp;</span> <span class=\"token punctuation\">{</span> id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> res <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/api/products/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>id<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n        method<span class=\"token operator\">:</span> <span class=\"token string\">'PATCH'</span><span class=\"token punctuation\">,</span>\n        headers<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> <span class=\"token string-property property\">'Content-Type'</span><span class=\"token operator\">:</span> <span class=\"token string\">'application/json'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        body<span class=\"token operator\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>updates<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>res<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to update product'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> <span class=\"token builtin\">Promise</span><span class=\"token operator\">&lt;</span>Product<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">onSuccess</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// 특정 제품 캐시 업데이트</span>\n      queryClient<span class=\"token punctuation\">.</span><span class=\"token function\">setQueryData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token string\">'products'</span><span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token comment\">// 제품 목록 캐시 무효화</span>\n      queryClient<span class=\"token punctuation\">.</span><span class=\"token function\">invalidateQueries</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> queryKey<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'products'</span><span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 사용 예시</span>\n<span class=\"token string\">'use client'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useProducts<span class=\"token punctuation\">,</span> useCreateProduct <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/hooks/useProducts'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">ProductsPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data<span class=\"token operator\">:</span> products<span class=\"token punctuation\">,</span> isLoading<span class=\"token punctuation\">,</span> error <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useProducts</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> createProduct <span class=\"token operator\">=</span> <span class=\"token function\">useCreateProduct</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>isLoading<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Error<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>error<span class=\"token punctuation\">.</span>message<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleCreate</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    createProduct<span class=\"token punctuation\">.</span><span class=\"token function\">mutate</span><span class=\"token punctuation\">(</span>\n      <span class=\"token punctuation\">{</span> name<span class=\"token operator\">:</span> <span class=\"token string\">'New Product'</span><span class=\"token punctuation\">,</span> price<span class=\"token operator\">:</span> <span class=\"token number\">10000</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token function-variable function\">onSuccess</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Product created!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token function-variable function\">onError</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to create:'</span><span class=\"token punctuation\">,</span> error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>handleCreate<span class=\"token punctuation\">}</span> disabled<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>createProduct<span class=\"token punctuation\">.</span>isPending<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>createProduct<span class=\"token punctuation\">.</span>isPending <span class=\"token operator\">?</span> <span class=\"token string\">'Creating...'</span> <span class=\"token operator\">:</span> <span class=\"token string\">'Create Product'</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>products<span class=\"token operator\">?.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span>product <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n          <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>product<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n            <span class=\"token punctuation\">{</span>product<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">}</span> <span class=\"token operator\">-</span> <span class=\"token punctuation\">{</span>product<span class=\"token punctuation\">.</span>price<span class=\"token punctuation\">}</span>원\n          <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"3-2-infinite-queries-무한-스크롤\" style=\"position:relative;\"><a href=\"#3-2-infinite-queries-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4\" aria-label=\"3 2 infinite queries 무한 스크롤 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3-2. Infinite Queries (무한 스크롤)</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useInfiniteQuery <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@tanstack/react-query'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">Post</span> <span class=\"token punctuation\">{</span>\n  id<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n  title<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n  content<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">PostsResponse</span> <span class=\"token punctuation\">{</span>\n  posts<span class=\"token operator\">:</span> Post<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n  nextCursor<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">useInfinitePosts</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token function\">useInfiniteQuery</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    queryKey<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'posts'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'infinite'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">queryFn</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> pageParam <span class=\"token operator\">=</span> <span class=\"token number\">0</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> res <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/api/posts?cursor=</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>pageParam<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">&amp;limit=10</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>res<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to fetch posts'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">as</span> <span class=\"token builtin\">Promise</span><span class=\"token operator\">&lt;</span>PostsResponse<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">getNextPageParam</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>lastPage<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> lastPage<span class=\"token punctuation\">.</span>nextCursor<span class=\"token punctuation\">,</span>\n    initialPageParam<span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 사용 예시</span>\n<span class=\"token string\">'use client'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useInfinitePosts <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/hooks/useInfinitePosts'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useIntersectionObserver <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/hooks/useIntersectionObserver'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useRef <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">InfinitePostsList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>\n    data<span class=\"token punctuation\">,</span>\n    fetchNextPage<span class=\"token punctuation\">,</span>\n    hasNextPage<span class=\"token punctuation\">,</span>\n    isFetchingNextPage<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useInfinitePosts</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> loadMoreRef <span class=\"token operator\">=</span> <span class=\"token generic-function\"><span class=\"token function\">useRef</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span>HTMLDivElement<span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token function\">useIntersectionObserver</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    target<span class=\"token operator\">:</span> loadMoreRef<span class=\"token punctuation\">,</span>\n    onIntersect<span class=\"token operator\">:</span> fetchNextPage<span class=\"token punctuation\">,</span>\n    enabled<span class=\"token operator\">:</span> <span class=\"token operator\">!</span><span class=\"token operator\">!</span>hasNextPage<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> posts <span class=\"token operator\">=</span> data<span class=\"token operator\">?.</span>pages<span class=\"token punctuation\">.</span><span class=\"token function\">flatMap</span><span class=\"token punctuation\">(</span>page <span class=\"token operator\">=></span> page<span class=\"token punctuation\">.</span>posts<span class=\"token punctuation\">)</span> <span class=\"token operator\">??</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>posts<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span>post <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n        <span class=\"token operator\">&lt;</span>article key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>h2<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>title<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h2<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>post<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>article<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      \n      <span class=\"token operator\">&lt;</span>div ref<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>loadMoreRef<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>isFetchingNextPage <span class=\"token operator\">&amp;&amp;</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading more<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">{</span><span class=\"token operator\">!</span>hasNextPage <span class=\"token operator\">&amp;&amp;</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>No more posts<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"3-3-optimistic-updates\" style=\"position:relative;\"><a href=\"#3-3-optimistic-updates\" aria-label=\"3 3 optimistic updates permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3-3. Optimistic Updates</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">useLikePost</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> queryClient <span class=\"token operator\">=</span> <span class=\"token function\">useQueryClient</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token function\">useMutation</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token function-variable function\">mutationFn</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span>postId<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> res <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/api/posts/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>postId<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">/like</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n        method<span class=\"token operator\">:</span> <span class=\"token string\">'POST'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>res<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to like post'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">onMutate</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span>postId<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// 진행 중인 쿼리 취소</span>\n      <span class=\"token keyword\">await</span> queryClient<span class=\"token punctuation\">.</span><span class=\"token function\">cancelQueries</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> queryKey<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'posts'</span><span class=\"token punctuation\">,</span> postId<span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      \n      <span class=\"token comment\">// 이전 값 백업</span>\n      <span class=\"token keyword\">const</span> previousPost <span class=\"token operator\">=</span> queryClient<span class=\"token punctuation\">.</span><span class=\"token function\">getQueryData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token string\">'posts'</span><span class=\"token punctuation\">,</span> postId<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      \n      <span class=\"token comment\">// 낙관적 업데이트</span>\n      queryClient<span class=\"token punctuation\">.</span><span class=\"token function\">setQueryData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token string\">'posts'</span><span class=\"token punctuation\">,</span> postId<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span>old<span class=\"token operator\">:</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">...</span>old<span class=\"token punctuation\">,</span>\n        likes<span class=\"token operator\">:</span> old<span class=\"token punctuation\">.</span>likes <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        isLiked<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      \n      <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> previousPost <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">onError</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">,</span> postId<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// 에러 시 롤백</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>context<span class=\"token operator\">?.</span>previousPost<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        queryClient<span class=\"token punctuation\">.</span><span class=\"token function\">setQueryData</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token string\">'posts'</span><span class=\"token punctuation\">,</span> postId<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">.</span>previousPost<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">onSettled</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">,</span> error<span class=\"token punctuation\">,</span> postId<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// 최종적으로 서버 데이터로 동기화</span>\n      queryClient<span class=\"token punctuation\">.</span><span class=\"token function\">invalidateQueries</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> queryKey<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'posts'</span><span class=\"token punctuation\">,</span> postId<span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"4-상태-관리-라이브러리-비교\" style=\"position:relative;\"><a href=\"#4-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EB%B9%84%EA%B5%90\" aria-label=\"4 상태 관리 라이브러리 비교 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4. 상태 관리 라이브러리 비교</h2>\n<h3 id=\"4-1-zustand---가벼운-상태-관리\" style=\"position:relative;\"><a href=\"#4-1-zustand---%EA%B0%80%EB%B2%BC%EC%9A%B4-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC\" aria-label=\"4 1 zustand   가벼운 상태 관리 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4-1. Zustand - 가벼운 상태 관리</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> create <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'zustand'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> devtools<span class=\"token punctuation\">,</span> persist <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'zustand/middleware'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">BearState</span> <span class=\"token punctuation\">{</span>\n  bears<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">increase</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>by<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n  <span class=\"token function-variable function\">decrease</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>by<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">void</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> useBearStore <span class=\"token operator\">=</span> <span class=\"token generic-function\"><span class=\"token function\">create</span><span class=\"token generic class-name\"><span class=\"token operator\">&lt;</span>BearState<span class=\"token operator\">></span></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span>\n  <span class=\"token function\">devtools</span><span class=\"token punctuation\">(</span>\n    <span class=\"token function\">persist</span><span class=\"token punctuation\">(</span>\n      <span class=\"token punctuation\">(</span>set<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        bears<span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token function-variable function\">increase</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>by<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">set</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> bears<span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>bears <span class=\"token operator\">+</span> by <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token function-variable function\">decrease</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>by<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">set</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> bears<span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>bears <span class=\"token operator\">-</span> by <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">{</span>\n        name<span class=\"token operator\">:</span> <span class=\"token string\">'bear-storage'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// localStorage 키</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span> name<span class=\"token operator\">:</span> <span class=\"token string\">'BearStore'</span> <span class=\"token punctuation\">}</span> <span class=\"token comment\">// Redux DevTools 이름</span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 사용 예시</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">BearCounter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> bears <span class=\"token operator\">=</span> <span class=\"token function\">useBearStore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>bears<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> increase <span class=\"token operator\">=</span> <span class=\"token function\">useBearStore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>increase<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>h1<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>bears<span class=\"token punctuation\">}</span> bears around here<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h1<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">increase</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>Add bear<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"4-2-jotai---원자적-상태-관리\" style=\"position:relative;\"><a href=\"#4-2-jotai---%EC%9B%90%EC%9E%90%EC%A0%81-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC\" aria-label=\"4 2 jotai   원자적 상태 관리 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4-2. Jotai - 원자적 상태 관리</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> atom<span class=\"token punctuation\">,</span> useAtom<span class=\"token punctuation\">,</span> useAtomValue<span class=\"token punctuation\">,</span> useSetAtom <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'jotai'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> atomWithStorage <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'jotai/utils'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 기본 atom</span>\n<span class=\"token keyword\">const</span> countAtom <span class=\"token operator\">=</span> <span class=\"token function\">atom</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 파생 atom</span>\n<span class=\"token keyword\">const</span> doubledCountAtom <span class=\"token operator\">=</span> <span class=\"token function\">atom</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>get<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">get</span><span class=\"token punctuation\">(</span>countAtom<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 비동기 atom</span>\n<span class=\"token keyword\">const</span> userAtom <span class=\"token operator\">=</span> <span class=\"token function\">atom</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> res <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'/api/user'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// localStorage와 동기화</span>\n<span class=\"token keyword\">const</span> themeAtom <span class=\"token operator\">=</span> <span class=\"token function\">atomWithStorage</span><span class=\"token punctuation\">(</span><span class=\"token string\">'theme'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'light'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 사용 예시</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">Counter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>count<span class=\"token punctuation\">,</span> setCount<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useAtom</span><span class=\"token punctuation\">(</span>countAtom<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> doubled <span class=\"token operator\">=</span> <span class=\"token function\">useAtomValue</span><span class=\"token punctuation\">(</span>doubledCountAtom<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span>Count<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>count<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span>Doubled<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>doubled<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setCount</span><span class=\"token punctuation\">(</span>c <span class=\"token operator\">=></span> c <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>Increment<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"5-성능-최적화\" style=\"position:relative;\"><a href=\"#5-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94\" aria-label=\"5 성능 최적화 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5. 성능 최적화</h2>\n<h3 id=\"5-1-코드-스플리팅과-레이지-로딩\" style=\"position:relative;\"><a href=\"#5-1-%EC%BD%94%EB%93%9C-%EC%8A%A4%ED%94%8C%EB%A6%AC%ED%8C%85%EA%B3%BC-%EB%A0%88%EC%9D%B4%EC%A7%80-%EB%A1%9C%EB%94%A9\" aria-label=\"5 1 코드 스플리팅과 레이지 로딩 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5-1. 코드 스플리팅과 레이지 로딩</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> lazy<span class=\"token punctuation\">,</span> Suspense <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 동적 import로 컴포넌트 레이지 로딩</span>\n<span class=\"token keyword\">const</span> HeavyComponent <span class=\"token operator\">=</span> <span class=\"token function\">lazy</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">import</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./HeavyComponent'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> ChartComponent <span class=\"token operator\">=</span> <span class=\"token function\">lazy</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">import</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./ChartComponent'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">App</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>showChart<span class=\"token punctuation\">,</span> setShowChart<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>Suspense fallback<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading component<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>HeavyComponent <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Suspense<span class=\"token operator\">></span>\n      \n      <span class=\"token punctuation\">{</span>showChart <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span>\n        <span class=\"token operator\">&lt;</span>Suspense fallback<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>Loading chart<span class=\"token operator\">...</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>ChartComponent <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Suspense<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      \n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setShowChart</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>Show Chart<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"5-2-이미지-최적화\" style=\"position:relative;\"><a href=\"#5-2-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%B5%9C%EC%A0%81%ED%99%94\" aria-label=\"5 2 이미지 최적화 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5-2. 이미지 최적화</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> Image <span class=\"token keyword\">from</span> <span class=\"token string\">'next/image'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">OptimizedImage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Image\n      src<span class=\"token operator\">=</span><span class=\"token string\">\"/hero.jpg\"</span>\n      alt<span class=\"token operator\">=</span><span class=\"token string\">\"Hero image\"</span>\n      width<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token number\">800</span><span class=\"token punctuation\">}</span>\n      height<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token number\">600</span><span class=\"token punctuation\">}</span>\n      priority <span class=\"token comment\">// 우선 로딩</span>\n      placeholder<span class=\"token operator\">=</span><span class=\"token string\">\"blur\"</span> <span class=\"token comment\">// 블러 플레이스홀더</span>\n      blurDataURL<span class=\"token operator\">=</span><span class=\"token string\">\"data:image/jpeg;base64,...\"</span>\n      sizes<span class=\"token operator\">=</span><span class=\"token string\">\"(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw\"</span>\n    <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"5-3-번들-분석\" style=\"position:relative;\"><a href=\"#5-3-%EB%B2%88%EB%93%A4-%EB%B6%84%EC%84%9D\" aria-label=\"5 3 번들 분석 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5-3. 번들 분석</h3>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># Next.js 번들 분석</span>\n<span class=\"token function\">npm</span> <span class=\"token function\">install</span> @next/bundle-analyzer\n\n<span class=\"token comment\"># next.config.js</span>\nconst withBundleAnalyzer <span class=\"token operator\">=</span> require<span class=\"token punctuation\">(</span><span class=\"token string\">'@next/bundle-analyzer'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  enabled: process.env.ANALYZE <span class=\"token operator\">==</span><span class=\"token operator\">=</span> <span class=\"token string\">'true'</span>,\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nmodule.exports <span class=\"token operator\">=</span> withBundleAnalyzer<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  // Next.js 설정\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\"># 분석 실행</span>\n<span class=\"token assign-left variable\">ANALYZE</span><span class=\"token operator\">=</span>true <span class=\"token function\">npm</span> run build</code></pre></div>\n<h2 id=\"6-nextjs-api-routes와-server-actions\" style=\"position:relative;\"><a href=\"#6-nextjs-api-routes%EC%99%80-server-actions\" aria-label=\"6 nextjs api routes와 server actions permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6. Next.js API Routes와 Server Actions</h2>\n<h3 id=\"6-1-api-routes\" style=\"position:relative;\"><a href=\"#6-1-api-routes\" aria-label=\"6 1 api routes permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6-1. API Routes</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token comment\">// app/api/users/route.ts</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> NextRequest<span class=\"token punctuation\">,</span> NextResponse <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'next/server'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> db <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/lib/db'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span>request<span class=\"token operator\">:</span> NextRequest<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> searchParams <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>nextUrl<span class=\"token punctuation\">.</span>searchParams<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> page <span class=\"token operator\">=</span> <span class=\"token function\">parseInt</span><span class=\"token punctuation\">(</span>searchParams<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">'page'</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">||</span> <span class=\"token string\">'1'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> limit <span class=\"token operator\">=</span> <span class=\"token function\">parseInt</span><span class=\"token punctuation\">(</span>searchParams<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">'limit'</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">||</span> <span class=\"token string\">'10'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> users <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> db<span class=\"token punctuation\">.</span>user<span class=\"token punctuation\">.</span><span class=\"token function\">findMany</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    skip<span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>page <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> limit<span class=\"token punctuation\">,</span>\n    take<span class=\"token operator\">:</span> limit<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> NextResponse<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> users <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token constant\">POST</span><span class=\"token punctuation\">(</span>request<span class=\"token operator\">:</span> NextRequest<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> body <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> request<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> user <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> db<span class=\"token punctuation\">.</span>user<span class=\"token punctuation\">.</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    data<span class=\"token operator\">:</span> body<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> NextResponse<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span>user<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> status<span class=\"token operator\">:</span> <span class=\"token number\">201</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"6-2-server-actions\" style=\"position:relative;\"><a href=\"#6-2-server-actions\" aria-label=\"6 2 server actions permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6-2. Server Actions</h3>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token comment\">// app/actions/user.ts</span>\n<span class=\"token string\">'use server'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> revalidatePath <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'next/cache'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> db <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/lib/db'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> z <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'zod'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> createUserSchema <span class=\"token operator\">=</span> z<span class=\"token punctuation\">.</span><span class=\"token function\">object</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  name<span class=\"token operator\">:</span> z<span class=\"token punctuation\">.</span><span class=\"token function\">string</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">min</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  email<span class=\"token operator\">:</span> z<span class=\"token punctuation\">.</span><span class=\"token function\">string</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">email</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">createUser</span><span class=\"token punctuation\">(</span>formData<span class=\"token operator\">:</span> FormData<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> rawData <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    name<span class=\"token operator\">:</span> formData<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">'name'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    email<span class=\"token operator\">:</span> formData<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">'email'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// 유효성 검사</span>\n  <span class=\"token keyword\">const</span> validatedData <span class=\"token operator\">=</span> createUserSchema<span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>rawData<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// 데이터베이스에 저장</span>\n  <span class=\"token keyword\">const</span> user <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> db<span class=\"token punctuation\">.</span>user<span class=\"token punctuation\">.</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    data<span class=\"token operator\">:</span> validatedData<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// 캐시 무효화</span>\n  <span class=\"token function\">revalidatePath</span><span class=\"token punctuation\">(</span><span class=\"token string\">'/users'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> success<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> user <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 사용 예시</span>\n<span class=\"token string\">'use client'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createUser <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@/app/actions/user'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useTransition <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">UserForm</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>isPending<span class=\"token punctuation\">,</span> startTransition<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useTransition</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">handleSubmit</span><span class=\"token punctuation\">(</span>formData<span class=\"token operator\">:</span> FormData<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">startTransition</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> result <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">createUser</span><span class=\"token punctuation\">(</span>formData<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">.</span>success<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'User created:'</span><span class=\"token punctuation\">,</span> result<span class=\"token punctuation\">.</span>user<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>form action<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>handleSubmit<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>input name<span class=\"token operator\">=</span><span class=\"token string\">\"name\"</span> placeholder<span class=\"token operator\">=</span><span class=\"token string\">\"Name\"</span> required <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>input name<span class=\"token operator\">=</span><span class=\"token string\">\"email\"</span> type<span class=\"token operator\">=</span><span class=\"token string\">\"email\"</span> placeholder<span class=\"token operator\">=</span><span class=\"token string\">\"Email\"</span> required <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button type<span class=\"token operator\">=</span><span class=\"token string\">\"submit\"</span> disabled<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>isPending<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>isPending <span class=\"token operator\">?</span> <span class=\"token string\">'Creating...'</span> <span class=\"token operator\">:</span> <span class=\"token string\">'Create User'</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"7-결론\" style=\"position:relative;\"><a href=\"#7-%EA%B2%B0%EB%A1%A0\" aria-label=\"7 결론 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>7. 결론</h2>\n<p>React와 Next.js는 현대적 웹 개발의 핵심 기술이다. 이 글에서 다룬 내용:</p>\n<ol>\n<li><strong>React Hooks 심화</strong>: useState, useReducer, useEffect, 커스텀 Hooks</li>\n<li><strong>Next.js 14 App Router</strong>: Server Components, Streaming, Suspense</li>\n<li><strong>데이터 페칭</strong>: React Query를 활용한 서버 상태 관리</li>\n<li><strong>상태 관리</strong>: Zustand, Jotai 등 현대적 라이브러리</li>\n<li><strong>성능 최적화</strong>: 코드 스플리팅, 이미지 최적화, 번들 분석</li>\n</ol>\n<p>이러한 기술들을 조합하면 확장 가능하고 유지보수하기 쉬운 프론트엔드 애플리케이션을 구축할 수 있다.</p>\n<h2 id=\"참고-자료\" style=\"position:relative;\"><a href=\"#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C\" aria-label=\"참고 자료 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>참고 자료</h2>\n<ul>\n<li><a href=\"https://react.dev/\">React 공식 문서</a></li>\n<li><a href=\"https://nextjs.org/docs\">Next.js 공식 문서</a></li>\n<li><a href=\"https://tanstack.com/query/latest\">TanStack Query 문서</a></li>\n<li><a href=\"https://zustand-demo.pmnd.rs/\">Zustand 문서</a></li>\n</ul>","tableOfContents":"<ul>\n<li>\n<p><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#react%EC%99%80-nextjs-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5---%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C\">React와 Next.js 완전정복 - 현대적 프론트엔드 개발 실전 가이드</a></p>\n<ul>\n<li>\n<p><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#1-react-hooks-%EC%8B%AC%ED%99%94\">1. React Hooks 심화</a></p>\n<ul>\n<li>\n<p><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#1-1-usestate%EC%99%80-usereducer-%EA%B3%A0%EA%B8%89-%ED%99%9C%EC%9A%A9\">1-1. useState와 useReducer 고급 활용</a></p>\n<ul>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#usestate%EC%9D%98-%ED%95%A8%EC%88%98%ED%98%95-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8\">useState의 함수형 업데이트</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#usereducer%EB%A1%9C-%EB%B3%B5%EC%9E%A1%ED%95%9C-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC\">useReducer로 복잡한 상태 관리</a></li>\n</ul>\n</li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#1-2-useeffect%EC%99%80-%EC%9D%98%EC%A1%B4%EC%84%B1-%EB%B0%B0%EC%97%B4-%EC%99%84%EB%B2%BD-%EC%9D%B4%ED%95%B4\">1-2. useEffect와 의존성 배열 완벽 이해</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#1-3-%EC%BB%A4%EC%8A%A4%ED%85%80-hooks-%ED%8C%A8%ED%84%B4\">1-3. 커스텀 Hooks 패턴</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#1-4-usememo%EC%99%80-usecallback-%EC%B5%9C%EC%A0%81%ED%99%94\">1-4. useMemo와 useCallback 최적화</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#2-react-server-components%EC%99%80-nextjs-14-app-router\">2. React Server Components와 Next.js 14 App Router</a></p>\n<ul>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#2-1-server-components-vs-client-components\">2-1. Server Components vs Client Components</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#2-2-nextjs-14-app-router-%EA%B5%AC%EC%A1%B0\">2-2. Next.js 14 App Router 구조</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#2-3-app-router-%EC%8B%A4%EC%A0%84-%EC%98%88%EC%A0%9C\">2-3. App Router 실전 예제</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#2-4-streaming%EA%B3%BC-suspense\">2-4. Streaming과 Suspense</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#3-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%8E%98%EC%B9%AD%EA%B3%BC-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC\">3. 데이터 페칭과 상태 관리</a></p>\n<ul>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#3-1-react-query-tanstack-query-%EC%99%84%EC%A0%84-%EC%A0%95%EB%A6%AC\">3-1. React Query (TanStack Query) 완전 정리</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#3-2-infinite-queries-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4\">3-2. Infinite Queries (무한 스크롤)</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#3-3-optimistic-updates\">3-3. Optimistic Updates</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#4-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EB%B9%84%EA%B5%90\">4. 상태 관리 라이브러리 비교</a></p>\n<ul>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#4-1-zustand---%EA%B0%80%EB%B2%BC%EC%9A%B4-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC\">4-1. Zustand - 가벼운 상태 관리</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#4-2-jotai---%EC%9B%90%EC%9E%90%EC%A0%81-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC\">4-2. Jotai - 원자적 상태 관리</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#5-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94\">5. 성능 최적화</a></p>\n<ul>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#5-1-%EC%BD%94%EB%93%9C-%EC%8A%A4%ED%94%8C%EB%A6%AC%ED%8C%85%EA%B3%BC-%EB%A0%88%EC%9D%B4%EC%A7%80-%EB%A1%9C%EB%94%A9\">5-1. 코드 스플리팅과 레이지 로딩</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#5-2-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%B5%9C%EC%A0%81%ED%99%94\">5-2. 이미지 최적화</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#5-3-%EB%B2%88%EB%93%A4-%EB%B6%84%EC%84%9D\">5-3. 번들 분석</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#6-nextjs-api-routes%EC%99%80-server-actions\">6. Next.js API Routes와 Server Actions</a></p>\n<ul>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#6-1-api-routes\">6-1. API Routes</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#6-2-server-actions\">6-2. Server Actions</a></li>\n</ul>\n</li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#7-%EA%B2%B0%EB%A1%A0\">7. 결론</a></li>\n<li><a href=\"/javascript/React-Next.js-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%ED%98%84%EB%8C%80%EC%A0%81-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EA%B0%80%EC%9D%B4%EB%93%9C/#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C\">참고 자료</a></li>\n</ul>\n</li>\n</ul>","wordCount":{"words":267},"fields":{"slug":"/javascript/React-Next.js-완전정복-현대적-프론트엔드-개발-가이드/","image":null,"faq":[]},"frontmatter":{"title":"React와 Next.js 완전정복 - 현대적 프론트엔드 개발 실전 가이드","date":"2025년 11월 15일","dateISO":"2025-11-15T00:00:00.000Z","updatedISO":null,"category":"javascript","description":"React Hooks 심화, Server Components, Next.js 14 App Router, React Query, 상태 관리 라이브러리 비교, 성능 최적화까지 현대적 React/Next.js 개발의 모든 것을 실전 예제와 함께 정리합니다.","tags":["React","Next.js","React Hooks","Server Components","React Query","프론트엔드","웹 개발","JavaScript","TypeScript","상태 관리"]}}},"pageContext":{"slug":"/javascript/React-Next.js-완전정복-현대적-프론트엔드-개발-가이드/","previous":{"fields":{"slug":"/python/FastAPI-완전정복-고성능-비동기-웹-API-개발-가이드/"},"frontmatter":{"title":"FastAPI 완전정복 - 고성능 비동기 웹 API 개발 실전 가이드","tags":["FastAPI","Python","비동기 프로그래밍","웹 API","REST API","asyncio","Pydantic","WebSocket","데이터베이스","백엔드 개발"]}},"next":{"fields":{"slug":"/algorithm/고급-알고리즘-완전정복-세그먼트-트리부터-위상정렬까지/"},"frontmatter":{"title":"고급 알고리즘 완전정복 - 세그먼트 트리부터 위상정렬까지","tags":["알고리즘","Algorithm","세그먼트 트리","Segment Tree","유니온 파인드","Union-Find","위상 정렬","Topological Sort","최소 신장 트리","MST","최대 유량","Max Flow","코딩 테스트","JavaScript"]}}}},"staticQueryHashes":["213619243","3262363727"]}