{"componentChunkName":"component---src-templates-post-js","path":"/개발/2020/10/10/start-next-js-4/","result":{"data":{"markdownRemark":{"fields":{"slug":"/개발/2020/10/10/start-next-js-4/","date":"2020-10-10"},"frontmatter":{"title":"Next.js 시작해보자 4/5 - Dynamic Routes","tags":["nextjs","react framework","dynamic routes","path","rendering","markdown","css"],"author":"jslee"},"id":"bd0e7549-ebed-5838-8925-6afe7888db9a","html":"<p><a href=\"https://nextjs.org/learn/basics/dynamic-routes\">https://nextjs.org/learn/basics/dynamic-routes</a></p>\n<p>블로그 데이터로 index page를 채웠지만 아직 개별 블로그 pages를 만들지 않았다. 이러한 페이지의 URL이 블로그 데이터에 의존하기를 원하므로 dynamic routes를 사용해야 한다.</p>\n<h1>포스트에서 다룰 내용</h1>\n<ul>\n<li>dynamic routes와 <code class=\"language-text\">getStaticPaths</code> 를 사용해서 정적으로 페이지 만들기</li>\n<li>각 블로그 포스트에 데이터를 <code class=\"language-text\">getStaticProps</code>를 어떻게 작성해서 가져오는지</li>\n<li><code class=\"language-text\">remark</code>를 사용해서 markdown을 rendering</li>\n<li><code class=\"language-text\">dynamic routes</code>를 사용해서 page를 어떻게 연결하는지</li>\n<li><code class=\"language-text\">dynamic routes</code>에서 유용한 정보들</li>\n</ul>\n<h1>Page Path Depends on External Data</h1>\n<p><a href=\"https://nextjs.org/learn/basics/dynamic-routes/page-path-external-data\">https://nextjs.org/learn/basics/dynamic-routes/page-path-external-data</a></p>\n<p>external data에 의존한 page content를 만들었다. <code class=\"language-text\">getStaticProps</code>을 사용해 필요한 데이터를 가져오고 index page에 render 했다. 이번에는 external data에 의존한 page path에 대해서 얘기를 해본다. Next.js에서는 external data에 의존한 path를 가지고 정적 페이지를 생성하는데 이 것을 dynamic URLs이라고 말한다.</p>\n<p><figure class=\"gatsby-resp-image-figure\" style=\"margin: 0 0;\">\n    <span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/c1dbf04ecb604171f4b52ff78bf1a752/08188/page-path.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 83%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAABYlAAAWJQFJUiTwAAAB5klEQVQ4y32UaaoCMRCEvf95vID+cEUZVFQQ0dFx3/dl1H58DR0yLi9QJCad6urqOKnb7Sb3+13O57NcLhdd2x7z9Xp1M4jjWJ7PpzweDwVrA3dS1WpVCoWClEolKZfLks/npVgsSqPRUHAOOM/lcjKZTOTbeL1eKip1Op1ks9nI4XCQ/X6v691ul8B2u3Ug7ng86kxFRuYIIZjNZor5fC6j0UiiKJLpdKqw/fF4rPNqtVKVw+FQFovFJyEb5gmzP5bLpSo2/wCq8NQvNVEyRpKt1+tpyX5gpVKRWq2milCOStQzI8CUJQhRBSFKCOayqcGrd9XvjfggJFOn01FvUEl2GgUgIxHEnK3Xa302XPxJSADB/X5fy6IJFoRXqCYZpXNGIrpt3htpghAyQKAF+Ybb+K98zlyXv3ljzwYQSMNQR9n4y/vEHjynAoZrCh4B+/uxNxgM9EIYhu6xW6OoijeJVZxjlSPk2bTbbWm1WlKv1xU0qtlsKlijzv7nKM5ms/obAnwmAWBPPex2u2o42VGCwiAItBGcs486I8xkMnqZfWaQIOQypEinFAYfAj4aKKBk1BDLm02n0y65JXOEXGbBppWAQjpOsP/pMlUQ+Z82810JKQOfyGCzBZlPBv8/7e+bv+z/AddSFqCPp9dxAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n        <source\n          srcset=\"/static/c1dbf04ecb604171f4b52ff78bf1a752/a5e6d/page-path.webp 200w,\n/static/c1dbf04ecb604171f4b52ff78bf1a752/2276a/page-path.webp 400w,\n/static/c1dbf04ecb604171f4b52ff78bf1a752/cf465/page-path.webp 800w,\n/static/c1dbf04ecb604171f4b52ff78bf1a752/6fdea/page-path.webp 1176w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/webp\"\n        />\n        <source\n          srcset=\"/static/c1dbf04ecb604171f4b52ff78bf1a752/56d15/page-path.png 200w,\n/static/c1dbf04ecb604171f4b52ff78bf1a752/d9f49/page-path.png 400w,\n/static/c1dbf04ecb604171f4b52ff78bf1a752/78d47/page-path.png 800w,\n/static/c1dbf04ecb604171f4b52ff78bf1a752/08188/page-path.png 1176w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/png\"\n        />\n        <img\n          class=\"gatsby-resp-image-image\"\n          src=\"/static/c1dbf04ecb604171f4b52ff78bf1a752/78d47/page-path.png\"\n          alt=\"출처: https://nextjs.org/learn/basics/dynamic-routes/page-path-external-data\"\n          title=\"출처: https://nextjs.org/learn/basics/dynamic-routes/page-path-external-data\"\n          loading=\"lazy\"\n          style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        />\n      </picture>\n  </a>\n    </span>\n    <figcaption class=\"gatsby-resp-image-figcaption\">출처: https://nextjs.org/learn/basics/dynamic-routes/page-path-external-data</figcaption>\n  </figure></p>\n<h2>How to Statically Generate Pages with Dynamic Routes</h2>\n<p>blog posts를 위해서 dynamic routes를 생성해보자.</p>\n<ul>\n<li>각 포스트는 <code class=\"language-text\">/posts/&lt;id&gt;</code></li>\n<li><code class=\"language-text\">ssg-ssr.md</code>는 <code class=\"language-text\">/posts/ssg-ssr</code>로</li>\n</ul>\n<p><code class=\"language-text\">&lt;id&gt;</code>를 dynamic 하게 생성이 가능하다.</p>\n<h1>Implement getStaticPaths</h1>\n<p><a href=\"https://nextjs.org/learn/basics/dynamic-routes/page-path-external-data\">https://nextjs.org/learn/basics/dynamic-routes/page-path-external-data</a></p>\n<p>아래와 같이 파일을 구성</p>\n<ul>\n<li><code class=\"language-text\">[id].js</code>를 <code class=\"language-text\">pages/posts</code> 안에 생성</li>\n</ul>\n<p>이전에 생성했던 <code class=\"language-text\">lib/posts.js</code>에 아래와 같이 함수를 추가한다. <code class=\"language-text\">.md</code>를 제거하고 파일명을 받아서 <code class=\"language-text\">id</code>로 사용하기 위해서</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getAllPostIds</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> fileNames <span class=\"token operator\">=</span> fs<span class=\"token punctuation\">.</span><span class=\"token function\">readdirSync</span><span class=\"token punctuation\">(</span>postsDirectory<span class=\"token punctuation\">)</span>\n\n  <span class=\"token comment\">// Returns an array that looks like this:</span>\n  <span class=\"token comment\">// [</span>\n  <span class=\"token comment\">//   {</span>\n  <span class=\"token comment\">//     params: {</span>\n  <span class=\"token comment\">//       id: 'ssg-ssr'</span>\n  <span class=\"token comment\">//     }</span>\n  <span class=\"token comment\">//   },</span>\n  <span class=\"token comment\">//   {</span>\n  <span class=\"token comment\">//     params: {</span>\n  <span class=\"token comment\">//       id: 'pre-rendering'</span>\n  <span class=\"token comment\">//     }</span>\n  <span class=\"token comment\">//   }</span>\n  <span class=\"token comment\">// ]</span>\n  <span class=\"token keyword\">return</span> fileNames<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">fileName</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>\n      params<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        id<span class=\"token operator\">:</span> fileName<span class=\"token punctuation\">.</span><span class=\"token function\">replace</span><span class=\"token punctuation\">(</span><span class=\"token regex\">/\\.md$/</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"\"</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>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><code class=\"language-text\">pages/posts/[id].js</code>에 아래와 같이 추가</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> getAllPostIds <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"../../lib/posts\"</span></code></pre></div>\n<p>그리고 <code class=\"language-text\">getStaticPaths</code>를 생성하고 호출</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getStaticPaths</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> paths <span class=\"token operator\">=</span> <span class=\"token function\">getAllPostIds</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    paths<span class=\"token punctuation\">,</span>\n    fallback<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h1>Implement getStatic Props</h1>\n<p><a href=\"https://nextjs.org/learn/basics/dynamic-routes/implement-getstaticprops\">https://nextjs.org/learn/basics/dynamic-routes/implement-getstaticprops</a></p>\n<p><code class=\"language-text\">id</code>가 주어졌을때 post를 렌더링하기 위해서는 데이터 fetch를 하는게 필요하다. 그 작업을 위해서 <code class=\"language-text\">lib/posts.js</code>에 <code class=\"language-text\">id</code>를 기반으로 post를 리턴하는 함수를 구성하자</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getPostData</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> fullPath <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span>postsDirectory<span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>id<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">.md</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> fileContents <span class=\"token operator\">=</span> fs<span class=\"token punctuation\">.</span><span class=\"token function\">readFileSync</span><span class=\"token punctuation\">(</span>fullPath<span class=\"token punctuation\">,</span> <span class=\"token string\">\"utf8\"</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token comment\">// Use gray-matter to parse the post metadata section</span>\n  <span class=\"token keyword\">const</span> matterResult <span class=\"token operator\">=</span> <span class=\"token function\">matter</span><span class=\"token punctuation\">(</span>fileContents<span class=\"token punctuation\">)</span>\n\n  <span class=\"token comment\">// Combine the data with the id</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    id<span class=\"token punctuation\">,</span>\n    <span class=\"token operator\">...</span>matterResult<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><code class=\"language-text\">pages/posts/[id].js</code>에 아래와 같이 코드를 추가하고</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> getAllPostIds<span class=\"token punctuation\">,</span> getPostData <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"../../lib/posts\"</span></code></pre></div>\n<p><code class=\"language-text\">getStaticProps</code>의 코드를 추가</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getStaticProps</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> params <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> postData <span class=\"token operator\">=</span> <span class=\"token function\">getPostData</span><span class=\"token punctuation\">(</span>params<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    props<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      postData<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></code></pre></div>\n<p><code class=\"language-text\">Post</code> 컴포넌트를 <code class=\"language-text\">postData</code>를 사용하도록 변경</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">Post</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> postData <span class=\"token punctuation\">}</span></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>Layout<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>title<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>date<span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><a href=\"https://github.com/vercel/next-learn-starter/tree/master/dynamic-routes-step-1\">최종 코드 비교</a></p>\n<h1>Render Markdown</h1>\n<p><a href=\"https://nextjs.org/learn/basics/dynamic-routes/render-markdown\">https://nextjs.org/learn/basics/dynamic-routes/render-markdown</a></p>\n<p>markdown content를 rendering 하기 위해서 <code class=\"language-text\">remark</code> 라이브러리를 사용</p>\n<div class=\"gatsby-highlight\" data-language=\"sh\"><pre class=\"language-sh\"><code class=\"language-sh\">npm install remark remark-html</code></pre></div>\n<p><code class=\"language-text\">lib/posts.js</code>에 import</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> remark <span class=\"token keyword\">from</span> <span class=\"token string\">\"remark\"</span>\n<span class=\"token keyword\">import</span> html <span class=\"token keyword\">from</span> <span class=\"token string\">\"remark-html\"</span></code></pre></div>\n<p><code class=\"language-text\">getPostData()</code>에 <code class=\"language-text\">remark</code>를 추가</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getPostData</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> fullPath <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span>postsDirectory<span class=\"token punctuation\">,</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>id<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">.md</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> fileContents <span class=\"token operator\">=</span> fs<span class=\"token punctuation\">.</span><span class=\"token function\">readFileSync</span><span class=\"token punctuation\">(</span>fullPath<span class=\"token punctuation\">,</span> <span class=\"token string\">\"utf8\"</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token comment\">// Use gray-matter to parse the post metadata section</span>\n  <span class=\"token keyword\">const</span> matterResult <span class=\"token operator\">=</span> <span class=\"token function\">matter</span><span class=\"token punctuation\">(</span>fileContents<span class=\"token punctuation\">)</span>\n\n  <span class=\"token comment\">// Use remark to convert markdown into HTML string</span>\n  <span class=\"token keyword\">const</span> processedContent <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">remark</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">.</span><span class=\"token function\">use</span><span class=\"token punctuation\">(</span>html<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">.</span><span class=\"token function\">process</span><span class=\"token punctuation\">(</span>matterResult<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> contentHtml <span class=\"token operator\">=</span> processedContent<span class=\"token punctuation\">.</span><span class=\"token function\">toString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token comment\">// Combine the data with the id and contentHtml</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    id<span class=\"token punctuation\">,</span>\n    contentHtml<span class=\"token punctuation\">,</span>\n    <span class=\"token operator\">...</span>matterResult<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<blockquote>\n<p><code class=\"language-text\">await</code>가 필요하기 때문에 <code class=\"language-text\">getPostData</code>에 <code class=\"language-text\">async</code>를 추가 <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function\">async에 대해서 알아보기</a></p>\n</blockquote>\n<p><code class=\"language-text\">pages/posts/[id].js</code>의 <code class=\"language-text\">getSTaticProps</code>에서도 <code class=\"language-text\">getPostData</code>를 할때 <code class=\"language-text\">await</code>를 사용해야 한다.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getStaticProps</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> params <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Add the \"await\" keyword like this:</span>\n  <span class=\"token keyword\">const</span> postData <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">getPostData</span><span class=\"token punctuation\">(</span>params<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span>\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>마지막으로 <code class=\"language-text\">Post</code> 컴포넌트를 <code class=\"language-text\">dangerouslySetInnerHTML</code>을 사용해서<code class=\"language-text\">contentHtml</code>을 렌더링하도록 수정</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">Post</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> postData <span class=\"token punctuation\">}</span></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>Layout<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>title<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>date<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div dangerouslySetInnerHTML<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> __html<span class=\"token operator\">:</span> postData<span class=\"token punctuation\">.</span>contentHtml <span class=\"token punctuation\">}</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>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><figure class=\"gatsby-resp-image-figure\" style=\"margin: 0 0;\">\n    <span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/2b16a94314badfdf732f564e3d867168/622c8/md-rendering-page.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 139.5%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAcCAYAAABh2p9gAAAACXBIWXMAABYlAAAWJQFJUiTwAAACr0lEQVRIx6WV6a7iMAyFef/n4i8CxE7Z951CF9bi6WfGVeGWO0JTyXKaOM7xsZ3k5MP3eDwSHfiB+L7/Yy3ry31yZpuOh4P0nI44zbYc3MOP9a8d7rc76bYdadWbst1s/u3QFrPEPv94lMDzMw98t83JL18URVIsFqVarUo+n9dxenMWSkUYhqEKxB9jNGjP83Q8n89lOp3KYDCQ8Xisc8jpdMpGCIpOpyPD4VDW67Vums1mqs3BarVKhDmzTTs0p+qw0Wio0/1+L//z4VRD3u126oxTCZWQ+Wce2W63cojLh7UgCBIbhH80lCUI+/1+ghLp9XpSLpc1CehCoSD1el0cx5Fut6u63W7rHLpWqyUUqEMWyGSr1ZJKpaJjDkCzAWGNjQj2aDuAKBIOGYAQud/vKtfrVUsGuVwucrvddGzr/J/PZ53D9oVDJuHLdV3NqPFl3DHHv9mgEXgk6zhO16QixMDqDZlMJlo6bMAx/DA2jS3z2NilYaWjnUIIlhg4YcO35fLSeqScTsAhjgmRcDfxZbBcLhMOP0m6r9UhxNMBZLLZbGoWKRcOIMRvUCqH8AAnoAEZYuSDnsRY0tDGJYkhmnRiNMsUMrVGUVNbIGUOGuAUsXoEtRW92ZJE/CQIrfE5jdMXi8XLhQBi0DM2Xq0tyTQODaUi5PYABaeBEh5BaMhMw63ZgA5NRUCNFbgitA0Y0FKEZSFzGAegccI8Tq2njXcqIXFoYbLAGE14FDkhsZkqGI1GagcqowOHlBoJU4f0JoYWcvpG4aKwy4BElEolHeOciLg84I+QE4fPLPc1rKc8a9Gyas7RVg2IObJkvFywYRBflL4Xa09OYfBycaLJvtWjXbQ0Q9YrmEOfbk8J/+pvevj9OY1bL34CgkjmbiTL41OiX97q90fp/dX7A5wKVt+fy1LvAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n        <source\n          srcset=\"/static/2b16a94314badfdf732f564e3d867168/a5e6d/md-rendering-page.webp 200w,\n/static/2b16a94314badfdf732f564e3d867168/2276a/md-rendering-page.webp 400w,\n/static/2b16a94314badfdf732f564e3d867168/cf465/md-rendering-page.webp 800w,\n/static/2b16a94314badfdf732f564e3d867168/cbd37/md-rendering-page.webp 1200w,\n/static/2b16a94314badfdf732f564e3d867168/617b0/md-rendering-page.webp 1384w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/webp\"\n        />\n        <source\n          srcset=\"/static/2b16a94314badfdf732f564e3d867168/56d15/md-rendering-page.png 200w,\n/static/2b16a94314badfdf732f564e3d867168/d9f49/md-rendering-page.png 400w,\n/static/2b16a94314badfdf732f564e3d867168/78d47/md-rendering-page.png 800w,\n/static/2b16a94314badfdf732f564e3d867168/64756/md-rendering-page.png 1200w,\n/static/2b16a94314badfdf732f564e3d867168/622c8/md-rendering-page.png 1384w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/png\"\n        />\n        <img\n          class=\"gatsby-resp-image-image\"\n          src=\"/static/2b16a94314badfdf732f564e3d867168/78d47/md-rendering-page.png\"\n          alt=\"최종화면\"\n          title=\"최종화면\"\n          loading=\"lazy\"\n          style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        />\n      </picture>\n  </a>\n    </span>\n    <figcaption class=\"gatsby-resp-image-figcaption\">최종화면</figcaption>\n  </figure></p>\n<h1>Polishing the Post Page</h1>\n<p><a href=\"https://nextjs.org/learn/basics/dynamic-routes/polishing-post-page\">https://nextjs.org/learn/basics/dynamic-routes/polishing-post-page</a></p>\n<h2>Adding <code class=\"language-text\">title</code> to the Post Page</h2>\n<p><code class=\"language-text\">pages/posts/[id].js</code>에 post data를 사용해서 <code class=\"language-text\">title</code> tag를 추가 <code class=\"language-text\">next/head</code>를 import하고 <code class=\"language-text\">title</code>을 추가해보자</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> Head <span class=\"token keyword\">from</span> <span class=\"token string\">\"next/head\"</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\">Post</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> postData <span class=\"token punctuation\">}</span></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>Layout<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>Head<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>title<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>title<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>title<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Head<span class=\"token operator\">></span>\n      <span class=\"token operator\">...</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2>Formatting the Date</h2>\n<p>date를 format하기 위해서 <code class=\"language-text\">date-fns</code>의 라이브러리를 사용</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install date-fns</code></pre></div>\n<p><code class=\"language-text\">Date</code> 컴포넌트를 <code class=\"language-text\">components/date.js</code>에 생성</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> parseISO<span class=\"token punctuation\">,</span> format <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"date-fns\"</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\">Date</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> dateString <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> date <span class=\"token operator\">=</span> <span class=\"token function\">parseISO</span><span class=\"token punctuation\">(</span>dateString<span class=\"token punctuation\">)</span>\n  <span class=\"token comment\">/* January 2, 2020 */</span>\n  <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>time dateTime<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>dateString<span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">{</span><span class=\"token function\">format</span><span class=\"token punctuation\">(</span>date<span class=\"token punctuation\">,</span> <span class=\"token string\">\"LLLL d, yyyy\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>time<span class=\"token operator\">></span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<blockquote>\n<p><a href=\"https://date-fns.org/v2.16.1/docs/format\">다른 format 옵션 확인</a>하</p>\n</blockquote>\n<p><code class=\"language-text\">pages/posts/[id].js</code>에서 사용하면 된다.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// Add this line to imports</span>\n<span class=\"token keyword\">import</span> Date <span class=\"token keyword\">from</span> <span class=\"token string\">\"../../components/date\"</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\">Post</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> postData <span class=\"token punctuation\">}</span></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>Layout<span class=\"token operator\">></span>\n      <span class=\"token operator\">...</span>\n      <span class=\"token punctuation\">{</span><span class=\"token comment\">/* Replace {postData.date} with this */</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>Date dateString<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>date<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">...</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2>Adding CSS</h2>\n<p>마지막으로 <code class=\"language-text\">pages/posts/[id].js</code>에 CSS를 추가해보자.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// Add this line</span>\n<span class=\"token keyword\">import</span> utilStyles <span class=\"token keyword\">from</span> <span class=\"token string\">'../../styles/utils.module.css'</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\">Post</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> postData <span class=\"token punctuation\">}</span></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>Layout<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>Head<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>title<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>title<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>title<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Head<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>article<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>h1 className<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>utilStyles<span class=\"token punctuation\">.</span>headingXl<span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>title<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>div className<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>utilStyles<span class=\"token punctuation\">.</span>lightText<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>Date dateString<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>postData<span class=\"token punctuation\">.</span>date<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>div<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>div dangerouslySetInnerHTML<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> __html<span class=\"token operator\">:</span> postData<span class=\"token punctuation\">.</span>contentHtml <span class=\"token punctuation\">}</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>article<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Layout<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span></code></pre></div>\n<p><figure class=\"gatsby-resp-image-figure\" style=\"margin: 0 0;\">\n    <span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/99db0bddcc5757d4f0f6d4da24827dc1/e76f9/adding-css.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 75.49999999999999%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAABYlAAAWJQFJUiTwAAABtElEQVQ4y6VSSYvCYAzt/z97VQQVXPCgKIieRRQVd1qrdQNX9KBTd33TF6hTnRk7MIGQfEm+5GVR8Ibu97vI6/WKy+XysNn2n0hxS7bf7zEZjjA0BjA/zCffnxM6UaxXKxh6D7qqYblYuKJ0RXi/3TCfTi2e4Wa17orQrvbKJM5taiWbzWYwDAPL5fLbLJ3xlMq7pdwsdLVaDe12G/l8XvTT6fS2I4UbXK/XOBwOOJ/PsgTTNAXJbreTDTOxEwWTMo4xrz6FjlAoBJ/Ph0wmg2QyiUQigVQqhXg8Dq/Xi0gkIr5gMAi/349AIACPx/OILZfLXwm32y2i0ShyuRyy2SxKpZK80+k0wuGwyFgsJh+pbzYbQc1uyETrnKtCAytwTs1mE/1+H8ViUd6VSgX1el2K0FcoFKTVd6emPJ2IJTmT/5Ag5FnM53NhngYlz8Rmoh6Px1hYh237V9bB858tuVhByO2yvUajgU6nI7qmadIqz4RcrVbRarWgqqowYxhr2/iXSQXh8XgUJ1GMRiPoui66EyHR0Ud9MBig1+uh2+1iMpmIjct5tMwHg+wKvx2sG9lL+QQ3EmzA1nhbQQAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n        <source\n          srcset=\"/static/99db0bddcc5757d4f0f6d4da24827dc1/a5e6d/adding-css.webp 200w,\n/static/99db0bddcc5757d4f0f6d4da24827dc1/2276a/adding-css.webp 400w,\n/static/99db0bddcc5757d4f0f6d4da24827dc1/cf465/adding-css.webp 800w,\n/static/99db0bddcc5757d4f0f6d4da24827dc1/cbd37/adding-css.webp 1200w,\n/static/99db0bddcc5757d4f0f6d4da24827dc1/1ac7f/adding-css.webp 1344w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/webp\"\n        />\n        <source\n          srcset=\"/static/99db0bddcc5757d4f0f6d4da24827dc1/56d15/adding-css.png 200w,\n/static/99db0bddcc5757d4f0f6d4da24827dc1/d9f49/adding-css.png 400w,\n/static/99db0bddcc5757d4f0f6d4da24827dc1/78d47/adding-css.png 800w,\n/static/99db0bddcc5757d4f0f6d4da24827dc1/64756/adding-css.png 1200w,\n/static/99db0bddcc5757d4f0f6d4da24827dc1/e76f9/adding-css.png 1344w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/png\"\n        />\n        <img\n          class=\"gatsby-resp-image-image\"\n          src=\"/static/99db0bddcc5757d4f0f6d4da24827dc1/78d47/adding-css.png\"\n          alt=\"adding css\"\n          title=\"adding css\"\n          loading=\"lazy\"\n          style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        />\n      </picture>\n  </a>\n    </span>\n    <figcaption class=\"gatsby-resp-image-figcaption\">adding css</figcaption>\n  </figure></p>\n<h1>Polishing the Index Page</h1>\n<p><a href=\"https://nextjs.org/learn/basics/dynamic-routes/polishing-index-page\">https://nextjs.org/learn/basics/dynamic-routes/polishing-index-page</a></p>\n<p><code class=\"language-text\">pages/index.js</code>에 각 포스트에 링크(Link)를 넣어 업데이트 해보자.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> Link <span class=\"token keyword\">from</span> <span class=\"token string\">\"next/link\"</span>\n<span class=\"token keyword\">import</span> Date <span class=\"token keyword\">from</span> <span class=\"token string\">\"../components/date\"</span></code></pre></div>\n<p><code class=\"language-text\">Home</code> 컴포넌트의 <code class=\"language-text\">li</code> tag를 변경하자</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token operator\">&lt;</span>li className<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>utilStyles<span class=\"token punctuation\">.</span>listItem<span class=\"token punctuation\">}</span> key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>id<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>Link href<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/posts/</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 operator\">></span>\n    <span class=\"token operator\">&lt;</span>a<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>title<span class=\"token punctuation\">}</span><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>Link<span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span>small className<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>utilStyles<span class=\"token punctuation\">.</span>lightText<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>Date dateString<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>date<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>small<span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span></code></pre></div>\n<p><figure class=\"gatsby-resp-image-figure\" style=\"margin: 0 0;\">\n    <span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/84f0a9f8f526979b694210bdf65e97d6/cc0ea/home.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAABYlAAAWJQFJUiTwAAACGUlEQVQ4y6VUy67aQAzN3yPdBVs2bPiFqv2PVkJteeQxENJcSDKBhDxn5tQzAS5QBS6qJeMZGx3bx85Y6BGl1OXc1A3atr34r2P3Yj0C0zaJYjDHBXM9ZIfsKehDwKqqDJiztGEvlvAc7ybZpwCvs9d1bQBd28FyNsfKW13ifVVaz/jLswyB7yMM/kCceHy5Qi2cc4RhaKoMggDb7RYZgadpCiFEL6h1Xb6U8vLnxWKBwWCA8XiMyWSCt7c3DIdDjEYjk6gXEA9EJyjL0pz12uhqtdX+ey47bAWraRqs1z4ch4i3bazWa7iua1THPi8dqKVb5HGElCdGeRIjiiLDWZ7nBrQoCqPH49FYvU5nX6nvdYtWniqsG4HpnMFhAX7bPr5P5/A8DzZV6+vpEl/6rjvQvtlsBsaYubu07CvmgYUp0vIMSDNgHNjsFdyYzrEgrl5p9a5lRQQ3dWkcH6tDA/mH9FuVJ70ZCv1YmodvX7/g18/pebav13ZZHwLUZG54i92hNTzscuD9IBHlis6kmUJeK3OPSXmhKN75t2SzSt18spaQCvZ7iXVM3+2ugB0W8LlEuJdgicSKNDkqhJRkk0oE5NdxrSyWJukNoOahrQqIhsoTFWRb/0fL6Fp29HQTspGEHXWZlzuJHxth2jfM9gzm+jnrKqQpJ3yPfZYjSTMcyArCaIRC3VL18vH71/M4SKPd6qiHLT2Tv9elFNP+I7SQAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n        <source\n          srcset=\"/static/84f0a9f8f526979b694210bdf65e97d6/a5e6d/home.webp 200w,\n/static/84f0a9f8f526979b694210bdf65e97d6/2276a/home.webp 400w,\n/static/84f0a9f8f526979b694210bdf65e97d6/cf465/home.webp 800w,\n/static/84f0a9f8f526979b694210bdf65e97d6/cbd37/home.webp 1200w,\n/static/84f0a9f8f526979b694210bdf65e97d6/3ac9e/home.webp 1368w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/webp\"\n        />\n        <source\n          srcset=\"/static/84f0a9f8f526979b694210bdf65e97d6/56d15/home.png 200w,\n/static/84f0a9f8f526979b694210bdf65e97d6/d9f49/home.png 400w,\n/static/84f0a9f8f526979b694210bdf65e97d6/78d47/home.png 800w,\n/static/84f0a9f8f526979b694210bdf65e97d6/64756/home.png 1200w,\n/static/84f0a9f8f526979b694210bdf65e97d6/cc0ea/home.png 1368w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/png\"\n        />\n        <img\n          class=\"gatsby-resp-image-image\"\n          src=\"/static/84f0a9f8f526979b694210bdf65e97d6/78d47/home.png\"\n          alt=\"Home 최종 화면\"\n          title=\"Home 최종 화면\"\n          loading=\"lazy\"\n          style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        />\n      </picture>\n  </a>\n    </span>\n    <figcaption class=\"gatsby-resp-image-figcaption\">Home 최종 화면</figcaption>\n  </figure></p>\n<h1>Dynamic Routes Details</h1>\n<p><a href=\"https://nextjs.org/learn/basics/dynamic-routes/dynamic-routes-details\">https://nextjs.org/learn/basics/dynamic-routes/dynamic-routes-details</a></p>\n<h2>Fetch External API or Query Database</h2>\n<p><code class=\"language-text\">getStaticProps</code>와 <code class=\"language-text\">getStaticPaths</code>로 어떤 데이터 소스로부터 데이터를 fetch 할 수 있다. <code class=\"language-text\">getAllPostIds</code>는 external API endpoint에서 가져올 수 있다.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getAllPostIds</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Instead of the file system,</span>\n  <span class=\"token comment\">// fetch post data from an external API endpoint</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\">\"..\"</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> posts <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">return</span> posts<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">post</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>\n      params<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        id<span class=\"token operator\">:</span> post<span class=\"token punctuation\">.</span>id<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></code></pre></div>\n<h2>Development v.s. Production</h2>\n<ul>\n<li>In development(<code class=\"language-text\">yarn dev</code>), <code class=\"language-text\">getStaticPaths</code>는 every request 실행</li>\n<li>In production, <code class=\"language-text\">getStaticPaths</code>는 build time에 실행</li>\n</ul>\n<h2>Fallback</h2>\n<p><code class=\"language-text\">getStaticPaths</code>에서 <code class=\"language-text\">fallback: false</code>는 404 page의 결과를 반환, <code class=\"language-text\">fallback is true</code>라면 <code class=\"language-text\">getStaticProps</code>의 동작이 변경된다.</p>\n<ul>\n<li><code class=\"language-text\">getStaticPaths</code>에서 반환된 경로는 반드시 빌드시에 HTML로 렌더링</li>\n<li>빌드시 생성되지 않은 경로는 404 page가 되지 않는다. 대신 Next.js는 이러한 경로에 대한 첫 번째 요청에서 페이지의 <code class=\"language-text\">fallback</code> 버전을 제공</li>\n<li>background에서 next.js는 요청된 경로를 정적으로 생성한다. 동일한 경로에 대한 후속 요청은 빌드시 사전렌더링 된 다른 페이지와 마찬가지로 생서된 페이지를 제공</li>\n</ul>\n<p><a href=\"https://nextjs.org/docs/basic-features/data-fetching#the-fallback-key-required\">fallback에 대한 자세한 내용 확인</a></p>\n<h2>Catch-all Routes (사실 언제 써야할지 모르겠음)</h2>\n<p>Dynamic routes는 3개의 dots(<code class=\"language-text\">...</code>)을 추가해서 모든 경로를 포착하도록 확장이 가능하다.</p>\n<ul>\n<li><code class=\"language-text\">pages/posts/[...id].js</code>는 <code class=\"language-text\">/posts/a</code>, <code class=\"language-text\">/posts/a/b/</code>… 등에 매칭</li>\n</ul>\n<p><code class=\"language-text\">getStaticPaths</code>에서 <code class=\"language-text\">id</code> key의 값을 배열이 형태로 사용하면 된다.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">return</span> <span class=\"token punctuation\">[</span>\n  <span class=\"token punctuation\">{</span>\n    params<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// Statically Generates /posts/a/b/c</span>\n      id<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"a\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"b\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"c\"</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>\n  <span class=\"token comment\">//...</span>\n<span class=\"token punctuation\">]</span></code></pre></div>\n<p>그리고 <code class=\"language-text\">getStaticProps</code>에서 <code class=\"language-text\">params.id</code>는 array로</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getStaticProps</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> params <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// params.id will be like ['a', 'b', 'c']</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><a href=\"https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes\">catch all routes documentaion</a></p>\n<h2>Router</h2>\n<p><code class=\"language-text\">next/router</code>로 부터 <code class=\"language-text\">useRouter</code>를 importing 할수 있다.</p>\n<h2>404 Pages</h2>\n<p>404 page를 커스텀하게 생성하고 싶으면 <code class=\"language-text\">pages/404.js</code>를 만들면 된다. 이 파일은 build time에 정적으로 생성된다.</p>\n<p><a href=\"https://nextjs.org/docs/advanced-features/custom-error-page#404-page\">error page에 대한 자세한 내용</a></p>\n<h2>More Examples</h2>\n<ul>\n<li><a href=\"https://github.com/vercel/next.js/tree/canary/examples/blog-starter\">https://github.com/vercel/next.js/tree/canary/examples/blog-starter</a></li>\n<li><a href=\"https://github.com/vercel/next.js/tree/canary/examples/cms-wordpress\">https://github.com/vercel/next.js/tree/canary/examples/cms-wordpress</a></li>\n<li><a href=\"https://github.com/vercel/next.js/tree/canary/examples/cms-datocms\">https://github.com/vercel/next.js/tree/canary/examples/cms-datocms</a></li>\n<li><a href=\"https://github.com/vercel/next.js/tree/canary/examples/cms-takeshape\">https://github.com/vercel/next.js/tree/canary/examples/cms-takeshape</a></li>\n<li><a href=\"https://github.com/vercel/next.js/tree/canary/examples/cms-sanity\">https://github.com/vercel/next.js/tree/canary/examples/cms-sanity</a></li>\n</ul>","excerpt":"https://nextjs.org/learn/basics/dynamic-routes 블로그 데이터로 index page를 채웠지만 아직 개별 블로그 pages를 만들지 않았다. 이러한 페이지의 URL이 블로그 데이터에 의존하기를 원하므로 dynamic…"}},"pageContext":{"pagePath":"/개발/2020/10/10/start-next-js-4/","next":{"fields":{"slug":"/개발/2020/10/10/start-next-js-5/"},"frontmatter":{"title":"Next.js 시작해보자 5/5 - API Routes","tags":["nextjs","react framework","API Routes"]}},"prev":{"fields":{"slug":"/개발/2020/10/10/start-next-js-3/"},"frontmatter":{"title":"Next.js 시작해보자 3/5 - Pre-rendering and Data Fetching","tags":["nextjs","react framework","rendering","data fetching","server-side rendering","client-side rendering","static generation"]}}}},"staticQueryHashes":["1981752614","3361508366"]}