<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>c_h_hyuk.log</title>
        <link>https://velog.io/</link>
        <description>선한 영향력을 펼치는 개발자가 되겠습니다.</description>
        <lastBuildDate>Mon, 29 Jan 2024 06:24:41 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>c_h_hyuk.log</title>
            <url>https://velog.velcdn.com/images/c_h_hyuk/profile/60eeaa19-6549-4cc2-8b4a-fefe9946f50c/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. c_h_hyuk.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/c_h_hyuk" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[블로그 이전]]></title>
            <link>https://velog.io/@c_h_hyuk/%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%9D%B4%EC%A0%84</link>
            <guid>https://velog.io/@c_h_hyuk/%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%9D%B4%EC%A0%84</guid>
            <pubDate>Mon, 29 Jan 2024 06:24:41 GMT</pubDate>
            <description><![CDATA[<p><a href="https://myblog-2e71c.web.app/">https://myblog-2e71c.web.app/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[개인 프로젝트 - 블로그 만들기 #2]]></title>
            <link>https://velog.io/@c_h_hyuk/%EA%B0%9C%EC%9D%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</link>
            <guid>https://velog.io/@c_h_hyuk/%EA%B0%9C%EC%9D%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</guid>
            <pubDate>Thu, 25 Jan 2024 13:53:07 GMT</pubDate>
            <description><![CDATA[<h2 id="로그인-기능">로그인 기능</h2>
<ul>
<li>구글 아이디를 통해 인증하도록 하였음. 추후 댓글 기능이나 내가 로그인했을 경우 관리자 기능, 게시글 작성, 삭제 등의 기능들을 활용하기 위해</li>
<li>간단하게 firebase에서 제공해주는 구글 인증 기능을 켜주고 </li>
</ul>
<pre><code class="language-js">//firebase.js
import { getAuth } from &quot;firebase/auth&quot;;
...
export const auth = getAuth(app);</code></pre>
<ul>
<li>위와 같이 나의 앱(웹)에 인증 시스템을 부여해주고 <pre><code class="language-jsx">//googleBtn.jsx
</code></pre>
</li>
</ul>
<p>export default function GoogleButton() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const navigate = useNavigate();</p>
<p>  useEffect(() =&gt; {
    const unsubscribe = auth.onAuthStateChanged(user =&gt; {
      setIsLoggedIn(!!user);
    });</p>
<pre><code>return () =&gt; unsubscribe();</code></pre><p>  }, []);</p>
<p>  const handleLogin = async () =&gt; {
    const provider = new GoogleAuthProvider();
    await signInWithPopup(auth, provider);
  };</p>
<p>  const handleLogout = async () =&gt; {
    await signOut(auth);
    navigate(&quot;/&quot;);
  };</p>
<p>  const onClick = () =&gt; {
    if (isLoggedIn) {
      handleLogout();
    } else {
      handleLogin();
    }
  };</p>
<p>  return (
    <Button onClick={onClick}>
      <Logo src="/google-icon.svg" />
      {isLoggedIn ? &quot;Logout&quot; : &quot;Login&quot;}
    </Button>
  );
}</p>
<p>```</p>
<ul>
<li>버튼 클릭 시 구글 로그인 팝업창이 뜨고 로그인 절차를 밟는다</li>
<li>로그인 시 버튼의 텍스트가 Login에서 Logout으로 바뀌고 다시 클릭 시 로그아웃된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[개인프로젝트 - 블로그 만들기 #1]]></title>
            <link>https://velog.io/@c_h_hyuk/%EA%B0%9C%EC%9D%B8%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-1</link>
            <guid>https://velog.io/@c_h_hyuk/%EA%B0%9C%EC%9D%B8%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-1</guid>
            <pubDate>Thu, 25 Jan 2024 09:08:46 GMT</pubDate>
            <description><![CDATA[<h2 id="라우트-설정">라우트 설정</h2>
<h3 id="설계에-맞도록-라우트를-설정">설계에 맞도록 라우트를 설정</h3>
<ul>
<li>우선 블로그의 기준 페이지를 먼저 만들기로 함<pre><code class="language-jsx">//app.jsx
import { RouterProvider, createBrowserRouter } from &quot;react-router-dom&quot;
import Layout from &quot;./components/layout&quot;
import Algorithm from &quot;./routes/algorithm&quot;
import Home from &quot;./routes/home&quot;
import DevTip from &quot;./routes/devTip&quot;
import Project from &quot;./routes/project&quot;
import TechInsight from &quot;./routes/techInsight&quot;
import TechStack from &quot;./routes/techStack&quot;
</code></pre>
</li>
</ul>
<p>const router = createBrowserRouter([
  {
    path:&quot;/&quot;,
    element: <Layout />,
    children : [
      {
        path:&#39;&#39;,
        element: <Home />,
      },
      {
        path:&#39;algorithm&#39;,
        element: <Algorithm />,
      },
      {
        path:&#39;devtip&#39;,
        element: <DevTip />
      },
      {
        path:&#39;project&#39;,
        element: <Project />
      },
      {
        path:&#39;techinsight&#39;,
        element: <TechInsight />
      },
      {
        path:&#39;techstack&#39;,
        element: <TechStack />
      },
      {
        path:&#39;techtrend&#39;,
        element: <Algorithm />
      },
    ]
  }
]) </p>
<p>function App() {</p>
<p>  return (
    &lt;&gt;
      <RouterProvider router={router} />
    &lt;/&gt;
  )
}</p>
<p>export default App</p>
<pre><code> - 레이아웃 : 사이드바, 각 게시판을 돌아다니는 네비게이션 역할을 함
 - 홈페이지(/) : 상단에 내 간단한 소개와 깃헙링크 등 표현 ,조회수가 높은 순으로 인기 게시글 표현, today, total 방문자 수 표현, 하단에 익명으로 실시간 채팅 기능도 표현해볼 예정
 - 알고리즘(/algorithm) : 백준, 프로그래머스의 알고리즘 문제 중 기억해두고 싶은 내용을 게시글로 작성할 예정
 - 개발 팁(/devtip) : 개발 관련 활동, 공부를 하던 중 알게 된 것들, 자원 절약 방법이나 효율적인 개발 방법 등을 알게 된다면 작성할 예정
 - 프로젝트(/project) : 개인, 팀 프로젝트 진행 시 내가 한 것들을 기록할 예정
 - 개발 관련 지식공부(/techinsight) : 개발에 필요한 지식, 개념적이고 원론적인 지식들을 작성할 예정
 - 기술 스택(/techstack) : 언어의 문법 혹은 라이브러리 등의 활용법에 관련된 내용을 작성할 예정
 - 기술 트렌드(/techtrend) : 관심있는 새로운 기술 관련된 동향을 스크랩하여 작성할 예정
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[개인프로젝트 - 블로그 이전을 위해 React로 블로그 직접 만들기]]></title>
            <link>https://velog.io/@c_h_hyuk/%EA%B0%9C%EC%9D%B8%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%9D%B4%EC%A0%84%EC%9D%84-%EC%9C%84%ED%95%B4-Next.js%EB%A1%9C-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%A7%81%EC%A0%91-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@c_h_hyuk/%EA%B0%9C%EC%9D%B8%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%9D%B4%EC%A0%84%EC%9D%84-%EC%9C%84%ED%95%B4-Next.js%EB%A1%9C-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%A7%81%EC%A0%91-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 24 Jan 2024 13:59:06 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<ul>
<li>현재 벨로그가 내용이 많아질수록 정리하기가 너무 어렵고 가독성도 떨어진다고 느껴 다른 블로그로 이전할 생각을 하던 중, 직접 블로그를 만들어보며 그 과정을 기록해보는 것이 내 웹 개발 능력 배양에 많은 도움이 될 것으로 생각하여 시작하게 되었음</li>
</ul>
<h2 id="구성">구성</h2>
<h3 id="시작-페이지">시작 페이지(/)</h3>
<ul>
<li>메인페이지로 나를 간단하게 소개하는 글이나 인삿말 등을 애니매이션으로 표현하고 입장 버튼 활성화, 클릭 시 블로그 페이지</li>
</ul>
<h3 id="블로그-페이지blog">블로그 페이지(/blog)</h3>
<h4 id="메뉴사이드바-및-들어갈-내용">메뉴(사이드바 및 들어갈 내용)</h4>
<ul>
<li>프로그래밍 언어와 프레임워크(Tech Stack) : python, javascript, react, next 등과 같은 특정 프로그래밍 언어나 프레임워크에 초점을 맞춘 카테고리</li>
<li>프로젝트(Projects) : 개인 혹은 팀으로 진행한 프로젝트에서 내가 개발을 해나가는 과정에 초점을 맞추어 정리한 카테고리</li>
<li>개발 관련 개념(Tech Insights) : 웹 개발, 자료구조, 컴퓨터 과학 기초, 고급 프로그래밍 기술 등 다양한 개발 관련 지식과 개념을 포괄적으로 다루는 카테고리</li>
<li>알고리즘과 자료구조(Algorithm) : 코딩 테스트 준비, 알고리즘 풀이 등을 정리하여 묶어놓은 카테고리</li>
<li>개발 경험 팁(Dev Tips) : 개인적인 개발 경험, 배운 교훈, 생산성 향상 팁 등을 공유하는 카테고리</li>
<li>기술 트렌드와 뉴스(Tech Trends) : 새로운 기술 동향, 업계 뉴스, 컨퍼런스 리뷰 등을 포함하는 카테고리</li>
</ul>
<h4 id="게시글">게시글</h4>
<ul>
<li>게시글은 제목, 사진(첫 이미지를 썸네일로 사용), 한줄 설명(20글자 내), 태그(velog와 유사, #으로 표시) 1개 지정, 내용(마크다운 형식)으로 구성</li>
<li>게시글에 댓글을 달 수 있음</li>
<li>게시글은 flex를 활용해 나열할 예정이고(1920px 기준 4개 정도) 상단에 태그를 클릭하여 원하는 태그의 게시글을 볼 수 있게 설정할 예정</li>
</ul>
<h2 id="사용-기술">사용 기술</h2>
<ul>
<li>React : 프론트엔드</li>
<li>firebase : 백엔드 전반적인 부분(DB, Auth, Hosting, Function 등)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #17 NextAuth]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-17-NextAuth</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-17-NextAuth</guid>
            <pubDate>Wed, 10 Jan 2024 03:27:39 GMT</pubDate>
            <description><![CDATA[<h2 id="nextauth">NextAuth</h2>
<pre><code class="language-js">import NextAuth from &quot;next-auth&quot;

export default NextAuth({
  // 인증 공급자, 데이터베이스 어댑터 등의 옵션을 정의합니다.
});</code></pre>
<ul>
<li>Next.js에서 각종 인증 관련 절차를 관리하는 함수</li>
</ul>
<h2 id="nextauth-함수의-옵션">NextAuth 함수의 옵션</h2>
<ul>
<li>providers: 다양한 OAuth 공급자를 설정합니다. 예를 들어 Google, Facebook, GitHub 등과 같은 서비스를 사용하여 로그인할 수 있도록 합니다.</li>
<li>adapter: 데이터베이스 어댑터를 설정합니다. 이를 통해 사용자, 세션, 계정 데이터를 데이터베이스에 저장할 수 있습니다.</li>
<li>callbacks: 로그인, 로그아웃, 세션 생성 등의 다양한 이벤트에 대한 콜백 함수를 정의할 수 있습니다. 예를 들어, 사용자가 로그인할 때 특정 로직을 실행하도록 설정할 수 있습니다.</li>
<li>session: 세션 관리 방식을 설정합니다. 세션 유효기간, 세션 체크 간격 등을 정의할 수 있습니다.</li>
<li>pages: 인증과 관련된 특정 페이지(로그인, 로그아웃, 오류, 등록 페이지 등)의 경로를 설정할 수 있습니다.</li>
<li>events: 로그인, 로그아웃 등의 인증 이벤트에 대한 이벤트 핸들러를 설정할 수 있습니다.</li>
<li>theme: 로그인 페이지의 테마를 light 또는 dark로 설정하거나, 사용자 정의 테마를 적용할 수 있습니다.</li>
</ul>
<h2 id="예시코드">예시코드</h2>
<pre><code class="language-js">import clientPromise from &quot;@/libs/mongoClient&quot;;
import { MongoDBAdapter } from &quot;@auth/mongodb-adapter&quot;;
import NextAuth from &quot;next-auth&quot;
import GoogleProvider from &quot;next-auth/providers/google&quot;

export const authOptions = {
  adapter: MongoDBAdapter(clientPromise),

  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET
    })
  ]
};

const handler = NextAuth(authOptions)

export { handler as GET, handler as POST}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #16  Advanced Routing Concepts 1]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-16-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%9D%BC%EC%9A%B0%ED%8C%85</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-16-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%9D%BC%EC%9A%B0%ED%8C%85</guid>
            <pubDate>Tue, 09 Jan 2024 04:47:24 GMT</pubDate>
            <description><![CDATA[<h2 id="parallel-routes">Parallel Routes</h2>
<ul>
<li><p>parallel Routes 는 더 진보된 라우팅 메커니즘으로, 하나의 레이아웃 안에 여러 페이지를 동시에 렌더링하는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/2a1c287a-bff6-44ea-863b-4b21cbece485/image.png" alt="">
이렇게 하나의 레이아웃 안에 User analytics, Revenue metrics, Notifications 같은 여러 페이지를 렌더링 하는것이다.</p>
</li>
</ul>
<ul>
<li>Next.js에서는 Parallel Routes(병렬 경로)를 &#39;slot&#39;이라고 하는 기능을 사용하여 정의함, 슬롯은 내용을 모듈식으로 구조화하는 데 도움을 줌</li>
<li>병렬 경로는 일반적으로 다른 경로가 동시에 활성화 되어있을 때 사용되며, 이를 통해 다양한 섹션 또는 컴포넌트를 동시에 렌더링할 수 있음.</li>
<li>슬롯을 정의하기 위해 &#39;@folder&#39; 라는 명명 규칙을 사용함, 이는 특정 폴더나 경로를 참조할 때 사용되어지는 방식임</li>
<li>그리고 각 슬롯은 prop으로 해당 layout.js파일에 전달됨</li>
</ul>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/dc0c319b-579f-41c8-a237-7f78be031e36/image.png" alt="">
이와 같은 구조임</p>
<pre><code class="language-js">// app/complex-dashboard/layout.js

export default function DashboardLayout({ children, users, revenue, notifications }) {
  return (
    &lt;div&gt;
      &lt;div&gt;{children}&lt;/div&gt;
      &lt;div style={{ display: &#39;flex&#39; }}&gt;
        &lt;div style={{ display: &#39;flex&#39;, flexDirection: &#39;column&#39; }}&gt;
          &lt;div&gt;{users}&lt;/div&gt;
          &lt;div&gt;{revenue}&lt;/div&gt;
        &lt;/div&gt;
        &lt;div style={{ display: &quot;flex&quot;, flex: 1 }}&gt;{notifications}&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

// app/complex-dashboard/@notification/page.js
import Card from &quot;@/components/card&quot;; // 스타일 컴포넌트

export default function Notifications() {
  return&lt;Card&gt;Notifications&lt;/Card&gt;
}

...
</code></pre>
<p>이와 같은 식으로 &#39;slot&#39; 개념을 사용하면 prop을 따로 정의하지 않아도 폴더 이름을 보고 알아서 인식하여 가져오게 됨</p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/28806f5f-b44f-4269-9679-7682db9f2553/image.png" alt="">
/complex-dashboard 페이지는 위와 같이 출력되게 됨</p>
<h3 id="parallel-routes병렬-경로-이점">parallel routes(병렬 경로) 이점</h3>
<ul>
<li>코드의 관리 용이성</li>
<li>독립적인 경로 처리</li>
<li>하위 네비게이션</li>
</ul>
<h3 id="independent-route-handling독립적인-경로-처리">independent route handling(독립적인 경로 처리)</h3>
<ul>
<li>병렬 경로를 사용하는 큰 이점 중 하나</li>
<li>각 슬롯이 자체적인 로딩 상태와 오류 상태를 가질 수 있음</li>
<li>한 부분에 문제가 생기더라도 전체 페이지의 사용성에 큰 영향을 주지 않고 사용자에게 더 나은 경험을 제공할 수 있음
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/fad57808-029d-4b07-882c-6c833f9085cb/image.png" alt=""></li>
</ul>
<h3 id="sub-navigation-in-routes라우트-내의-하위-네비게이션">Sub-navigation in routes(라우트 내의 하위 네비게이션)</h3>
<ul>
<li>각 슬롯이 마치 미니 애플리케이션처럼 동작할 수 있다는 것을 의미</li>
<li>자체적인 네비게이션과 상태 관리 시스템을 갖추고 있어, 복잡한 애플리케이션 내에서 각 섹션이 독립적으로 작동할 수 있음
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/9c449ba1-1ff4-41c1-bf84-b0c9f1222e29/image.png" alt=""></li>
</ul>
<h2 id="unmatched-routes">Unmatched Routes</h2>
<ul>
<li>URL의 변경이 있을 경우에도 UI 내의 탐색으로 인해 특정 슬롯의 이전 활성 상태를 유지하는 기능</li>
<li>사용자가 UI 내에서 다른 페이지로 이동하더라도 특정 슬롯(병렬 라우트의 한 부분)이 로드된 상태나 사용자 상호작용의 상태를 그대로 유지하게 해줌</li>
<li>변경되지 않은 URL의 슬롯의 상태를 그대로 유지하면서 새로운 URL에 해당하는 슬롯만 업데이트하거나 변경함
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/c30531a1-483f-4295-bb6c-0ef1cf1a5728/image.png" alt="">
예를 들어 @notifications 폴더에 archived 폴더를 만들어 두 페이지 간에 Link를 통해 URL의 변동이 일어난다고 해도 
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/f75c4aa1-8c59-42a2-9b78-e6d5c554be85/image.png" alt="">
Notifications에 해당하는 슬롯을 제외한 나머지는 상태를 유지시키는 것을 의미</li>
<li>또한 페이지를 새로 로드할 때 Next.js는 각 매칭되지 않은 슬롯에 대해 default.js(default.tsx)를 즉시 검색하여 만약 현재 라우트에서 매칭되지 않은 슬롯에 default 파일이 없다면 404오류를 렌더링함</li>
</ul>
<h3 id="defaultjs">default.js</h3>
<ul>
<li>특정 슬롯의 활성 상태를 현재 URL에서 검색할 수 없을 때 사용되는 대체 컨텐츠를 렌더링하기 위한 파일</li>
<li>즉 default 파일은 특정 경로에 대한 슬롯의 내용이 없을 때 보여주는 기본 뷰나 컨텐츠를 제공</li>
<li>잠재적인 라우트 문제를 우아하게 처리하고 사용자가 애플리케이션 내에서 길을 잃지 않도록 하는 데 중요한 역할을 함</li>
<li>예를 들어 /complex-dashboard 에서 각 슬롯의 page.js가 로드되지 않은 상태에서 /complex-dashboard/archived로 접근하게 되면 archived 라우트에서 정의되지 않은 users, revenue, 그리고 layout의 children은 로드 될 정보가 없으니 404 에러가 떠야 하지만 default.js를 만들어 두면 404 에러 대신 default가 출력되게 되는 구조
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/66634b0d-40b0-4278-9565-ea1c9d6efe36/image.png" alt="">
위와 같은 구조일 때
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/747c2a5c-0e93-46b1-9e6f-7cde1710ff17/image.png" alt="">
/archived로 바로 접근 시 default가 대신 출력되게 됨</li>
</ul>
<h2 id="conditional-routes">Conditional Routes</h2>
<ul>
<li>상황에 맞는 페이지를 출력할 수도 있다.</li>
<li>만약 complex-dashboard에 로그인을 해야 진입할 수 있다면 아래와 같이 @login 페이지를 만들어 주고 <img src="https://velog.velcdn.com/images/c_h_hyuk/post/4dcf5a07-4e14-44f9-ae3d-7fb70ba6a9bc/image.png" alt=""><pre><code class="language-js">// app/complex-dashboard/layout.js
</code></pre>
</li>
</ul>
<p>export default function DashboardLayout({ children, users, revenue, notifications, login }) {
  const isLoggedIn = true</p>
<p>  return isLoggedIn ? (
    <div>
      {/* app/complex-dashboard/@children/page.js */}
      <div>{children}</div>
      &lt;div style={{ display: &#39;flex&#39; }}&gt;
        &lt;div style={{ display: &#39;flex&#39;, flexDirection: &#39;column&#39; }}&gt;
          <div>{users}</div>
          <div>{revenue}</div>
        </div>
        &lt;div style={{ display: &quot;flex&quot;, flex: 1 }}&gt;{notifications}</div>
      </div>
    </div>
  ) : (
    login
  );
}</p>
<p>```
이와 같이 layout.js로 login prop을 받아와 isLoggedIn이라는 불린값에 따라 login 페이지 혹은 기존의 complex-dashboard 페이지가 출력되게끔 하는 것이 가능함</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #15 Component Hierarchy]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-15-Component-Hierarchy</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-15-Component-Hierarchy</guid>
            <pubDate>Mon, 08 Jan 2024 06:09:16 GMT</pubDate>
            <description><![CDATA[<h2 id="nextjs의-컴포넌트-계층-구조">Next.js의 컴포넌트 계층 구조</h2>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/ad4d5dae-9950-4d50-9f4d-8a51839ddafc/image.png" alt=""></p>
<ul>
<li>layout 컴포넌트가 최상위</li>
<li>그 안에 template 컴포넌트</li>
<li>template 컴포넌트는 errorboundary와 suspense컴포넌트로 감싸진 page컴포넌트를 포함함</li>
<li>errorboundary는 자식 컴포넌트에서 발생하는 에러를 처리하고, suspense는 데이터 로딩을 처리함(error.js, loading.js)</li>
<li>페이지가 발견되지 않을 시 notfound 컴포넌트가 표시</li>
<li>각각의 역할에 따라 계층적으로 분리하여 애플리케이션의 유지 보수성과 확장성을 향상시키는 데 도움을 줌</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #14 Error Handling]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-14-Error-Handling</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-14-Error-Handling</guid>
            <pubDate>Mon, 08 Jan 2024 06:06:15 GMT</pubDate>
            <description><![CDATA[<h2 id="errorjs">error.js</h2>
<p> <img src="https://velog.velcdn.com/images/c_h_hyuk/post/46a867a7-5dbe-484c-ae12-075df6d46ff8/image.png" alt=""></p>
<ul>
<li>기존의 에러 발생 시 위와 같이 페이지가 출력되는데 이는 좋은 UX가 아니다.</li>
<li>error.js를 만들어주면 해당 라우트 세그먼트에서 에러 발생 시 위의 에러 페이지 대신 커스텀한 에러 페이지를 출력할 수 있다.</li>
</ul>
<pre><code class="language-js">// app/product/[productId]/reviews/[reviewId]/page.js

import { notFound } from &quot;next/navigation&quot;;

function getRandomInt(count) {
  return Math.floor(Math.random() * count)
}

export default function ReviewDetail({ params }) {
  const random = getRandomInt(2)

  if (random === 1) {
    throw new Error(&quot;Error loading review&quot;);
  }

  if (parseInt(params.reviewId) &gt; 1000) {
    notFound();
  }

  return (
    &lt;h1&gt; {params.reviewId}th Review for product {params.productId}&lt;/h1&gt;
  )
}

// app/product/[productId]/reviews/[reviewId]/error.js

&#39;use client&#39;

export default function ErrorBoundary({error}) {
  return &lt;div&gt;{error.message}&lt;/div&gt;
}</code></pre>
<p>해당 라우트 세그먼트에 랜덤으로 에러가 발생하는 상황을 발생시킨 뒤 error.js에 에러 메시지가 출력되는 커스텀 에러 페이지를 만들게 되면 </p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/e7548ca6-4f86-46d1-8b94-97e494602c41/image.png" alt="">
에러 발생 안할 경우</p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/4422e069-db53-4917-aa1d-9ba76232f417/image.png" alt="">
에러 발생한 경우</p>
<p>와 같이 error.js가 출력되게 된다.</p>
<h2 id="recovering-from-errors">Recovering from Errors</h2>
<ul>
<li>에러 발생 시 넘어가진 error.js 페이지에서 recover 하는 방법<pre><code class="language-js">// .../error.js
&#39;use client&#39;
</code></pre>
</li>
</ul>
<p>export default function ErrorBoundary({error, reset}) {
  return <div>
    {error.message}
    <button onClick={reset}> Try again</button>
  </div>
}</p>
<p>// .../page.js
&#39;use client&#39;
import { notFound } from &quot;next/navigation&quot;;</p>
<p>function getRandomInt(count) {
  return Math.floor(Math.random() * count)
}</p>
<p>export default function ReviewDetail({ params }) {
  const random = getRandomInt(2)</p>
<p>  if (random === 1) {
    throw new Error(&quot;Error loading review&quot;);
  }</p>
<p>  if (parseInt(params.reviewId) &gt; 1000) {
    notFound();
  }</p>
<p>  return (
    <h1> {params.reviewId}th Review for product {params.productId}</h1>
  )
}</p>
<p>```</p>
<p>이와 같이 error.js의 ErrorBoundary의 reset기능을 활용해 간단하게 기존의 페이지를 리렌더링 할 수 있음(설정해둔 확률로 에러 발생)</p>
<h2 id="중첩-라우트에서의-error-handling">중첩 라우트에서의 Error handling</h2>
<ul>
<li>에러는 가장 가까운 상위 Error Boundary까지 전파됨</li>
<li>error.js(error.tsx)는 같은 라우트 세그먼트 내에 있는 모든 중첩된 자식 세그먼트에서의 에러까지 처리해준다</li>
<li>라우트의 중첩된 폴더 내에서, error.js(error.tsx)파일을 다른 레벨에 배치함으로써 보다 세밀한 수준의 에러 핸들링 달성이 가능함</li>
<li>즉 가장 가까운 상위 디렉토리의 error.js를 따라가기 때문에 큰 범위에서의 에러관리, 세밀한 범위에서의 에러관리가 모두 가능하다.</li>
<li>예를 들어, /product/error.js가 있다고 하위 디렉토리에 error.js가 없다면 /product 하위의 모든 라우트 세그먼트에서 에러가 발생 시 /product/error.js의 에러 페이지를 띄우게 됨 </li>
</ul>
<h2 id="레이아웃에서의-error-handling">레이아웃에서의 Error handling</h2>
<ul>
<li>에러 바운더리는 동일한 디렉토리(폴더)에 있는 레이아웃에 생긴 에러를 잡아 낼 수 없는데, 그 이유는 에러 바운더리보다 레이아웃이 더 상위 범주(계층)에 속하고 있기 때문임</li>
<li>따라서 해당 레이아웃에 생기는 에러를 catch하기 위해서는 더 상위에 있는 폴더에 error.js를 위치시키면 된다.</li>
<li>예를 들어 /product/[productId]/layout.js에서의 에러를 커스텀 하기 위해서는 /product/error.js와 같은 디렉토리에 위치시켜야 한다는 뜻이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #13 Loading UI]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-13-Loading-UI</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-13-Loading-UI</guid>
            <pubDate>Mon, 08 Jan 2024 05:49:11 GMT</pubDate>
            <description><![CDATA[<h2 id="loadingjs">loading.js</h2>
<ul>
<li>이 파일은 특정 라우트 세그먼트에서 컨텐츠가 로드되는 동안 사용자에게 보여지는 로딩 상태를 만들기 위한 것</li>
<li>사용자가 새로운 페이지로 이동할 때 바로 로딩 상태가 나타나서 애플리케이션이 반응하고 있고 컨텐츠를 활발히 로드하고 있다는 것을 보장해줌. 이는 사용자에게 애플리케이션이 응답성이 있으며 활동적으로 작동하고 있음을 알려줌</li>
<li>예를 들어 /blog 라우트 세그먼트에서 컨텐츠가 로딩 될 때 까지 로딩페이지를 만들고 싶다면 아래와 같이 간단하게 표현할 수 있다.<pre><code class="language-js">// app/blog/loading.js
export default function Loading() {
return &lt;h1&gt;Loading...&lt;/h1&gt;
}</code></pre>
</li>
</ul>
<h2 id="loadingjs를-사용하면-좋은-점">loading.js를 사용하면 좋은 점</h2>
<ul>
<li>사용자가 새로운 루트로 이동할 때 로딩 상태를 바로 표시할 수 있음.</li>
<li>새로운 루트 세그먼트가 로딩되는 동안에도 상호작용이 가능한 공유 레이아웃을 만들 수 있도록 함. 레이아웃은 로드 된 상태이므로 네비게이션 메뉴나 사이드바 같은 요소들과 계속적인 상호작용이 가능함</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #12 Templates]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-12-Templates</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-12-Templates</guid>
            <pubDate>Mon, 08 Jan 2024 05:29:05 GMT</pubDate>
            <description><![CDATA[<h2 id="template">template</h2>
<ul>
<li>템플릿은 기본적으로 레이아웃과 구조적으로 비슷한 역할을 하지만, 상태관리와 라이프사이클 측면에서 다른 점이 있음</li>
<li>레이아웃처럼 템플릿도 각 자식 레이아웃이나 페이지를 감싸는 역할을 하지만, 사용자가 템플릿을 공유하는 라우트들 사이를 이동할 때, 새로운 컴포넌트 인스턴스가 마운트되고 DOM 요소가 재생성되며, 상태는 보존되지 않고, 효과(effect)가 다시 동기화 됨</li>
<li>즉, 템플릿은 페이지 간 이동할 때마다 상태를 초기화하며, 각 페이지 또는 라우트가 마운트될 때마다 새로 시작함, 이러한 특성은 특정 페이지 또는 라우트들이 각각 독립적인 상태와 생명주기를 가져야 할 때 유용함</li>
<li>템플릿은 template.js 또는 templage.tsx 파일에서 기본 react 컴포넌트를 내보내는 것으로 정의될 수 있으며, 레이아웃과 마찬가지로 children prop을 통해 중첩된 라우트 세그먼트를 렌더링해야 함(layout.js와 구조적으론 동일)</li>
</ul>
<pre><code class="language-js">// app/(auth)/layout.js

&#39;use client&#39;;

import Link from &quot;next/link&quot;;
import { usePathname } from &quot;next/navigation&quot;;
import &#39;./styles.css&#39;
import { useState } from &quot;react&quot;;

const navLinks = [
  { name: &#39;Register&#39;, href: &#39;/register&#39; },
  { name: &#39;Login&#39;, href: &#39;/login&#39; },
  { name: &#39;Forgot Password&#39;, href: &#39;/forgot-password&#39; },
];

export default function AuthLayout({ children }) {
  const pathname = usePathname();
  const [input, setInput] = useState(&#39;&#39;)

  return (
    &lt;div&gt;
      &lt;div&gt;
        &lt;input value={input} onChange={(e) =&gt; setInput(e.target.value)}&gt;&lt;/input&gt;
      &lt;/div&gt;
      &lt;div className=&quot;button-container&quot;&gt;
        {navLinks.map((link) =&gt; {
          const isActive = pathname.startsWith(link.href);

          return (
            &lt;Link
              href={link.href}
              key={link.name}
              className={isActive ? &quot;red&quot; : &quot;blue&quot;}
            &gt;
              {link.name}
            &lt;/Link&gt;
          )
        })}
        {children}
      &lt;/div&gt;
    &lt;/div&gt;
  )
}</code></pre>
<p>(auth)에 해당하는 페이지에 들어가면
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/f3c8a412-02b9-473c-8c88-62dc68300ecd/image.png" alt="">
위와 같이 input값을 입력 가능한 텍스트 박스를 만들었다.
해당 input 텍스트 박스는 layout이므로 register, login, forgot password 페이지를 이동하더라도 동일한 레이아웃을 공유하는 페이지이므로 input값은 그대로 유지된다.
하지만 해당 layout.js 파일의 이름을 template.js로 바꾸게 되면 레이아웃이 아닌 템플릿이 되어 다른 페이지로 이동할 때 마다 템플릿의 특성에 의해 상태를 초기화시켜 input값이 초기화된다.</p>
<p>템플릿과 레이아웃을 함께 사용할 수 있는데 
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/9659e9ab-39b9-4f5f-97b3-a14c87806729/image.png" alt="">
이와 같은 구조를 가지게 된다.</p>
<p>예를 들어 <img src="https://velog.velcdn.com/images/c_h_hyuk/post/b39f0b8c-5b7e-4da1-b0fc-ce75e9db3063/image.png" alt="">
이런 식으로 layout.js와 template.js 파일을 같은 경로에 두게 되면 
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/48b3e8b1-4e05-4007-9def-1a5eb8486aad/image.png" alt="">
이와 같이 레이아웃 안에 템플릿이 들어가는 구조가 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #11 useRouter]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-11-Link-Component-Navigation-2-useRouter</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-11-Link-Component-Navigation-2-useRouter</guid>
            <pubDate>Mon, 08 Jan 2024 04:54:52 GMT</pubDate>
            <description><![CDATA[<h3 id="강의-21"><a href="https://www.youtube.com/playlist?list=PLC3y8-rFHvwjOKd6gdf4QtV1uYNiQnruI">강의</a> 21</h3>
<h2 id="userouter">useRouter</h2>
<ul>
<li>버튼 혹은 링크를 클릭 했을 때, 특정한 기능이 수행되면서 원하는 페이지로 이동하기 쉽게 하기 위해 useRouter라는 훅을 사용함</li>
<li>해당 훅을 사용하면 함수형 컴포넌트에서 Next.js 라우터의 기능을 사용할 수 있음<pre><code class="language-js">// app/order-place/page.js
</code></pre>
</li>
</ul>
<p>&#39;use client&#39;</p>
<p>import { useRouter } from &quot;next/navigation&quot;;</p>
<p>export default function OrderProduct() {
  const router = useRouter()</p>
<p>  const handleClick = () =&gt; {
    console.log(&quot;placing your order&quot;);
    router.push(&#39;/&#39;);
  }</p>
<p>  return (
    &lt;&gt;
      <h1>Order Product</h1>
      <button onClick={handleClick}>Place order</button>
    &lt;/&gt;
  )
}</p>
<pre><code>
/order-place 페이지는 place order 버튼을 클릭 시 placing your order가 콘솔창에 출력되면서 / 페이지로 사용자를 이동시키는 페이지이다.
이와 같이 useRouter는 클라이언트 컴포넌트에서 사용 가능한(클라이언트와 상호작용을 통해 작동하므로) 간편한 라우팅 기능을 가졌으며 push(path)외에도 replace(path), back(), forward() 같은 메서드를 가지고 있음

 - push(path) : 지정된 경로로 클라이언트 사이드 라우트 이동을 함
 - replace(path) : push와 비슷하지만 히스토리 스택에 새로운 엔트리를 추가하는 것이 아니라 현재 엔트리를 대체함
 - back() : 히스토리 스택에서 한 단계 뒤로 이동
 - forward() : 히스토리 스택에서 한 단계 앞으로 이동
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #10 Link Component Navigation]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-10-Link-Component-Navigation</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-10-Link-Component-Navigation</guid>
            <pubDate>Mon, 08 Jan 2024 04:40:18 GMT</pubDate>
            <description><![CDATA[<h3 id="강의-1920번"><a href="https://www.youtube.com/playlist?list=PLC3y8-rFHvwjOKd6gdf4QtV1uYNiQnruI">강의</a> 19~20번</h3>
<h2 id="link-component-navigation">Link Component Navigation</h2>
<ul>
<li>Next.js 애플리케이션 내에서 다른 라우트(경로)간의 클라이언트 측 내비게이션을 가능하게 하는 Link 컴포넌트에 대한 소개</li>
<li>새 페이지를 로드하기 위해 서버에 요청을 보내지 않고, 웹 애플리케이션 내에서 뷰를 변경하는 과정</li>
<li>React의 Link 컴포넌트를 활용</li>
</ul>
<p>예시</p>
<pre><code class="language-js">// app/page.js
import Link from &quot;next/link&quot;

export default function Home() {
  return (
    &lt;&gt;
      &lt;Link href=&quot;/blog&quot;&gt;Blog&lt;/Link&gt;
      &lt;h1&gt;Home Page&lt;/h1&gt;
    &lt;/&gt;
  )
}</code></pre>
<p>Link의 기본적인 사용법은 위와 같고 
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/6d59a631-9a06-4489-a214-c0b977b4501b/image.png" alt="">
이렇게 출력된다. blog버튼을 클릭하면 
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/947178c0-dca5-4fca-85f8-ea2ea0335603/image.png" alt="">
/blog 경로의 페이지를 출력하게 됨</p>
<p>돌아오는 Link를 만들고 싶다면</p>
<pre><code class="language-js">// app/blog/page.js
import Link from &quot;next/link&quot;

export const metadata = {
  title: {
    absolute: &quot;Blog&quot;
  }
}

export default function Blog() {
  return (
    &lt;&gt;
      &lt;Link href=&quot;/&quot;&gt;Home&lt;/Link&gt;
      &lt;h1&gt;My blog&lt;/h1&gt;
    &lt;/&gt;
  )
}</code></pre>
<p>위와 같이 경로를 / 로 해주면 된다
또한 link의 경로를 동적으로 정의 해줄 수도 있는데</p>
<pre><code class="language-js">// app/product/page.js
import Link from &quot;next/link&quot;

export default function ProductList() {
  const productId = 100
  return(
    &lt;&gt;
      &lt;h1&gt;Product List&lt;/h1&gt;
      &lt;h1&gt;Product1&lt;/h1&gt;
      &lt;h1&gt;Product2&lt;/h1&gt;
      &lt;h1&gt;Product3&lt;/h1&gt;
      &lt;h1&gt;&lt;Link href={`/product/${productId}`} replace&gt;Product {productId}&lt;/Link&gt;&lt;/h1&gt;
    &lt;/&gt;
  )
}</code></pre>
<p> 이와 같이 productId의 값을 지역변수로 선언해주고 Link에 넣어주면 해당 변수값(Id)의 링크로 넘어가진다.</p>
<p> replace는 페이지를 넘어갔을 때 바로 이전 방문한 페이지(여기서는 /product)의 히스토리를 대체하여 사용자가 뒤로가기를 했을 때 해당 페이지로 돌아가지 않도록 함, 이는 특정 상황에서 유용하게 작용할 수 있는데, 예를 들어 사용자가 양식을 제출한 후 뒤로 가기를 눌렀을 때 양식 제출 페이지로 돌아가는 것을 방지하고 싶을 때 사용하여 양식을 두번 제출하는 것을 방지할 수 있다</p>
<p>또한 Link는 다양하게 응용될 수 있는데
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/c68676c4-d5c8-40cc-be6b-50b34bc8dc75/image.png" alt=""></p>
<p>이와 같이 Link Component에 map을 활용할 수 있고, 출력되는 페이지는 
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/eca4a6ba-d7c1-448f-8a14-fcf77193449c/image.png" alt="">
이와 같으며 각 버튼을 클릭 할 경우 버튼은 그대로 남게 되고(layout이므로) 해당 URL에 해당하는 페이지가 출력된다.</p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/410a8636-a190-4270-b346-ea2c71bcd65e/image.png" alt="">
또한 이와 같이 usePathname을 사용해서 브라우저의 경로명을 가져와, 활성화된 내비게이션 링크를 가져온 후, active 여부에 따라 css를 적용하는 것도 가능하다.</p>
<pre><code class="language-css">/* app/(auth)/styles.css */
.button-container *{
  padding: 0 10px;
  text-decoration: none;
}

.red {
  color: red;
  font-weight: bold;
}

.blue {
  color: blue;
  font-weight: lighter;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[WebSocket]]></title>
            <link>https://velog.io/@c_h_hyuk/WebSocket</link>
            <guid>https://velog.io/@c_h_hyuk/WebSocket</guid>
            <pubDate>Fri, 05 Jan 2024 13:19:00 GMT</pubDate>
            <description><![CDATA[<h2 id="웹소켓">웹소켓</h2>
<ul>
<li>실시간, 양방향 통신을 웹 클라이언트와 서버 간에 가능하게 하는 기술</li>
<li>전통적인 HTTP 통신과 다르게, 웹소켓은 지속적 연결을 제공하여 서버와 클라이언트가 언제든 서로에게 데이터를 보낼 수 있게 함, 실시간 애플리케이션에 매우 적합</li>
</ul>
<h2 id="작동-방식">작동 방식</h2>
<ul>
<li>연결 초기화 : 클라이언트가 서버에 연결 요청을 보냄(사용자가 웹 페이지를 열 때)</li>
<li>핸드셰이크 과정 : 서버는 요청을 받고 웹소켓 연결을 수락함(사용자가 채팅 앱을 열면 서버는 이를 인식하고 연결을 확립함)</li>
<li>데이터 교환 : 클라이언트와 서버 간에 지속적인 연결이 맺어지며, 실시간으로 데이터를 주고받을 수 있음(채팅 앱에서 사용자가 메시지를 보내면, 해당 메시지가 서버를 거쳐 다른 사용자에게 즉시 전달)</li>
</ul>
<h2 id="사용-이유">사용 이유</h2>
<ul>
<li>실시간 통신 가능</li>
<li>낮은 오버헤드 : 추가적인 HTTP 요청 없이 핸드셰이크를 함으로써 데이터 교환이 가능해 통신 오버헤드가 낮음</li>
<li>양방향 통신 : 클라이언트와 서버가 양방향 통신이 가능</li>
</ul>
<h2 id="사용-예시">사용 예시</h2>
<ul>
<li>채팅 애플리케이션</li>
<li>온라인 게임</li>
<li>금융 애플리케이션</li>
<li>실시간 알림</li>
</ul>
<pre><code class="language-js">// express 서버에 웹소켓
const express = require(&#39;express&#39;);
const http = require(&#39;http&#39;);
const WebSocket = require(&#39;ws&#39;);

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

wss.on(&#39;connection&#39;, function connection(ws) {
  ws.on(&#39;message&#39;, function incoming(message) {
    console.log(&#39;received: %s&#39;, message);
    ws.send(`Server received: ${message}`);
  });
});

app.get(&#39;/&#39;, (req, res) =&gt; {
  res.send(&#39;Hello, World!&#39;);
});</code></pre>
<h2 id="인기-있는-웹소켓-라이브러리-및-프레임워크">인기 있는 웹소켓 라이브러리 및 프레임워크</h2>
<ul>
<li>ws(WebSocket) : Node.js용 가벼운 웹소켓 라이브러리, 간단하고 빠르며 확장성이 뛰어남</li>
<li>Socket.IO : 실시간 통신을 위한 매우 인기 있는 라이브러리, 자동 재연결, 방(Room)개념, 여러 트랜스포트(fallback) 지원 등 고급 기능을 제공</li>
<li>WebSocket-Node : ws와 비슷하지만 다른 API와 추가 기능 제공</li>
<li>SockJS : WebSocket이 지원되지 않는 오래된 브라우저에서도 사용할 수 있는 라이브러리</li>
<li>SignalR(ASP.NET) : ASP.NET 개발자를 위한 웹소켓 및 실시간 통신 라이브러리</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Virtual DOM ]]></title>
            <link>https://velog.io/@c_h_hyuk/Virtual-DOM</link>
            <guid>https://velog.io/@c_h_hyuk/Virtual-DOM</guid>
            <pubDate>Fri, 05 Jan 2024 07:26:16 GMT</pubDate>
            <description><![CDATA[<h2 id="virtual-dom가상-돔">Virtual DOM(가상 돔)</h2>
<ul>
<li>실제 DOM 트리의 사본으로, 웹 페이지의 UI를 표현하는, 메모리에 존재하는 가상의 DOM</li>
<li>효율적인 UI 업데이트와 빠른 렌더링을 가능하게 함</li>
</ul>
<h2 id="작동-원리-in-react">작동 원리 in react</h2>
<ul>
<li>초기 렌더링 시 실제 돔을 기반으로 가상 돔을 메모리에 띄움</li>
<li>UI에 변경이 감지되면 React는 새로운 가상 돔을 만들어 기존의 가상 돔과 비교하여 변경점 확인함</li>
<li>변경된 부분만 실제 돔에 업데이트하여 필요한 부분만 렌더링 되도록 함</li>
</ul>
<h2 id="react를-사용하는-이유">React를 사용하는 이유</h2>
<ul>
<li>가상 돔 활용하여 렌더링 성능 향상</li>
<li>컴포넌트 기반의 독립적이고 재사용 가능한 구조</li>
<li>UI를 상태에 따라 선언적으로 표현하여 가독성과 유지보수 용이</li>
<li>강력한 생태계와 커뮤니티를 가지고 있어 개발 편의성이 높음</li>
<li>다양한 웹가 모바일 애플리케이션 개발에 적용할 수 있으며, Redux, MobX등의 상태 관리 라이브러리와 통합 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[불변성 ]]></title>
            <link>https://velog.io/@c_h_hyuk/%EB%B6%88%EB%B3%80%EC%84%B1-44re3yky</link>
            <guid>https://velog.io/@c_h_hyuk/%EB%B6%88%EB%B3%80%EC%84%B1-44re3yky</guid>
            <pubDate>Fri, 05 Jan 2024 07:08:39 GMT</pubDate>
            <description><![CDATA[<h2 id="불변성">불변성</h2>
<ul>
<li>데이터가 생성된 후 변경되지 않는다는 개념</li>
<li>함수형 프로그래밍에서 특히 중요한 원칙으로 데이터의 안정성과 예측 가능성을 높이는 데 기여함</li>
</ul>
<h2 id="자바스크립트에서-불변성이-중요한-이유">자바스크립트에서 불변성이 중요한 이유</h2>
<ul>
<li>예측 가능한 코드 : 함수나 앱의 동작이 예측 가능해짐</li>
<li>부작용 최소화 : 함수가 외부 상태를 변경하지 않으므로, side effect(부작용)이 줄어듬</li>
<li>병렬 처리 용이 : 여러 스레드나 프로세스에서 동시에 데이터를 안전하게 읽을 수 있음</li>
<li>버그 감소 : 데이터가 의도치 않게 변경되는 버그를 방지할 수 있음</li>
<li>리액트 및 리덕스와의 호환성 : React, Redux는 불변성에 최적화 되어있음</li>
</ul>
<h2 id="불변성-유지-방법">불변성 유지 방법</h2>
<ul>
<li>원시 값(Primitive Values) : 자바스크립트의 원시 값(숫자, 문자열, 불린)은 기본적으로 불변임</li>
<li>불변 객체 생성 : 객체의 속성을 변경하는 대신 동결하여 속성 변경을 방지함, Object.freeze()로 객체를 동결하여 속성 변경을 방지, 또는 스프레드 연산자나 Object.assign()을 사용하여 새 객체를 만들어 속성을 복사함(기존 객체는 그대로 유지)</li>
<li>함수형 프로그래밍 기법 : 순수 함수(pure functions)를 사용하여 외부 상태를 변경하지 않음, push,pop,splice 같은 변경 메서드보단, map,filter,concat,slice 같은 새 배열을 반환하는 메서드를 사용</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Prototype in JS]]></title>
            <link>https://velog.io/@c_h_hyuk/Prototype-in-JS</link>
            <guid>https://velog.io/@c_h_hyuk/Prototype-in-JS</guid>
            <pubDate>Fri, 05 Jan 2024 06:31:04 GMT</pubDate>
            <description><![CDATA[<h2 id="프로토타입의-기본-개념">프로토타입의 기본 개념</h2>
<ul>
<li>객체의 속성과 메서드를 다른 객체와 공유하기 위한 메커니즘</li>
<li>모든 자바스크립트 객체는 &#39;prototype&#39;이라는 숨겨진 속성이 있으며, 이는 다른 객체의 참조를 가리킬 수 있음</li>
<li>Object 관련 메서드는 이미 생성된 개별 객체 인스턴스에 직접 접근하여 속성을 추가하거나 변경</li>
<li>프로토타입 속성은 생성자 함수의 속성을 추가하거나 변경</li>
<li>Object : 만들어진 붕어빵에 크림발라먹기</li>
<li>프로토타입 : 붕어빵 틀을 개조하여 모양 바꾸기<pre><code class="language-js">// 객체 생성자 함수
function Person(name) {
this.name = name
}
</code></pre>
</li>
</ul>
<p>// prototype을 사용하여 Person 객체의 모든 인스턴스에 공통 메서드 추가
Person.prototype.greet = function() {
  return &quot;Hello, my name is &quot; + this.name
}</p>
<p>// Person 객체의 인스턴스 생성
let alice = new Person(&quot;Alice&quot;)
let tom = new Person(&quot;Tom&quot;)</p>
<p>//greet 메서드 호출
console.log(alice.greet()); // Hello, my name is Alice
console.log(tom.greet()); // Hello, my name is Tom</p>
<pre><code>## 프로토타입을 사용하는 이유
 - 메모리 효율성 : 모든 인스턴스가 메서드와 속성을 공유하여 메모리 사용을 최소화
 - 코드 재사용성 : 공통 기능을 프로토타입에 정의하여 중복을 줄이고 재사용성을 높임
 - 동적 속성 추가 및 수정 : 실행 중인 객체에 속성과 메서드를 동적으로 추가하거나 변경할 수 있음
 - 확장성 : 프로토타입 체인을 통해 복잡한 객체 계층과 상속 구조를 구성할 수 있음
 - 객체 지향 프로그래밍 지원 : 클래스 기반 언어의 상속과 유사한 패턴을 구현하여 객체 지향적 설계를 지원 
 - 유연성 : 객체의 구조와 행동을 고정하지 않고 실행 중에 변경할 수 있는 유연성 제공
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Metadata]]></title>
            <link>https://velog.io/@c_h_hyuk/Metadata</link>
            <guid>https://velog.io/@c_h_hyuk/Metadata</guid>
            <pubDate>Thu, 04 Jan 2024 11:07:11 GMT</pubDate>
            <description><![CDATA[<h2 id="메타데이터란">메타데이터란</h2>
<ul>
<li>데이터에 대한 데이터, 다른 데이터를 설명 또는 관리하기 위한 정보</li>
<li>데이터를 관리, 검색, 해석, 통합 등을 할 때 데이터의 기준과 양식 등을 설명해주기 때문에 효율적으로 데이터 핸들링이 가능해짐</li>
</ul>
<h2 id="종류">종류</h2>
<ul>
<li>구조적 메타데이터 : 데이터의 형식, 관계 및 기타 구조적 특성을 설명, 데이터베이스의 테이블 구조나 XML문서의 스키마 등</li>
<li>기술적 메타데이터 : 데이터의 기술적 측면, 파일 형식, 크기, 생성 날짜, 수정 날짜 등, 사진의 경우 해상도, 카메라 설정 등</li>
<li>행정적 메타데이터 : 데이터 관리와 관련된 정보, 저작권 정보, 사용 권한, 데이터 생성자 등</li>
<li>사용 및 접근성 메타데이터 : 데이터 사용 방법, 접근 권한, 관련 정책 및 절차 등</li>
</ul>
<h2 id="웹-개발에서-메타데이터-사용의-중요성">웹 개발에서 메타데이터 사용의 중요성</h2>
<ul>
<li>검색 엔진 최적화(SEO) : 웹 페이지의 메타 태그는 검색 엔진이 페이지의 내용을 이해하고 적절하게 색인화하는 데 도움을 줌, 페이지의 가시성(Visibility) 향상</li>
<li>웹 사이트의 메타 정보 제공 : 웹 페이지의 저자, 생성 날짜, 키워드, 페이지 설명 등과 같은 중요한 정보를 제공함, 이 정보는 사용자와 검색 엔진에 페이지의 내용과 맥락을 제공</li>
<li>브라우저 호환성 및 표시 제어 : 웹 페이지가 다양한 브라우저와 장치에서 어떻게 표시되는지 제어할 수 있음, 예를 들어 viewport 메타 태그는 모바일 장치에서 페이지의 레이아웃을 제어하는 데 사용됨</li>
<li>보안 및 접근성 : 웹 페이지의 보안 설정을 강화하거나 웹 접근성을 향상시키는 데 사용, HTTP 헤더를 통해 전송되는 보안 관련 메타데이터는 사이트의 보안을 강화하는 데 도움이 될 수 있음</li>
</ul>
<h2 id="주로-사용되어지는-메타-태그">주로 사용되어지는 메타 태그</h2>
<pre><code class="language-html"> - &lt;title&gt; : 웹 페이지의 제목을 정의, 브라우저의 탭, 검색 엔진 결과 등에 표시

 - &lt;meta name=&quot;description&quot; content=&quot;...&quot;&gt; : 페이지의 간단한 설명 제공, 검색 엔진 결과에서 종종 사용 

 - &lt;meta name=&quot;keywords&quot; content=&quot;...&quot;&gt; : 페이지와 관련된 키워드를 나열, 요즘엔 중요성이 떨어짐

 - &lt;meta name=&quot;viewport&quot; content=&quot;...&quot;&gt; : 모바일 브라우저에서 페이지가 어떻게 보여질 지를 제어
                                             반응형 디자인을 위해 사용
 - &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt; : 페이지의 문자 인코딩을 지정

 - &lt;meta property=&quot;og:title&quot; content=&quot;...&quot;&gt;, &lt;meta property=&quot;og:description&quot; content=&quot;...&quot;&gt;,
   &lt;meta property=&quot;og:image&quot; content=&quot;...&quot;&gt; : 소셜 미디어 플랫폼에서 페이지를 공유할 때 사용되는 
                                           Open Graph 프로토콜 태그, 페이지의 제목, 설명, 이미지 등을 정의함</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #9 Metadata]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-9</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-9</guid>
            <pubDate>Thu, 04 Jan 2024 05:28:46 GMT</pubDate>
            <description><![CDATA[<h3 id="강의-1718번"><a href="https://www.youtube.com/playlist?list=PLC3y8-rFHvwjOKd6gdf4QtV1uYNiQnruI">강의</a> 17~18번</h3>
<h2 id="라우팅-메타데이터">라우팅 메타데이터</h2>
<ul>
<li>적절한 검색 엔진 최적화(SEO)를 확보하는 것은 가시성을 높이고 사용자를 끌어들이는 데 중요함</li>
<li>Next.js에서는 각 페이지에 대한 메타데이터를 정의할 수 있는 메타데이터 API를 도입</li>
<li>메타 데이터는 페이지가 공유되거나 인덱싱 될 때 정확하고 관련성 있는 정보가 표시되도록 보장함</li>
<li>메타 데이터 api를 활용해 라우팅 메타데이터를 향상 시키는 방법을 알아보도록 함</li>
</ul>
<h2 id="메타데이터-구성-방법">메타데이터 구성 방법</h2>
<ul>
<li>app 라우터에선 메타 데이터를 layout.js와 page.js에서 각각 구성할 수 있다.(두 가지 방법이 있음을 의미)</li>
<li>메타 데이터는 정적 메타데이터 객체를 내보내거나(export a static metadata object), 동적으로 메타데이터를 생성하는 generateMetadata 함수를 내보낼 수 있음</li>
<li>메타 데이터의 규칙으로는 다음과 같음</li>
</ul>
<ol>
<li>layout.js와 page.js 모두 메타 데이터를 내보낼 수 있음, layout.js에서 메타데이터를 정의하면 그 레이아웃에 포함된 모든 페이지에 적용, page.js에서 메타데이터를 정의하면 해당 페이지에서만 적용</li>
<li>메타 데이터는 루트 레벨에서 최종 페이지 레벨까지 순서대로 읽힘</li>
<li>동일한 라우트에 여러 위치에서 메타데이터가 있을 경우 이들은 결합됨, 그러나 같은 속성을 가진 경우 페이지 메타데이터가 레이아웃 메타데이터를 대체함</li>
</ol>
<ul>
<li>즉 Next.js에선 메타데이터를 페이지나 레이아웃 수준에서 설정할 수 있으며, 페이지마다 구체적인 메타 데이터를 가질 수 있도록 하여 더 나은 SEO 성능을 달성할 수 있게 해줌</li>
</ul>
<pre><code class="language-js">// app/layout.js
export const metadata = {
  title: &#39;Next.js&#39;,
  description: &#39;Generated by Next.js&#39;,
}

export default function RootLayout({ children }) {
  return (/* children과 레이아웃 코드*/)
}</code></pre>
<p>app/layout.js의 메타데이터는 전역으로 적용되어짐</p>
<pre><code class="language-js">// app/about/page.js
export const metadata = {
  title: &quot;About Page&quot;  
}


export default function About() {
  return &lt;h1&gt;about page&lt;/h1&gt;
}</code></pre>
<p>/about 페이지에서만 적용되어지는 메타데이터, 전역 metadata인 title이 있지만 page의 메타데이터가 우선이기 때문에 About page로 표현됨</p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/484ce4b9-66ac-4745-81ef-b7a4dbc54a02/image.png" alt=""></p>
<pre><code class="language-js">// app/product/[productId]/page.js

export const generateMetadata = async ({ params }) =&gt; {
  return {
    title: `product ${params.productId}`
  }
}


export default function ProductDetails({ params }) {
  return (
    &lt;&gt;
      &lt;h1&gt;Details about product {params.productId}&lt;/h1&gt;
    &lt;/&gt;
  )
}</code></pre>
<p>이와 같이 동적 라우팅 되는 페이지의 경우에도 params로 매개변수를 불러와 간단하게 metadata의 설정이 가능함</p>
<p>또한 메타데이터 function은 async function으로도 정의될 수 있는데, 이는 metadata의 컨텐츠를 비동기적으로 불러올 수 있다는 것이다</p>
<pre><code class="language-js">// app/product/[productId]/page.js
export const generateMetadata = async ({ params }) =&gt; {
  const title = await new Promise(resolve =&gt; {
    setTimeout(() =&gt; {
      resolve(`iPhone ${params.productId}`)
    }, 3000)
  })

  return {
    title: `Product ${title}`
  }
}

export default function ProductDetails({ params }) {
  return (
    &lt;&gt;
      &lt;h1&gt;Details about product {params.productId}&lt;/h1&gt;
    &lt;/&gt;
  )
}</code></pre>
<p>해당 예시에선 async, await을 활용한 가장 기본적인 setTimeout 함수를 활용하여 3초를 기다리게 만들었지만, fetch 등을 활용하여 metadata를 동적으로 생성하고 페이지 로드 시에 필요한 데이터를 기다린 후 metadata를 완성할 수 있다. 이러한 방식은 서버로부터 실시간 데이터를 가져와 페이지의 메타데이터에 반영할 때 특히 유용하다.</p>
<h2 id="title-메타데이터">title 메타데이터</h2>
<ul>
<li>title 메타데이터의 경우 웹 페이지의 제목으로, 웹 브라우저의 탭 제목, 검색 엔진 결과 페이지(SERP)의 제목 등에 사용되어짐</li>
<li>사용자의 검색 엔진에게 해당 페이지의 내용을 간략하게 설명하고 SEO, 사용자 경험, 소셜 미디어 공유 등에 대한 중요한 역할을 함</li>
</ul>
<pre><code class="language-js">// app/layout.js

export const metadata = {
  title: {
    absolute: &#39;&#39;,
    default:&#39;Next.js Tutorial - Codevolution&#39;,
    template: &#39;%s | Codevolution&#39;,
  },
  description: &#39;Generated by Next.js&#39;,
}
</code></pre>
<p>이와 같이 title을 세분화 시키면 absolute, default, template로 나눌 수 있음</p>
<ul>
<li><p>default : 기본이 되는 title</p>
</li>
<li><p>template : 동적 title, &quot;%s&quot;가 하위 디렉토리의 metadata.title 값으로 바뀜
예를 들어</p>
<pre><code class="language-js">// app/blog/page.js
export const metadata = {
title: &#39;Blog&#39;,
}
</code></pre>
</li>
</ul>
<p>export default function Blog() {
  return <h1>My blog</h1>
}</p>
<pre><code>이와 같이 하위 디렉토리에서 title을 정의해주면
![](https://velog.velcdn.com/images/c_h_hyuk/post/0fa199f0-2ab2-4332-821f-261cd2417865/image.png)
Blog | Codevolution 과 같이 %s가 하위 디렉토리의 metadata.title 값에 따라 동적으로 변하는 것을 확인할 수 있음

- absolute : template가 동적으로 변하는 title이라면 absolute는 title값을 고정시켜줘야 할 경우 사용함
```js
// app/blog/page.js
export const metadata = {
  title: {
    absolute: &quot;Blog&quot;
  }
}

export default function Blog() {
  return &lt;h1&gt;My blog&lt;/h1&gt;
}</code></pre><p>이와 같이 하위 디렉토리에서 title을 absolute로 정의해주면
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/18e748cb-28d9-4351-a1fe-ab28437f54ef/image.png" alt="">
이와 같이 absolute로 정의한 title이 출력되는 것을 확인할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #8 Layouts, Nested Layouts, Route Group Layout]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-8-Layouts-Nested-Layouts-Route-Group-Layout</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-8-Layouts-Nested-Layouts-Route-Group-Layout</guid>
            <pubDate>Thu, 04 Jan 2024 03:24:07 GMT</pubDate>
            <description><![CDATA[<h3 id="강의-1416번"><a href="https://www.youtube.com/playlist?list=PLC3y8-rFHvwjOKd6gdf4QtV1uYNiQnruI">강의</a> 14~16번</h3>
<h2 id="레이아웃">레이아웃</h2>
<ul>
<li>페이지는 라우트에 따라 고유한 UI이다</li>
<li>레이아웃은 앱의 여러 페이지들 사이에서 공유 되어진다</li>
</ul>
<h2 id="레아아웃-만드는-법">레아아웃 만드는 법</h2>
<ul>
<li><p>레이아웃은 layout.js 또는 layout.tsx 파일에 기본으로 내보내진(export) React 컴포넌트를 통해 정의할 수 있다.</p>
</li>
<li><p>이 컴포넌트는 children prop을 포함해야 하며, 이 prop은 렌더링 시 자식 페이지의 내용을 담게 된다.</p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/5696fc13-e89d-4ce5-96ae-440eb5706dfc/image.png" alt="">
app 폴더 바로 아래 있는 layout.js는 topmost layout 또는 root layout이라 하며,필수적으로 모든 next.js 애플리케이션에 레이아웃된다. 해당 파일은 지우더라도 next.js 애플리케이션을 시작할때 regenerate된다.</p>
</li>
</ul>
<pre><code class="language-js">// layout.js
export const metadata = {
  title: &#39;Next.js&#39;,
  description: &#39;Generated by Next.js&#39;,
}

export default function RootLayout({ children }) {
 return (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;body&gt;{children}&lt;/body&gt;
    &lt;/html&gt;
   )
}

// html의 body 태그 내에 아래와 같이 레이아웃을 만들어 줄 수 있음
export default function RootLayout({ children }) {
  return (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;body&gt;
        &lt;header
          style={{
            backgroundColor: &quot;lightblue&quot;,
            padding: &quot;1rem&quot;,
          }}
        &gt;
        &lt;p&gt;Header&lt;/p&gt;
      &lt;/header&gt;
      {children}
      &lt;footer 
        style ={{
          backgroundColor: &quot;ghostwhite&quot;,
          padding: &quot;1rem&quot;
        }}&gt;
        &lt;p&gt;Footer&lt;/p&gt;
      &lt;/footer&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  )
}</code></pre>
<p>이렇게 root layout에 header 태그와 footer 태그를 추가해주면
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/3ee993b9-2127-4b36-9a60-3dbb4aecab95/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/9cb1eb4b-0fd7-498e-8370-dc690d5ee868/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/84636483-a5f0-4d0e-834d-089af8409058/image.png" alt=""></p>
<p>이렇게 모든 next.js의 페이지에 뜨게 된다</p>
<h2 id="특정-페이지에서-다른-컨텐츠의-레이아웃을-추가시키고-싶은-경우">특정 페이지에서 다른 컨텐츠의 레이아웃을 추가시키고 싶은 경우</h2>
<ul>
<li><p>예를 들어 product의 detail page에 접근했을 때 product detail에 해당하는 레이아웃 컨텐츠를 추가시키고 싶은 경우</p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/bbc6dc3a-5a30-4724-9aa3-0c9085017ff0/image.png" alt=""></p>
</li>
</ul>
<p>컨텐츠를 추가하고 싶은 페이지의 경로(여기선 [productId] 폴더)에 layout.js를 만들어주면 
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/5cd02313-4462-4e5b-9766-5a38f3f179b6/image.png" alt="">
해당 이미지의 Header,Footer(root layout)안에 Featured product(productDetailLayout)이 중첩되어 레아아웃 된다.
이걸 중첩된 레이아웃(Nested Layout)이라 함</p>
<p>만약 라우트 그룹을 만들고 해당 라우트 그룹에서 추가적인 레이아웃 컨텐츠를 만들고 싶으면
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/77d34ca6-0cb9-4c9c-b7e7-e45399aa1a54/image.png" alt="">
이와 같이 경로를 지정해주면 /login, /register 경로에서만 AuthLayout이 출력되게 된다.
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/e9376ed5-9da1-4e1b-bf84-7c031011e6f0/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 14 시작하기 #7 Route Groups]]></title>
            <link>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-7-Route-Groups</link>
            <guid>https://velog.io/@c_h_hyuk/Next.js-14-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-7-Route-Groups</guid>
            <pubDate>Wed, 03 Jan 2024 09:21:15 GMT</pubDate>
            <description><![CDATA[<h3 id="강의-13"><a href="https://www.youtube.com/playlist?list=PLC3y8-rFHvwjOKd6gdf4QtV1uYNiQnruI">강의</a> 13</h3>
<h2 id="라우트-그룹">라우트 그룹</h2>
<ul>
<li>개발자가 웹 애플리케이션의 라우트(경로)를 논리적으로 그룹화 할 수 있게 해주는 기능</li>
<li>이것은 URL 경로 구조에 영향을 주지 않으면서 관련 라우트를 하나로 묶을 수 있음</li>
</ul>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/b8280503-af59-4f18-91d5-5cb08d7d14f8/image.png" alt="">
예를 들어 register, login, forgot-password를 하나의 라우트로 그룹화 시키고자 한다</p>
<p>위와 같이 폴더 구조를 만들면 /register, /login, /forgot-password 경로에 라우트되는데</p>
<p><img src="https://velog.velcdn.com/images/c_h_hyuk/post/81c62190-08df-40e3-a201-61567d8565cf/image.png" alt="">
이와 같이 auth 폴더 밑으로 만들어주면 되긴 한다. 실제로 이건 좋은 방법이다 하지만 이렇게 하면 URL이 /auth/register와 같이 된다. URL에 auth가 들어가는건 인증 라우트라는 걸로 받아들여 질 수 있지만 마케팅이나 분석과 같은 다른 그룹에는 적합하지 않을 수 있다. 그래서 라우트 그룹 개념이 필요하다
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/d489e8e8-f3b8-4237-80d6-481a107df73f/image.png" alt="">
이와 같이 auth 폴더의 폴더명을 소괄호로 감싸주면
<img src="https://velog.velcdn.com/images/c_h_hyuk/post/338b00cc-24fa-4fe3-827f-4469bd06b9e1/image.png" alt="">
이와 같이 라우트 경로에 auth를 없앨 수 있다.</p>
<h2 id="라우트-그룹을-쓰는-이유">라우트 그룹을 쓰는 이유</h2>
<ul>
<li>코드의 구성 정리 : 코드 구성을 깔끔하게 정리하고 관리 가능, 라우트를 찾기 쉽고 유지보수에 도움</li>
<li>중복 제거 : 경로의 공통 부분을 한번만 작성하고 그룹 내의 모든 라우트에 대해 이를 재사용할 수 있음</li>
<li>미들웨어 적용 : 특정 그룹의 라우트에 공통된 미들웨어(예: 인증, 로깅, 에러 처리 등)을 적용하기 용이함</li>
<li>보안 강화 : 특정 라우트 그룹에 대한 접근 제한이나 권한을 쉽게 과닐 가능</li>
<li>라우트 관리의 용이성 : URL 구조를 변경하거나 새로운 라우트를 추가할 때 더 적은 노력으로 이를 관리할 수 있음, 또한 API 버전 관리나 서브도메인 관리에도 유용</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>