<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>R 스토리</title>
    <link>https://studyhardgogo.tistory.com/</link>
    <description>작업하거나 공부하면서 경험한 것들을 정리하는 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Tue, 7 Jul 2026 20:14:09 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>아랄라랄라</managingEditor>
    <image>
      <title>R 스토리</title>
      <url>https://tistory1.daumcdn.net/tistory/2912091/attach/17bafddd8174449cb28de60b214d4519</url>
      <link>https://studyhardgogo.tistory.com</link>
    </image>
    <item>
      <title>[Storybook] Next.js 관리자 페이지에 Storybook을 붙이면서 알게 된 핵심 개념 정리</title>
      <link>https://studyhardgogo.tistory.com/380</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js로 관리자 페이지를 만들면서 Storybook을 함께 적용해보고 있다.&lt;br /&gt;처음에는 단순히 &amp;ldquo;컴포넌트를 따로 볼 수 있는 도구&amp;rdquo; 정도로만 이해했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 Alert, Dropdown, Modal 같은 컴포넌트의 Story를 만들다 보니 몇 가지 꼭 알아야 할 개념이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 Storybook을 처음 적용하면서 이해한 핵심 내용을 정리해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Storybook은 페이지보다 컴포넌트를 보기 위한 도구다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storybook은 관리자 페이지 전체를 실행하는 도구라기보다, 버튼이나 모달 같은 개별 UI 컴포넌트를 따로 꺼내서 확인하는 도구에 가깝다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 관리자 페이지에는 이런 컴포넌트들이 반복해서 사용된다.&lt;/p&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Button
Badge
Alert
Modal
Dropdown
Input
Table
Pagination
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 컴포넌트를 실제 페이지에 붙이기 전에 Storybook에서 먼저 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;Button&amp;gt;저장&amp;lt;/Button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;Alert
  variant=&quot;success&quot;
  title=&quot;완료&quot;
  message=&quot;정상 처리되었습니다.&quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;Modal isOpen={true} onClose={() =&amp;gt; {}}&amp;gt;
  모달 내용
&amp;lt;/Modal&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Storybook은 &amp;ldquo;이 컴포넌트가 어떤 props를 받았을 때 어떻게 보이는지&amp;rdquo; 확인하는 공간이라고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Story를 만들기 전에 props를 먼저 확인해야 한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storybook 파일을 만들 때 가장 먼저 확인해야 하는 것은 컴포넌트의 Props다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Alert 컴포넌트가 아래와 같은 props를 받는다고 가정해보자.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;interface AlertProps {
  variant: &quot;success&quot; | &quot;error&quot; | &quot;warning&quot; | &quot;info&quot;;
  title: string;
  message: string;
  showLink?: boolean;
  linkHref?: string;
  linkText?: string;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 것은 ? 표시다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;showLink?: boolean;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;?가 붙어 있으면 선택값이고, 붙어 있지 않으면 필수값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 필수 props는 아래 3개다.&lt;/p&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;variant
title
message
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Storybook에서도 이 값들은 기본적으로 넣어줘야 한다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;args: {
  variant: &quot;success&quot;,
  title: &quot;처리가 완료되었습니다.&quot;,
  message: &quot;요청한 작업이 정상적으로 완료되었습니다.&quot;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 선택 props는 필요한 Story에서만 넣으면 된다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;export const WithLink: Story = {
  args: {
    variant: &quot;info&quot;,
    title: &quot;추가 안내가 있습니다.&quot;,
    message: &quot;자세한 내용은 링크를 통해 확인할 수 있습니다.&quot;,
    showLink: true,
    linkHref: &quot;/&quot;,
    linkText: &quot;자세히 보기&quot;,
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하면 Story를 만들 때 흐름은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;컴포넌트 Props 확인
&amp;rarr; 필수 props 확인
&amp;rarr; 기본 args에 필수 props 넣기
&amp;rarr; 선택 props는 필요한 케이스에서만 사용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;args는 컴포넌트에 전달하는 props 값이다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storybook을 만들다 보면 args라는 값을 자주 사용하게 된다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;args: {
  variant: &quot;success&quot;,
  title: &quot;성공&quot;,
  message: &quot;정상 처리되었습니다.&quot;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 낯설 수 있지만, 어렵게 생각할 필요는 없다.&lt;br /&gt;args는 컴포넌트에 넣어주는 props 값이라고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 실제로 아래처럼 컴포넌트를 사용하는 것과 비슷하다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;Alert
  variant=&quot;success&quot;
  title=&quot;성공&quot;
  message=&quot;정상 처리되었습니다.&quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storybook 화면에서는 이 args 값을 Controls 패널에서 직접 바꿔볼 수도 있다.&lt;br /&gt;즉, Storybook은 props 값을 바꿔가며 컴포넌트가 어떻게 변하는지 확인할 수 있게 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단순한 컴포넌트는 args만으로 충분하다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼, 배지, 알림처럼 props 값만 바꾸면 화면이 달라지는 컴포넌트는 보통 args만으로 충분하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Alert 컴포넌트의 Story는 이런 식으로 만들 수 있다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import type { Meta, StoryObj } from &quot;@storybook/react&quot;;
import Alert from &quot;./Alert&quot;;

const meta = {
  title: &quot;UI/Alert&quot;,
  component: Alert,
  tags: [&quot;autodocs&quot;],
  args: {
    variant: &quot;success&quot;,
    title: &quot;처리가 완료되었습니다.&quot;,
    message: &quot;요청한 작업이 정상적으로 완료되었습니다.&quot;,
  },
} satisfies Meta&amp;lt;typeof Alert&amp;gt;;

export default meta;

type Story = StoryObj&amp;lt;typeof meta&amp;gt;;

export const Success: Story = {
  args: {
    variant: &quot;success&quot;,
    title: &quot;처리가 완료되었습니다.&quot;,
    message: &quot;요청한 작업이 정상적으로 완료되었습니다.&quot;,
  },
};

export const Error: Story = {
  args: {
    variant: &quot;error&quot;,
    title: &quot;처리 중 오류가 발생했습니다.&quot;,
    message: &quot;입력값을 확인한 뒤 다시 시도해주세요.&quot;,
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 컴포넌트는 별도의 상태 관리가 필요하지 않기 때문에 Story 코드도 비교적 단순하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;상태가 필요한 컴포넌트는 render를 사용한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 컴포넌트가 args만으로 충분한 것은 아니다.&lt;br /&gt;Modal이나 Dropdown처럼 열림/닫힘 상태가 필요한 컴포넌트는 별도의 상태 관리가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 모달은 보통 아래와 같은 상태가 필요하다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;const [isOpen, setIsOpen] = useState(false);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우에는 render를 사용해서 Story 안에서 직접 예시 화면을 구성한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function DefaultModalExample() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    &amp;lt;&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setIsOpen(true)}&amp;gt;
        모달 열기
      &amp;lt;/button&amp;gt;

      &amp;lt;Modal
        isOpen={isOpen}
        onClose={() =&amp;gt; setIsOpen(false)}
      &amp;gt;
        모달 내용
      &amp;lt;/Modal&amp;gt;
    &amp;lt;/&amp;gt;
  );
}

export const Default: Story = {
  render: () =&amp;gt; &amp;lt;DefaultModalExample /&amp;gt;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하면 기준은 간단하다.&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;props 값만 바꾸면 되는 컴포넌트 &amp;rarr; args 사용
클릭, 열림/닫힘, 선택값, 입력값 상태가 필요한 컴포넌트 &amp;rarr; render 사용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 다음과 같이 나눌 수 있다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;Button &amp;rarr; args
Badge &amp;rarr; args
Alert &amp;rarr; args
StatusBadge &amp;rarr; args

Modal &amp;rarr; render
Dropdown &amp;rarr; render
DatePicker &amp;rarr; render
SearchFilter &amp;rarr; render
Table &amp;rarr; render 가능성 높음
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;필수 props가 있는 컴포넌트는 meta의 args를 잘 넣어야 한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Modal이나 Dropdown을 Storybook에 올리면서 타입 오류를 만날 수 있다.&lt;br /&gt;대표적으로 이런 오류다.&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;args 속성이 없습니다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 오류는 컴포넌트에 필수 props가 있는데 Story에서 기본 args를 제공하지 않았을 때 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Modal이 아래 props를 필수로 받는다고 해보자.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;interface ModalProps {
  isOpen: boolean;
  onClose: () =&amp;gt; void;
  children: React.ReactNode;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 Story의 meta에도 기본 args를 넣어주는 것이 좋다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;const meta = {
  title: &quot;UI/Modal&quot;,
  component: Modal,
  args: {
    isOpen: true,
    onClose: () =&amp;gt; {},
    children: &amp;lt;div&amp;gt;모달 내용&amp;lt;/div&amp;gt;,
  },
} satisfies Meta&amp;lt;typeof Modal&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해두면 타입 오류를 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Modal과 Dropdown은 Storybook에서 다르게 보일 수 있다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storybook을 쓰면서 헷갈렸던 부분 중 하나는 Modal과 Dropdown이 실제 서비스 화면과 다르게 보일 수 있다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 서비스에서는 모달이 브라우저 전체 화면 위에 뜨지만, Storybook에서는 컴포넌트가 Storybook 미리보기 영역 안에서 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 다음과 같은 문제가 생길 수 있다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;모달이 좁은 영역 안에서 열린다
드롭다운이 잘린다
높이가 부족해서 스크롤이 생긴다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 반드시 컴포넌트 코드가 잘못된 것은 아니다.&lt;br /&gt;Storybook의 실행 환경 특성 때문에 생기는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때는 Storybook 설정에서 레이아웃을 넓게 잡아주는 것이 좋다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;parameters: {
  layout: &quot;fullscreen&quot;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Story 내부에서도 충분한 높이를 확보한다.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;&amp;lt;div className=&quot;min-h-screen p-10&quot;&amp;gt;
  ...
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드롭다운은 이런 식으로 감싸줄 수 있다.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;&amp;lt;div className=&quot;relative h-64 w-64&quot;&amp;gt;
  ...
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모달은 이런 식으로 감싸줄 수 있다.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;&amp;lt;div className=&quot;min-h-screen bg-gray-50 p-10&quot;&amp;gt;
  ...
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Modal이나 Dropdown은 Storybook에서 확인하기 위해 별도의 공간 설정이 필요할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Storybook 파일의 기본 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storybook 파일은 보통 아래 구조를 따른다.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;import type { Meta, StoryObj } from &quot;@storybook/react&quot;;
import Component from &quot;./Component&quot;;

const meta = {
  title: &quot;UI/Component&quot;,
  component: Component,
  tags: [&quot;autodocs&quot;],
  args: {
    // 기본 props
  },
} satisfies Meta&amp;lt;typeof Component&amp;gt;;

export default meta;

type Story = StoryObj&amp;lt;typeof meta&amp;gt;;

export const Default: Story = {
  args: {
    // 이 Story에서 보여줄 props
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 이 구조만 익혀도 충분하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태가 필요한 컴포넌트는 여기에 render를 추가하면 된다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;function Example() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    &amp;lt;Component
      isOpen={isOpen}
      onClose={() =&amp;gt; setIsOpen(false)}
    /&amp;gt;
  );
}

export const Default: Story = {
  render: () =&amp;gt; &amp;lt;Example /&amp;gt;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storybook을 처음 적용하면서 가장 중요하다고 느낀 점은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. Storybook은 페이지보다 컴포넌트를 보기 위한 도구다.
2. Story를 만들기 전에 props를 먼저 확인해야 한다.
3. 필수 props는 args에 반드시 넣어야 한다.
4. args는 컴포넌트에 전달하는 props 값이다.
5. 단순 컴포넌트는 args만으로 충분하다.
6. 상태가 필요한 컴포넌트는 render와 useState를 사용한다.
7. Modal과 Dropdown은 Storybook 환경에서 잘릴 수 있으므로 layout과 높이 설정이 필요하다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음부터 페이지 전체를 Storybook에 올리려고 하면 복잡해진다.&lt;br /&gt;따라서 버튼, 배지, 알림, 모달, 드롭다운처럼 작은 컴포넌트부터 하나씩 만들어보는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 컴포넌트부터 Story를 만들어두면, 이후 관리자 페이지를 개발할 때 UI를 더 빠르게 확인하고 재사용할 수 있다.&lt;/p&gt;</description>
      <category>Web/react</category>
      <category>storybook</category>
      <category>스토리북</category>
      <author>아랄라랄라</author>
      <guid isPermaLink="true">https://studyhardgogo.tistory.com/380</guid>
      <comments>https://studyhardgogo.tistory.com/380#entry380comment</comments>
      <pubDate>Thu, 18 Jun 2026 13:49:21 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Next.js App Router 경계 정리표</title>
      <link>https://studyhardgogo.tistory.com/379</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  1. Server vs Client 핵심 구조&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Server Component&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Client Component&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;기본 동작&lt;/td&gt;
&lt;td&gt;기본값&lt;/td&gt;
&lt;td&gt;&quot;use client&quot; 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;실행 위치&lt;/td&gt;
&lt;td&gt;서버 (Node.js)&lt;/td&gt;
&lt;td&gt;브라우저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;상태 관리&lt;/td&gt;
&lt;td&gt;❌ 불가&lt;/td&gt;
&lt;td&gt;⭕ useState 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이벤트(onClick)&lt;/td&gt;
&lt;td&gt;❌ 불가&lt;/td&gt;
&lt;td&gt;⭕ 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;router&lt;/td&gt;
&lt;td&gt;❌ 사용 불가&lt;/td&gt;
&lt;td&gt;⭕ useRouter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hooks&lt;/td&gt;
&lt;td&gt;❌ 대부분 불가&lt;/td&gt;
&lt;td&gt;⭕ useEffect, useState&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터 fetch&lt;/td&gt;
&lt;td&gt;⭕ 직접 가능&lt;/td&gt;
&lt;td&gt;⭕ 가능 (보통 API 호출)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  2. &amp;ldquo;무조건 외워야 하는 기준&amp;rdquo;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Server Component에서 가능한 것&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;✔ 데이터 가져오기 (DB / fetch)
✔ props 전달
✔ HTML 렌더링
✔ async/await
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;export default async function Page() {
    const data = await fetch(...)
    return &amp;lt;div&amp;gt;{data}&amp;lt;/div&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Server Component에서 절대 금지&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;❌ useState
❌ useEffect
❌ onClick
❌ useRouter
❌ window / document
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Client Component (&quot;use client&quot;)&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;✔ useState
✔ useEffect
✔ 이벤트 처리
✔ router 사용
✔ form handling
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;capnproto&quot;&gt;&lt;code&gt;&quot;use client&quot;;

import { useRouter } from &quot;next/navigation&quot;;
import { useState } from &quot;react&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  3. router 정리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;❌ 절대 금지&lt;/p&gt;
&lt;pre class=&quot;capnproto&quot;&gt;&lt;code&gt;import { router } from &quot;next/client&quot;;
import router from &quot;next/router&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ App Router 정답&lt;/p&gt;
&lt;pre class=&quot;capnproto&quot;&gt;&lt;code&gt;import { useRouter } from &quot;next/navigation&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용:&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;const router = useRouter();

router.push(&quot;/admin/ads&quot;);
router.refresh();
router.back();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  4. params / dynamic route&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Server Component&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;export default function Page({ params }: {
    params: { id: string }
}) {
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Client Component&lt;/p&gt;
&lt;pre class=&quot;capnproto&quot;&gt;&lt;code&gt;import { useParams } from &quot;next/navigation&quot;;

const params = useParams();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  5. 구조 설계 기준&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✔ 추천 구조&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/app
  /admin
    /ads
      page.tsx          (SERVER - 리스트)
      /[id]
        /edit
          page.tsx      (CLIENT - 수정)
        page.tsx        (SERVER - optional)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✔ UI 컴포넌트 분리&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;components/
  DeleteModal.tsx  &amp;rarr; CLIENT
  AdForm.tsx       &amp;rarr; CLIENT
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  6. 지금 내 프로젝트 기준 핵심 판단&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✔ 올바른 방향&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트 &amp;rarr; Server&lt;/li&gt;
&lt;li&gt;수정 &amp;rarr; Client&lt;/li&gt;
&lt;li&gt;삭제 &amp;rarr; API Route&lt;/li&gt;
&lt;li&gt;이동 &amp;rarr; useRouter&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;❌ 지금까지 에러 원인 패턴&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Server Component
  &amp;darr;
client hook 들어간 컴포넌트 import
  &amp;darr;
router 잘못 import
  &amp;darr;
Class extends undefined 에러
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  7. 에러 빠른 판별법&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 에러 나오면 무조건 이거&lt;/p&gt;
&lt;pre class=&quot;monkey&quot;&gt;&lt;code&gt;Class extends value undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  90% 확률:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;router 잘못 import&lt;/li&gt;
&lt;li&gt;client/server 혼용&lt;/li&gt;
&lt;li&gt;useState 서버에서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  8. 한 줄 최종 요약&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Server는 &amp;ldquo;데이터&amp;rdquo;, Client는 &amp;ldquo;동작&amp;rdquo;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;router / state / event는 무조건 Client로 빼라&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/react</category>
      <author>아랄라랄라</author>
      <guid isPermaLink="true">https://studyhardgogo.tistory.com/379</guid>
      <comments>https://studyhardgogo.tistory.com/379#entry379comment</comments>
      <pubDate>Mon, 18 May 2026 10:47:43 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Next.js + TypeScript + Tailwind CSS 관리자 페이지 만들기 2</title>
      <link>https://studyhardgogo.tistory.com/378</link>
      <description>&lt;h1&gt;프로젝트 시작&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;생성&lt;/h2&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;선택한 옵션&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;App Router&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;src 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;처음 만난 에러&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Missing &amp;lt;html&amp;gt; and &amp;lt;body&amp;gt; tags in the root layout&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 실행하자마자 만난 에러.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;원인&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App Router에서는:&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;layout.tsx가 HTML 뼈대 역할
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 반드시:&lt;/p&gt;
&lt;pre class=&quot;apache&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;태그가 필요했다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;수정&lt;/h1&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    &amp;lt;html lang=&quot;ko&quot;&amp;gt;
      &amp;lt;body&amp;gt;{children}&amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;App Router 구조 이해하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전 React처럼:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;&amp;ldquo;컴포넌트만 만들면 되는 구조&amp;rdquo;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴더 구조 자체가 라우팅이었다.&lt;/p&gt;
&lt;h1&gt;예시&lt;/h1&gt;
&lt;pre class=&quot;nsis&quot;&gt;&lt;code&gt;app/
 ├─ admin/
 │   ├─ ads/
 │   │   ├─ page.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;의미&lt;/h1&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;/admin/ads
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URL이 자동 생성된다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;관리자 페이지 만들기 시작&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 만든 건 광고 목록 페이지였다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;더미 데이터 만들기&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;dummy-data.ts&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;export type AdStatus = &quot;진행중&quot; | &quot;대기&quot; | &quot;종료&quot;;

export type Ad = {
    id: number;
    title: string;
    position: string;
    status: AdStatus;
    startDate: string;
    endDate: string;
};

export const ads: Ad[] = [
    {
        id: 1,
        title: &quot;메인 상단 배너 광고&quot;,
        position: &quot;홈 메인 상단&quot;,
        status: &quot;진행중&quot;,
        startDate: &quot;2026-05-01&quot;,
        endDate: &quot;2026-05-31&quot;,
    },
];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;여기서 처음 느낀 TypeScript의 장점&lt;/h1&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;status 값을 마음대로 못 넣게 막아준다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;status: &quot;완료&quot; ❌
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;TailwindCSS 사용&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 클래스가 너무 길어 보였는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점점:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;&amp;ldquo;HTML 안에서 바로 스타일 조합&amp;rdquo;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하는 방식이 엄청 빠르다는 걸 느꼈다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;반응형도 쉽게 가능&lt;/h1&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;div className=&quot;flex flex-col gap-4 sm:flex-row&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;의미&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모바일:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;세로 배치
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sm 이상:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;가로 배치
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;상세 페이지 만들기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 동적 라우팅.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조:&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;app/admin/ads/[id]/page.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;여기서 이해한 개념&lt;/h1&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;[id] = URL 파라미터
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;예시&lt;/h1&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;/admin/ads/1
/admin/ads/2
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;처음 만난 params 에러&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;에러&lt;/h2&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;params is a Promise
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;원인&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js App Router 최신 버전에서는:&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;params가 Promise 형태일 수 있다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;해결&lt;/h1&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;type Props = {
    params: Promise&amp;lt;{
        id: string;
    }&amp;gt;;
};

export default async function Page({ params }: Props) {
    const { id } = await params;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;여기서 이해한 핵심&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App Router는 전체적으로:&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;async 기반 구조
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라는 것.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Server Component vs Client Component&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 가장 많이 헷갈렸다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;처음엔 이렇게 생각했다&lt;/h1&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;ldquo;수정 페이지도 서버 데이터 쓰니까 Server Component 아닌가?&amp;rdquo;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;하지만 핵심 차이는 이것이었다&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Server Component&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;데이터 조회
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Client Component&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;브라우저 인터랙션
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;예시&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Server Component 가능&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 가져오기&lt;/li&gt;
&lt;li&gt;DB 조회&lt;/li&gt;
&lt;li&gt;페이지 렌더링&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Client Component 필요&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useState&lt;/li&gt;
&lt;li&gt;onClick&lt;/li&gt;
&lt;li&gt;input 입력&lt;/li&gt;
&lt;li&gt;모달&lt;/li&gt;
&lt;li&gt;이벤트 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;여기서 배운 핵심&lt;/h1&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;&amp;ldquo;브라우저에서 동작하면 Client&amp;rdquo;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;use client 에러도 경험&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔:&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;use strict
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 써놓고 왜 안 되는지 한참 헤맸다  &lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;실제로 필요한 건&lt;/h1&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;&quot;use client&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;수정 페이지 만들기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수정 페이지에서는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;input&lt;/li&gt;
&lt;li&gt;select&lt;/li&gt;
&lt;li&gt;state&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 사용했다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;여기서 배운 것&lt;/h1&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;폼 = 거의 Client Component
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;TypeScript select 이벤트도 처음 경험&lt;/h1&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;onChange={(e: React.ChangeEvent&amp;lt;HTMLSelectElement&amp;gt;) =&amp;gt; {
    setStatus(e.currentTarget.value as AdStatus);
}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;처음 느낌&lt;/h1&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;&amp;ldquo;왜 이렇게 길어?&amp;rdquo;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;그런데 이해하고 보니&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TypeScript가:&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;&amp;ldquo;이 이벤트가 select 이벤트라는 걸 명확하게 알려주는 것&amp;rdquo;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이었다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;삭제 모달 만들기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 관리자 페이지에서 자주 쓰는 기능인:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;삭제 버튼 + 확인 모달
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;구조 분리&lt;/h1&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;[id]/page.tsx
└── DeleteModal.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;왜 분리했나?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상세 페이지는:&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;async function
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형태의 Server Component였고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모달은:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useState&lt;/li&gt;
&lt;li&gt;onClick&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 필요했기 때문.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;여기서 이해한 개념&lt;/h1&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Server Component 안에
Client Component를 넣을 수 있다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;API Route 만들기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 진짜 CRUD 느낌이 나기 시작했다.&lt;/p&gt;
&lt;h1&gt;구조&lt;/h1&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;src/app/api/ads/[id]/route.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;App Router에서 API 만드는 법&lt;/h1&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;route.ts = API endpoint
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;DELETE API 작성&lt;/h1&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;export async function DELETE() {
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;fetch 요청&lt;/h1&gt;
&lt;pre class=&quot;accesslog&quot;&gt;&lt;code&gt;await fetch(`/api/ads/${adId}`, {
    method: &quot;DELETE&quot;,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;그런데 DELETE가 안 됐다&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GET은 되는데 DELETE만:&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;404 Not Found
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;진짜 원인&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 params 타입이었다.&lt;/p&gt;
&lt;h1&gt;잘못된 코드&lt;/h1&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;{ params }: { params: { id: string } }
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;해결 코드&lt;/h1&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;{ params }: { params: Promise&amp;lt;{ id: string }&amp;gt; }

const { id } = await params;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;여기서 배운 핵심&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App Router 최신 구조에서는:&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;params도 async 흐름일 수 있다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Turbopack도 처음 이해하게 됨&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 로그에 계속 보이던:&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;turbopack
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Turbopack이란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말하면:&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Next.js 개발 서버를 빠르게 돌려주는 최신 엔진
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;장점&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빠른 실행&lt;/li&gt;
&lt;li&gt;빠른 HMR&lt;/li&gt;
&lt;li&gt;Next.js 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;단점&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;route.ts 인식 문제&lt;/li&gt;
&lt;li&gt;캐시 문제&lt;/li&gt;
&lt;li&gt;POST/DELETE 이상 동작&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 이슈가 있음.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;그래서 실무에서는&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 생기면:&lt;/p&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;rm -rf .next
npm run dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하거나,&lt;/p&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;next dev --no-turbo
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 잠시 끄기도 한다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;이번 프로젝트로 이해한 것들&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✔ App Router 구조&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;폴더 구조 자체가 라우팅
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✔ Server vs Client&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;조회는 서버
인터랙션은 클라이언트
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✔ CRUD 흐름&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;브라우저 &amp;rarr; API &amp;rarr; 데이터 처리
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✔ async 기반 구조&lt;/h2&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;params도 Promise일 수 있다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;느낀 점&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔:&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;&amp;ldquo;Next.js 너무 어려운데?&amp;rdquo;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싶었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관리자 페이지를 실제로 만들면서 배우니까:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;왜 Server Component가 필요한지&lt;/li&gt;
&lt;li&gt;왜 Client Component가 필요한지&lt;/li&gt;
&lt;li&gt;왜 TypeScript를 쓰는지&lt;/li&gt;
&lt;li&gt;왜 App Router가 async 기반인지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금씩 연결되기 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 단순히 문법만 보는 게 아니라:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;&amp;ldquo;실제 기능을 만들며 배우는 방식&amp;rdquo;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 훨씬 이해가 잘 됐다  &lt;/p&gt;</description>
      <category>Web/react</category>
      <author>아랄라랄라</author>
      <guid isPermaLink="true">https://studyhardgogo.tistory.com/378</guid>
      <comments>https://studyhardgogo.tistory.com/378#entry378comment</comments>
      <pubDate>Thu, 14 May 2026 10:33:30 +0900</pubDate>
    </item>
    <item>
      <title>Next.js App Router DELETE API 404 해결기</title>
      <link>https://studyhardgogo.tistory.com/377</link>
      <description>&lt;h1&gt;Next.js App Router DELETE API 404 해결기&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;ldquo;GET은 되는데 DELETE만 404 나는 이유&amp;rdquo;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 &lt;a href=&quot;https://nextjs.org/?utm_source=chatgpt.com&quot;&gt;Next.js&lt;/a&gt; + TypeScript + App Router 기반으로 관리자 페이지 CRUD를 만들다가 꽤 헷갈리는 이슈를 만났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상황은 단순했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/api/ads/1 GET 요청은 정상&lt;/li&gt;
&lt;li&gt;그런데 DELETE 요청만 404&lt;/li&gt;
&lt;li&gt;route.ts 안의 console.log도 실행되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fetch 문제인가?&lt;/li&gt;
&lt;li&gt;API 경로 문제인가?&lt;/li&gt;
&lt;li&gt;use client 문제인가?&lt;/li&gt;
&lt;li&gt;Turbopack 문제인가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엄청 헷갈렸는데, 원인은 의외로 params 구조였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;문제 상황&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;route.ts&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { NextResponse } from &quot;next/server&quot;;
import { ads } from &quot;@/lib/dummy-data&quot;;

export async function DELETE(
    req: Request,
    { params }: { params: { id: string } }
) {
    const id = Number(params.id);

    const index = ads.findIndex((a) =&amp;gt; a.id === id);

    if (index === -1) {
        return NextResponse.json(
            { message: &quot;not found&quot; },
            { status: 404 }
        );
    }

    ads.splice(index, 1);

    return NextResponse.json({
        message: &quot;deleted&quot;,
    });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;DeleteModal.tsx&lt;/h2&gt;
&lt;pre class=&quot;accesslog&quot;&gt;&lt;code&gt;const response = await fetch(`/api/ads/${adId}`, {
    method: &quot;DELETE&quot;,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;발생한 에러&lt;/h1&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;DELETE http://localhost:3000/api/ads/1 404 (Not Found)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 route.ts 안의:&lt;/p&gt;
&lt;pre class=&quot;accesslog&quot;&gt;&lt;code&gt;console.log(&quot;DELETE 들어옴&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조차 실행되지 않았다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;이상했던 점&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저에서 직접:&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;http://localhost:3000/api/ads/1
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접속하면:&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;405 Method Not Allowed
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 의미는:&lt;/p&gt;
&lt;pre class=&quot;oxygene&quot;&gt;&lt;code&gt;라우트 자체는 존재함
하지만 해당 HTTP Method를 처리 못함
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API 경로 자체는 정상&lt;/li&gt;
&lt;li&gt;route.ts도 인식 중&lt;/li&gt;
&lt;li&gt;그런데 DELETE handler만 정상 실행 안 되는 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;009&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/009.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/009.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;진짜 원인&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 params 타입이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 프로젝트 환경:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Next.js 16&lt;/li&gt;
&lt;li&gt;App Router&lt;/li&gt;
&lt;li&gt;React 19&lt;/li&gt;
&lt;li&gt;Turbopack&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 조합에서는 route handler의 params가 Promise 형태로 전달될 수 있다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;잘못된 코드&lt;/h1&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;{ params }: { params: { id: string } }
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 동기 객체라고 가정한 코드였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실제 runtime에서는:&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;params = Promise
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형태로 전달되고 있었다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;해결 방법&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;수정 후&lt;/h2&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;import { NextResponse } from &quot;next/server&quot;;
import { ads } from &quot;@/lib/dummy-data&quot;;

export async function DELETE(
    req: Request,
    { params }: { params: Promise&amp;lt;{ id: string }&amp;gt; }
) {
    const { id } = await params;

    const adId = Number(id);

    const index = ads.findIndex((a) =&amp;gt; a.id === adId);

    if (index === -1) {
        return NextResponse.json(
            { message: &quot;not found&quot; },
            { status: 404 }
        );
    }

    ads.splice(index, 1);

    return NextResponse.json({
        message: &quot;deleted&quot;,
    });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;왜 이게 중요할까?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App Router의 핵심 특징 중 하나는:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;페이지와 API를 비동기 기반으로 통합 처리한다는 것
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 최신 Next.js에서는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;page.tsx&lt;/li&gt;
&lt;li&gt;layout.tsx&lt;/li&gt;
&lt;li&gt;route.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 async 기반 흐름으로 통합되는 방향이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 route.ts에서도 params가 Promise 형태로 전달될 수 있다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;내가 헷갈렸던 포인트&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;page.tsx에서는 이미 이렇게 쓰고 있었다&lt;/h2&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;const { id } = await params;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 route.ts에서는 예전 방식처럼:&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;params.id
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 사용하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;page.tsx는 최신 async 방식&lt;/li&gt;
&lt;li&gt;route.ts는 예전 sync 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 섞여 있었던 것.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;이번에 이해한 핵심&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;App Router에서 params는 &amp;ldquo;항상 일반 객체&amp;rdquo;라고 생각하면 안 된다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경/버전에 따라:&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;params: Promise&amp;lt;{ id: string }&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형태일 수 있다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;정리&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;DELETE만 안 되었던 이유&lt;/h2&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;route.ts에서 params를 동기 객체처럼 사용했기 때문
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결 방법&lt;/h2&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;const { id } = await params;
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;느낀 점&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 이슈로:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Server Component&lt;/li&gt;
&lt;li&gt;Route Handler&lt;/li&gt;
&lt;li&gt;App Router의 async 구조&lt;/li&gt;
&lt;li&gt;params 처리 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 어떻게 연결되는지 조금 더 이해하게 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 App Router는 &amp;ldquo;비동기 기반 프레임워크&amp;rdquo;라는 걸 체감한 디버깅이었다  &lt;/p&gt;</description>
      <category>ETC/이슈노트</category>
      <author>아랄라랄라</author>
      <guid isPermaLink="true">https://studyhardgogo.tistory.com/377</guid>
      <comments>https://studyhardgogo.tistory.com/377#entry377comment</comments>
      <pubDate>Thu, 14 May 2026 10:17:05 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Server vs Client Component 완전 정리</title>
      <link>https://studyhardgogo.tistory.com/376</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Next.js를 처음 배우면 가장 많이 헷갈리는 개념이 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;서버에서 데이터 쓰는 것도 서버 컴포넌트 아닌가?&amp;rdquo;&lt;br /&gt;&amp;ldquo;수정 페이지도 데이터 보여주는데 왜 Client야?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이 글은 이 혼란을 완전히 정리하기 위한 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;1. 핵심 개념: 기준은 &amp;ldquo;데이터&amp;rdquo;가 아니라 &amp;ldquo;실행 위치&amp;rdquo;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js에서 Server / Client를 나누는 기준은 단순하다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Server / Client 구분 기준 = 어디서 실행되느냐
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✔ Server Component&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에서 실행됨&lt;/li&gt;
&lt;li&gt;HTML을 만들어서 브라우저로 전달&lt;/li&gt;
&lt;li&gt;데이터 조회에 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  특징&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useState ❌&lt;/li&gt;
&lt;li&gt;onClick ❌&lt;/li&gt;
&lt;li&gt;useEffect ❌&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;&amp;ldquo;그냥 화면 만들어서 보여주는 역할&amp;rdquo;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✔ Client Component&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저에서 실행됨&lt;/li&gt;
&lt;li&gt;사용자 인터랙션 처리&lt;/li&gt;
&lt;li&gt;상태 관리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  특징&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useState ⭕&lt;/li&gt;
&lt;li&gt;onChange ⭕&lt;/li&gt;
&lt;li&gt;onClick ⭕&lt;/li&gt;
&lt;li&gt;useParams ⭕&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;&amp;ldquo;사용자가 직접 조작하는 화면&amp;rdquo;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;2. 가장 큰 착각&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 사람들이 이렇게 생각한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;❌ 잘못된 생각&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;서버에서 데이터를 쓰면 서버 컴포넌트다
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⭕ 실제 기준&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;데이터를 쓰는지 여부는 중요하지 않다
&amp;ldquo;사용자가 조작하는지&amp;rdquo;가 기준이다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;3. 실제 페이지로 비교&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  상세 페이지 (/ads/[id])&lt;/h2&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;- 데이터 조회
- 화면 출력
- 수정 없음
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Server Component&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✏️ 수정 페이지 (/ads/[id]/edit)&lt;/h2&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;- 기존 데이터 표시
- input 수정
- 상태 변경
- 버튼 클릭
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Client Component&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;4. 핵심 포인트: &amp;ldquo;같은 데이터라도 다르다&amp;rdquo;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 페이지 모두 동일하게 데이터를 사용한다:&lt;/p&gt;
&lt;pre class=&quot;capnproto&quot;&gt;&lt;code&gt;import { ads } from &quot;@/lib/dummy-data&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 중요한 건 이것이다:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;데이터가 아니라 &amp;ldquo;사용 방식&amp;rdquo;이 다르다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;5. 가장 헷갈리는 질문&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;❓ &amp;ldquo;서버로 보내는 것도 서버 아닌가?&amp;rdquo;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답은:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;❌ 아니다
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✔ 이유&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;데이터를 &amp;ldquo;보내는 주체&amp;rdquo;는 항상 브라우저(Client)
데이터를 &amp;ldquo;받는 주체&amp;rdquo;는 서버
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;6. 전체 흐름으로 이해하기&lt;/h1&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;[브라우저]
사용자가 입력/수정
&amp;darr;
Client Component
&amp;darr;
fetch 요청 전송
&amp;darr;
[서버]
데이터 받음
DB 업데이트
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;7. 한 줄 핵심 정리&lt;/h1&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Server = 데이터를 준비하고 화면을 만든다
Client = 사용자의 행동을 처리한다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;8. 실무 기준으로 외우기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js에서 가장 중요한 판단 기준은 이것이다:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;✔ 조회만 한다 &amp;rarr; Server Component
✔ 입력/클릭/상태가 있다 &amp;rarr; Client Component
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;9. 최종 정리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Server Component&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Client Component&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;실행 위치&lt;/td&gt;
&lt;td&gt;서버&lt;/td&gt;
&lt;td&gt;브라우저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;역할&lt;/td&gt;
&lt;td&gt;데이터 준비 / 화면 생성&lt;/td&gt;
&lt;td&gt;사용자 인터랙션&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;상태 관리&lt;/td&gt;
&lt;td&gt;불가능&lt;/td&gt;
&lt;td&gt;가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이벤트&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1 style=&quot;text-align: right;&quot;&gt;마무리&lt;/h1&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;Next.js의 핵심은 &amp;ldquo;데이터가 어디 있느냐&amp;rdquo;가 아니라&lt;br /&gt;&amp;ldquo;누가 화면을 움직이느냐&amp;rdquo;이다.&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;이 기준만 잡히면 Server / Client 구분은 더 이상 헷갈리지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/react</category>
      <author>아랄라랄라</author>
      <guid isPermaLink="true">https://studyhardgogo.tistory.com/376</guid>
      <comments>https://studyhardgogo.tistory.com/376#entry376comment</comments>
      <pubDate>Fri, 8 May 2026 15:51:03 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Next.js + TypeScript + Tailwind CSS 관리자 페이지 만들기 1</title>
      <link>https://studyhardgogo.tistory.com/375</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;대상&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서는 아래와 같은 사람을 기준으로 설명합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML/CSS는 익숙하다&lt;/li&gt;
&lt;li&gt;JavaScript는 초급 수준이다&lt;/li&gt;
&lt;li&gt;React를 아주 조금 들어봤다&lt;/li&gt;
&lt;li&gt;Next.js는 처음이다&lt;/li&gt;
&lt;li&gt;실무 스타일의 관리자 페이지를 만들어보고 싶다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;지금까지 만든 것&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 현재 아래 기능까지 만들었다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/admin
/admin/ads
/admin/ads/[id]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;대시보드
광고 목록
광고 상세
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 흐름을 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 아래 기술들을 사용했다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Next.js
TypeScript
Tailwind CSS
App Router
Dynamic Route
layout.tsx
map()
Link
usePathname()
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Next.js란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js는 React 기반 프레임워크다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말하면:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;React를 더 실무적으로 편하게 쓰게 해주는 도구
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 React만 쓰면 직접 설정해야 하는 것들을:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;라우팅
페이지 구조
서버 기능
최적화
빌드
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js가 자동으로 처리해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 실무에서는 React 단독보다 Next.js를 훨씬 많이 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;왜 TypeScript를 같이 쓰는가?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 Next.js를 만들 때:&lt;/p&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 사용했고,&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;TypeScript: Yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 선택했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;TypeScript란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TypeScript는 JavaScript에 타입 기능을 추가한 언어다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;const name = &quot;홍길동&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 JavaScript.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TypeScript에서는:&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;const name: string = &quot;홍길동&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처럼 타입을 명시할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;타입을 왜 쓰는가?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 광고 데이터를 만든다고 생각해보자.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;{
    id: 1,
    title: &quot;메인 광고&quot;,
    status: &quot;진행중&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 실수로:&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;{
    id: &quot;안녕하세요&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 넣으면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;광고 id는 숫자여야 하는데 문자열이 들어간 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TypeScript는 이런 실수를 미리 잡아준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;개발 실수를 줄여준다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 가장 큰 장점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Tailwind CSS란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 CSS를 이렇게 작성하지 않았다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.box {
    padding: 20px;
    background: white;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;div className=&quot;p-5 bg-white&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처럼 작성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 Tailwind CSS다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Tailwind CSS 장점&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 빠르다&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;div className=&quot;flex items-center justify-between&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 줄로 레이아웃 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 클래스 이름 고민이 없다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 CSS는:&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;.card-box
.card-wrap
.card-inner
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 네이밍 고민이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tailwind는 그런 고민이 거의 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 반응형 작업이 편하다&lt;/h2&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;className=&quot;p-4 lg:p-8&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모바일:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;padding: 16px
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PC:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;padding: 32px
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동 처리.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;App Router란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는:&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;src/app
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴더를 사용하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 App Router 방식이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js 최신 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;App Router 핵심 개념&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴더 이름이 곧 URL이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;src/app/admin/page.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;는:&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/admin
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;src/app/admin/ads/page.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;는:&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;/admin/ads
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;현재 프로젝트 구조&lt;/h1&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;src
 ├─ app
 │   ├─ layout.tsx
 │   ├─ globals.css
 │   │
 │   └─ admin
 │       ├─ layout.tsx
 │       ├─ page.tsx
 │       │
 │       └─ ads
 │           ├─ page.tsx
 │           │
 │           └─ [id]
 │               └─ page.tsx
 │
 ├─ components
 │   └─ admin
 │       ├─ AdminHeader.tsx
 │       └─ AdminSidebar.tsx
 │
 └─ lib
     └─ dummy-data.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;layout.tsx 이해하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 Next.js 초보가 가장 헷갈려하는 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Root Layout&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일:&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;src/app/layout.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 앱 전체의 가장 바깥 껍데기다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 이렇게 만들었다.&lt;/p&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;html lang=&quot;ko&quot;&amp;gt;
    &amp;lt;body&amp;gt;
        {children}
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;왜 html/body가 필요한가?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js App Router에서는:&lt;/p&gt;
&lt;pre class=&quot;apache&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 반드시 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;없으면 이런 에러가 난다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;Missing &amp;lt;html&amp;gt; and &amp;lt;body&amp;gt; tags in the root layout.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;children이란?&lt;/h1&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;{children}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;은:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;실제 페이지 내용이 들어오는 자리
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라고 이해하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/admin
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에 접속하면:&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;src/app/admin/page.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내용이 children에 들어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;관리자 전용 layout&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일:&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;src/app/admin/layout.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 관리자 페이지 전용 공통 레이아웃이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 여기서:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;사이드바
헤더
콘텐츠 영역
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;/admin
/admin/ads
/admin/users
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 관리자 페이지들은 전부 같은 레이아웃을 공유한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;왜 layout을 쓰는가?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 사이드바를 모든 페이지에 직접 넣으면:&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;/admin/page.tsx
/admin/ads/page.tsx
/admin/users/page.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전부 같은 코드를 반복해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;layout.tsx를 쓰면:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;한 번만 작성하면 모든 페이지에 자동 적용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 매우 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;컴포넌트란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는:&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;AdminSidebar
AdminHeader
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 걸 컴포넌트라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;컴포넌트를 왜 쓰는가?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 헤더를 여러 곳에서 사용한다고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트가 없으면:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;복붙
복붙
복붙
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트로 만들면:&lt;/p&gt;
&lt;pre class=&quot;apache&quot;&gt;&lt;code&gt;&amp;lt;AdminHeader /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 줄로 재사용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;map() 이해하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 메뉴와 광고 목록에서 map()을 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;menuItems.map((item) =&amp;gt; {
    return &amp;lt;li&amp;gt;{item.name}&amp;lt;/li&amp;gt;;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;map()이란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열을 반복하는 함수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 반복하면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1
2
3
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나씩 꺼낼 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;광고 목록에서 map()&lt;/h1&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;{ads.map((ad) =&amp;gt; {
    return (
        &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;{ad.title}&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
    );
})}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미는:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;광고 배열을 반복해서 테이블 행을 만들어라
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;key란?&lt;/h1&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;tr key={ad.id}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React는 반복 요소를 구분하기 위해 key가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;각 요소의 고유값
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통:&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;id
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 많이 사용한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Link 컴포넌트&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 a 태그 대신:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;Link href=&quot;/admin/ads&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 사용했다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;왜 a 태그를 안 쓰는가?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js에서는 페이지 이동을 최적화하기 위해 Link를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;빠른 페이지 이동
새로고침 최소화
성능 향상
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;동적 라우트 [id]&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는:&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;src/app/admin/ads/[id]/page.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대괄호 폴더는:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;동적으로 변하는 값
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 의미한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;예시&lt;/h1&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;/admin/ads/1
/admin/ads/2
/admin/ads/3
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1
2
3
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 id가 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;params란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js는 URL의 값을 params로 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;/admin/ads/3
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이면:&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;params.id
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값은:&lt;/p&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;&quot;3&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Next.js 최신 버전에서 바뀐 점&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에는:&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;params.id
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 바로 사용할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 최신 Next.js에서는 params가 Promise가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서:&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;const { id } = await params;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처럼 사용해야 한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;왜 async를 붙였는가?&lt;/h1&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;export default async function AdDetailPage()
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;await를 사용하려면 함수가 async여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;비동기 함수로 만들어야 await 사용 가능
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;find() 이해하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 광고 상세 페이지에서:&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const ad = ads.find((item) =&amp;gt; {
    return item.id === adId;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 사용했다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;find()란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열에서 조건에 맞는 하나를 찾는 함수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;const users = [
    { id: 1, name: &quot;철수&quot; },
    { id: 2, name: &quot;영희&quot; },
];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 id가 2인 사람 찾기:&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;users.find((user) =&amp;gt; {
    return user.id === 2;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과:&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;{ id: 2, name: &quot;영희&quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;notFound()&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는:&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;if (!ad) {
    notFound();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 사용했다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;왜 필요한가?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;/admin/ads/999
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같이 존재하지 않는 페이지 접근 시:&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;404 페이지
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 보내기 위해 사용한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;반응형 작업&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 Tailwind 반응형 문법도 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;className=&quot;p-4 lg:p-8&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;모바일: padding 16px
PC: padding 32px
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Tailwind 반응형 규칙&lt;/h1&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;기본 = 모바일
sm = 작은 태블릿
md = 태블릿
lg = 노트북/PC
xl = 큰 화면
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;예시&lt;/h1&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;className=&quot;flex flex-col lg:flex-row&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미:&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;모바일: 세로
PC: 가로
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;관리자 페이지 반응형 전략&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는:&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;모바일
- 상단 메뉴
- 테이블 가로 스크롤
- 작은 padding

PC
- 왼쪽 사이드바
- 넓은 콘텐츠
- 큰 여백
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전략으로 만들었다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;overflow-x-auto&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 반응형에서 중요한 코드:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;div className=&quot;overflow-x-auto&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;가로 스크롤 허용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이라는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관리자 테이블은 컬럼이 많아서 모바일에서 자주 사용한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;현재 메뉴 활성화&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는:&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;usePathname()
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 사용해서 현재 메뉴를 활성화했다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;usePathname()&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 URL 경로를 가져오는 훅이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;/admin/ads
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이면:&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;const pathname = usePathname();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과:&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;/admin/ads
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;왜 &quot;use client&quot;가 필요한가?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;usePathname은 React 훅이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 훅은 클라이언트 컴포넌트에서만 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서:&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;&quot;use client&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 파일 최상단에 넣었다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;서버 컴포넌트 vs 클라이언트 컴포넌트&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js App Router의 핵심 개념 중 하나다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;서버 컴포넌트&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 상태.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;빠름
성능 좋음
보안 유리
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;클라이언트 컴포넌트&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저에서 동작하는 컴포넌트.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 경우:&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;useState
useEffect
클릭 이벤트
브라우저 API
React Hook
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;정리&lt;/h1&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;기본은 서버 컴포넌트
필요할 때만 use client
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Next.js 최신 스타일이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;지금까지 익힌 실무 개념&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 이미 꽤 많은 핵심 개념을 익혔다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;프로젝트 구조
App Router
layout.tsx
컴포넌트 분리
Tailwind CSS
반응형
map()
find()
Link
동적 라우트
params
notFound()
서버 컴포넌트
클라이언트 컴포넌트
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 실제 관리자 페이지 실무에서도 정말 많이 쓰이는 개념들이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;현재 관리자 페이지 흐름&lt;/h1&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/admin
  &amp;darr;
대시보드

/admin/ads
  &amp;darr;
광고 목록

/admin/ads/1
  &amp;darr;
광고 상세
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;목록 &amp;rarr; 상세
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흐름까지 완성했다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;다음 단계에서 만들 것&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에는 아래 기능들을 만들면 좋다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;광고 등록
광고 수정
폼 입력
input 상태 관리
useState
삭제 버튼
모달
API 연결
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 다음 단계부터:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;폼 처리
상태 관리
이벤트 처리
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 본격적으로 들어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분부터 React 느낌이 강해진다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;지금 가장 중요한 것&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;외우는 것
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보다:&lt;/p&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;&quot;왜 이렇게 구조를 나누는가&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 이해하는 게 훨씬 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;왜 layout을 쓰는가?
왜 컴포넌트를 분리하는가?
왜 map을 쓰는가?
왜 Link를 쓰는가?
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 흐름이 이해되면 Next.js 실력이 정말 빨리 는다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;추천 공부 방법&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 화면 먼저 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나처럼 HTML/CSS가 강하면:&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;UI 먼저
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 훨씬 유리하다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 작은 기능 반복&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;목록
상세
등록
수정
삭제
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 흐름을 계속 반복하면 React 구조가 몸에 익는다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 직접 수정해보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;컬럼 추가
상태 추가
메뉴 추가
카드 UI 변경
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 바꿔보는 게 가장 많이 는다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;마지막 정리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 나는 단순히 예제를 따라친 수준이 아니라:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;실무 관리자 페이지 구조
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 이미 경험하고 있는 단계다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히:&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;layout.tsx
컴포넌트 구조
동적 라우트
반응형 관리자 UI
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 Next.js 실무에서 정말 핵심이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 흐름 그대로 가면:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;실무형 프론트엔드 구조 감각
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 꽤 빠르게 생길 거다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;010&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/010.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/010.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>Web/react</category>
      <author>아랄라랄라</author>
      <guid isPermaLink="true">https://studyhardgogo.tistory.com/375</guid>
      <comments>https://studyhardgogo.tistory.com/375#entry375comment</comments>
      <pubDate>Fri, 8 May 2026 13:17:48 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] 초보의 관리자 페이지 만들기 시작기</title>
      <link>https://studyhardgogo.tistory.com/374</link>
      <description>&lt;p data-end=&quot;182&quot; data-start=&quot;151&quot; data-section-id=&quot;1aedbfq&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;182&quot; data-start=&quot;151&quot; data-section-id=&quot;1aedbfq&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;설치부터 레이아웃, 목록/상세/수정/등록 흐름까지&lt;/b&gt;&lt;/h4&gt;
&lt;p data-end=&quot;182&quot; data-start=&quot;151&quot; data-section-id=&quot;1aedbfq&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;311&quot; data-start=&quot;184&quot; data-ke-size=&quot;size16&quot;&gt;이번에 관리자 페이지 작업을 하게 되면서 Next.js를 처음 제대로 만져보게 됐다.&lt;br /&gt;원래는 React를 아주 조금 알고 있었고, HTML/CSS는 익숙한 편이지만 JavaScript와 Next.js는 거의 초보 수준이었다.&lt;/p&gt;
&lt;p data-end=&quot;311&quot; data-start=&quot;184&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;421&quot; data-start=&quot;313&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 &amp;ldquo;이걸 다 새로 만들어야 하나?&amp;rdquo;라는 막막함이 있었는데,&lt;br /&gt;실제로 하나씩 부딪혀보니 &lt;b&gt;Next.js는 폴더 구조와 페이지 흐름을 익히는 것부터 시작하는 게 중요하다&lt;/b&gt;는 걸 느꼈다.&lt;/p&gt;
&lt;p data-end=&quot;421&quot; data-start=&quot;313&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;이번 글은 내가 로컬에 Next.js를 설치하고, 관리자 페이지의 기본 흐름인&lt;br /&gt;&lt;b&gt;목록 &amp;rarr; 상세 &amp;rarr; 수정 &amp;rarr; 등록&lt;/b&gt;&lt;br /&gt;구조를 만드는 과정까지 정리한 기록이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;536&quot; data-start=&quot;522&quot; data-section-id=&quot;14zrwj6&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 로컬 환경 세팅&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;560&quot; data-start=&quot;538&quot; data-ke-size=&quot;size16&quot;&gt;먼저 Node와 npm 버전을 확인했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1777336398681&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;node -v
npm -v&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;604&quot; data-start=&quot;590&quot; data-ke-size=&quot;size16&quot;&gt;내 환경은 아래와 같았다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;637&quot; data-start=&quot;606&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;624&quot; data-start=&quot;606&quot; data-section-id=&quot;y8u7m9&quot;&gt;Node.js v20.19.2&lt;/li&gt;
&lt;li data-end=&quot;637&quot; data-start=&quot;625&quot; data-section-id=&quot;1ywywxc&quot;&gt;npm 10.8.2&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;672&quot; data-start=&quot;639&quot; data-ke-size=&quot;size16&quot;&gt;버전 자체는 충분했지만, 설치 과정에서 바로 문제가 생겼다.&lt;/p&gt;
&lt;p data-end=&quot;672&quot; data-start=&quot;639&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;702&quot; data-start=&quot;674&quot; data-section-id=&quot;1l0v7d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;설치 중 만난 문제: ECONNRESET&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;742&quot; data-start=&quot;703&quot; data-ke-size=&quot;size16&quot;&gt;create-next-app 실행 시 아래와 같은 에러가 발생했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336427074&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm error code ECONNRESET
npm error network request to https://registry.npmjs.org/create-next-app failed&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;972&quot; data-start=&quot;862&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 npm 설정 문제인 줄 알았지만, 확인해보니 &lt;b&gt;회사 내부망 이슈&lt;/b&gt;였다.&lt;br /&gt;결국 네트워크 문제를 해결한 뒤 다시 설치를 진행했고, 정상적으로 Next.js 프로젝트를 생성할 수 있었다.&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1000&quot; data-start=&quot;979&quot; data-section-id=&quot;mujp08&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. Next.js 프로젝트 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1019&quot; data-start=&quot;1002&quot; data-ke-size=&quot;size16&quot;&gt;설치는 아래 명령어로 진행했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336473545&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx create-next-app@latest admin-next&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1086&quot; data-start=&quot;1072&quot; data-ke-size=&quot;size16&quot;&gt;옵션은 다음처럼 선택했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1194&quot; data-start=&quot;1088&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1105&quot; data-start=&quot;1088&quot; data-section-id=&quot;1umo496&quot;&gt;TypeScript: Yes&lt;/li&gt;
&lt;li data-end=&quot;1119&quot; data-start=&quot;1106&quot; data-section-id=&quot;wgca5w&quot;&gt;ESLint: Yes&lt;/li&gt;
&lt;li data-end=&quot;1138&quot; data-start=&quot;1120&quot; data-section-id=&quot;7ct1ys&quot;&gt;Tailwind CSS: No&lt;/li&gt;
&lt;li data-end=&quot;1159&quot; data-start=&quot;1139&quot; data-section-id=&quot;1yapo2e&quot;&gt;src directory: Yes&lt;/li&gt;
&lt;li data-end=&quot;1177&quot; data-start=&quot;1160&quot; data-section-id=&quot;120gfxz&quot;&gt;App Router: Yes&lt;/li&gt;
&lt;li data-end=&quot;1194&quot; data-start=&quot;1178&quot; data-section-id=&quot;1qrhm62&quot;&gt;Turbopack: Yes&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1277&quot; data-start=&quot;1196&quot; data-ke-size=&quot;size16&quot;&gt;내 경우에는 Bootstrap 기반 UI 감각을 유지한 채 Next.js 구조를 익히는 것이 목적이었기 때문에, Tailwind는 일단 제외했다.&lt;/p&gt;
&lt;p data-end=&quot;1306&quot; data-start=&quot;1279&quot; data-ke-size=&quot;size16&quot;&gt;설치가 끝난 뒤 아래 명령어로 실행까지 확인했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336486801&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd admin-next
npm run dev&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1378&quot; data-start=&quot;1352&quot; data-section-id=&quot;qf06j8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;1378&quot; data-start=&quot;1352&quot; data-section-id=&quot;qf06j8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1378&quot; data-start=&quot;1352&quot; data-section-id=&quot;qf06j8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1378&quot; data-start=&quot;1352&quot; data-section-id=&quot;qf06j8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1378&quot; data-start=&quot;1352&quot; data-section-id=&quot;qf06j8&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 처음 이해한 Next.js 기본 구조&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1412&quot; data-start=&quot;1380&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트를 실행한 뒤 가장 먼저 본 파일은 아래 3개였다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1481&quot; data-start=&quot;1414&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1434&quot; data-start=&quot;1414&quot; data-section-id=&quot;wshfah&quot;&gt;src/app/page.tsx&lt;/li&gt;
&lt;li data-end=&quot;1457&quot; data-start=&quot;1435&quot; data-section-id=&quot;buai1s&quot;&gt;src/app/layout.tsx&lt;/li&gt;
&lt;li data-end=&quot;1481&quot; data-start=&quot;1458&quot; data-section-id=&quot;1l9cfni&quot;&gt;src/app/globals.css&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1507&quot; data-start=&quot;1483&quot; data-ke-size=&quot;size16&quot;&gt;이때 가장 먼저 이해한 개념은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1583&quot; data-start=&quot;1509&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1533&quot; data-start=&quot;1509&quot; data-section-id=&quot;1lgbx70&quot;&gt;page.tsx &amp;rarr; 실제 페이지 화면&lt;/li&gt;
&lt;li data-end=&quot;1558&quot; data-start=&quot;1534&quot; data-section-id=&quot;bg1m2y&quot;&gt;layout.tsx &amp;rarr; 공통 레이아웃&lt;/li&gt;
&lt;li data-end=&quot;1583&quot; data-start=&quot;1559&quot; data-section-id=&quot;7xwshq&quot;&gt;globals.css &amp;rarr; 전역 스타일&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1650&quot; data-start=&quot;1585&quot; data-ke-size=&quot;size16&quot;&gt;그리고 Next.js App Router에서는 &lt;b&gt;폴더 구조가 곧 URL 구조가 된다&lt;/b&gt;는 점이 굉장히 중요했다.&lt;/p&gt;
&lt;p data-end=&quot;1650&quot; data-start=&quot;1585&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1658&quot; data-start=&quot;1652&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;src/app/admin/dashboard/page.tsx&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1714&quot; data-start=&quot;1706&quot; data-ke-size=&quot;size16&quot;&gt;를 만들면 바로&lt;/p&gt;
&lt;p data-end=&quot;1714&quot; data-start=&quot;1706&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;/admin/dashboard&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1753&quot; data-start=&quot;1746&quot; data-ke-size=&quot;size16&quot;&gt;경로가 된다.&lt;/p&gt;
&lt;p data-end=&quot;1753&quot; data-start=&quot;1746&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1796&quot; data-start=&quot;1755&quot; data-ke-size=&quot;size16&quot;&gt;이 구조가 익숙해지기 시작하면서 Next.js가 조금씩 이해되기 시작했다.&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;1822&quot; data-start=&quot;1803&quot; data-section-id=&quot;vt4a3g&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1822&quot; data-start=&quot;1803&quot; data-section-id=&quot;vt4a3g&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1822&quot; data-start=&quot;1803&quot; data-section-id=&quot;vt4a3g&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1822&quot; data-start=&quot;1803&quot; data-section-id=&quot;vt4a3g&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 첫 관리자 페이지 만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1849&quot; data-start=&quot;1824&quot; data-ke-size=&quot;size16&quot;&gt;가장 먼저 만든 페이지는 관리자 대시보드였다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1777336595646&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function DashboardPage() {
    return (
        &amp;lt;main&amp;gt;
            &amp;lt;h1&amp;gt;관리자 대시보드&amp;lt;/h1&amp;gt;
            &amp;lt;p&amp;gt;첫 관리자 페이지입니다.&amp;lt;/p&amp;gt;
        &amp;lt;/main&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2077&quot; data-start=&quot;1996&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2077&quot; data-start=&quot;1996&quot; data-ke-size=&quot;size16&quot;&gt;이후 src/app/admin/layout.tsx를 만들고, 관리자 공통 레이아웃인 &lt;b&gt;사이드바 + 헤더 + 본문 영역&lt;/b&gt; 구조를 잡았다.&lt;/p&gt;
&lt;p data-end=&quot;2077&quot; data-start=&quot;1996&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2149&quot; data-start=&quot;2079&quot; data-ke-size=&quot;size16&quot;&gt;이 단계에서 알게 된 점은, 관리자 페이지는 개별 화면보다 먼저 &lt;b&gt;공통 프레임을 잡는 것이 훨씬 중요하다&lt;/b&gt;는 점이었다.&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;2185&quot; data-start=&quot;2156&quot; data-section-id=&quot;1velxrf&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2185&quot; data-start=&quot;2156&quot; data-section-id=&quot;1velxrf&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2185&quot; data-start=&quot;2156&quot; data-section-id=&quot;1velxrf&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2185&quot; data-start=&quot;2156&quot; data-section-id=&quot;1velxrf&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;5. a href 대신 Link 사용하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2264&quot; data-start=&quot;2187&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 사이드바 링크를 일반 &amp;lt;a href=&quot;&quot;&amp;gt;로 넣었는데, Next.js에서는 Link를 사용하는 게 맞다는 걸 알게 됐다.&lt;/p&gt;
&lt;p data-end=&quot;2264&quot; data-start=&quot;2187&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2283&quot; data-start=&quot;2266&quot; data-ke-size=&quot;size16&quot;&gt;다만 여기서 작은 실수를 했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336638317&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Link from 'next/Link'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2358&quot; data-start=&quot;2326&quot; data-ke-size=&quot;size16&quot;&gt;처럼 대문자 L로 import를 해서 에러가 발생했다.&lt;/p&gt;
&lt;p data-end=&quot;2358&quot; data-start=&quot;2326&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2369&quot; data-start=&quot;2360&quot; data-ke-size=&quot;size16&quot;&gt;정답은 아래였다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336649582&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Link from 'next/link'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2446&quot; data-start=&quot;2412&quot; data-ke-size=&quot;size16&quot;&gt;소문자 경로를 써야 한다는 점을 제대로 기억하게 된 계기였다.&lt;/p&gt;
&lt;p data-end=&quot;2446&quot; data-start=&quot;2412&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2446&quot; data-start=&quot;2412&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2446&quot; data-start=&quot;2412&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;2472&quot; data-start=&quot;2453&quot; data-section-id=&quot;1iy67r5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2472&quot; data-start=&quot;2453&quot; data-section-id=&quot;1iy67r5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2472&quot; data-start=&quot;2453&quot; data-section-id=&quot;1iy67r5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2472&quot; data-start=&quot;2453&quot; data-section-id=&quot;1iy67r5&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;6. 회원 목록 페이지 만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2520&quot; data-start=&quot;2474&quot; data-ke-size=&quot;size16&quot;&gt;그다음에는 관리자 페이지에서 가장 기본이 되는 &lt;b&gt;회원 목록 페이지&lt;/b&gt;를 만들었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1777336681389&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const users = [
  { id: 1, name: '홍길동', email: 'hong@test.com', status: '활성' },
  { id: 2, name: '김민지', email: 'kim@test.com', status: '비활성' },
  { id: 3, name: '이준호', email: 'lee@test.com', status: '활성' },
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2781&quot; data-start=&quot;2743&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2781&quot; data-start=&quot;2743&quot; data-ke-size=&quot;size16&quot;&gt;이 배열을 기준으로 테이블을 렌더링하면서 아래 개념들을 같이 익혔다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2842&quot; data-start=&quot;2783&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2795&quot; data-start=&quot;2783&quot; data-section-id=&quot;xc7hhc&quot;&gt;배열 데이터 만들기&lt;/li&gt;
&lt;li data-end=&quot;2814&quot; data-start=&quot;2796&quot; data-section-id=&quot;1sx2ty9&quot;&gt;map()으로 반복 렌더링&lt;/li&gt;
&lt;li data-end=&quot;2825&quot; data-start=&quot;2815&quot; data-section-id=&quot;199qot6&quot;&gt;key 사용&lt;/li&gt;
&lt;li data-end=&quot;2842&quot; data-start=&quot;2826&quot; data-section-id=&quot;yx1n8&quot;&gt;기본적인 테이블 UI 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2886&quot; data-start=&quot;2844&quot; data-ke-size=&quot;size16&quot;&gt;이 시점부터 &amp;ldquo;관리자 페이지를 만들고 있다&amp;rdquo;는 느낌이 확실히 들기 시작했다.&lt;/p&gt;
&lt;p data-end=&quot;2886&quot; data-start=&quot;2844&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;2886&quot; data-start=&quot;2844&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2918&quot; data-start=&quot;2893&quot; data-section-id=&quot;jhkhu8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2918&quot; data-start=&quot;2893&quot; data-section-id=&quot;jhkhu8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2918&quot; data-start=&quot;2893&quot; data-section-id=&quot;jhkhu8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2918&quot; data-start=&quot;2893&quot; data-section-id=&quot;jhkhu8&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;7. 상세 페이지와 동적 라우팅 이해하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2956&quot; data-start=&quot;2920&quot; data-ke-size=&quot;size16&quot;&gt;회원 목록에서 이름을 클릭하면 상세 페이지로 이동하도록 만들었다.&lt;/p&gt;
&lt;p data-end=&quot;2956&quot; data-start=&quot;2920&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2975&quot; data-start=&quot;2958&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 아래 구조를 만들면,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336706210&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;src/app/admin/users/[id]/page.tsx&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3058&quot; data-start=&quot;3024&quot; data-ke-size=&quot;size16&quot;&gt;URL의 id 값을 받아 상세 페이지를 렌더링할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;3058&quot; data-start=&quot;3024&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3137&quot; data-start=&quot;3060&quot; data-ke-size=&quot;size16&quot;&gt;이 과정에서 처음엔 &amp;ldquo;페이지에 id 말고 다른 값도 넘길 수 있나?&amp;rdquo;라는 궁금증이 생겼고, 이를 통해 아래 개념 차이를 정리하게 됐다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3210&quot; data-start=&quot;3139&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3162&quot; data-start=&quot;3139&quot; data-section-id=&quot;pw5v2q&quot;&gt;props &amp;rarr; 컴포넌트끼리 값 전달&lt;/li&gt;
&lt;li data-end=&quot;3183&quot; data-start=&quot;3163&quot; data-section-id=&quot;12fiyvy&quot;&gt;params &amp;rarr; URL 경로값&lt;/li&gt;
&lt;li data-end=&quot;3210&quot; data-start=&quot;3184&quot; data-section-id=&quot;rfzpgh&quot;&gt;searchParams &amp;rarr; URL 쿼리값&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3263&quot; data-start=&quot;3212&quot; data-ke-size=&quot;size16&quot;&gt;즉, 상세 페이지에서 받는 id는 props가 아니라 &lt;b&gt;URL의 동적 경로값&lt;/b&gt;이었다.&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3309&quot; data-start=&quot;3270&quot; data-section-id=&quot;1pr3fhs&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;8. 수정 페이지 만들기: /admin/users/1/edit&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3391&quot; data-start=&quot;3311&quot; data-ke-size=&quot;size16&quot;&gt;상세 페이지 아래에 수정하기 버튼을 붙이고, /admin/users/[id]/edit/page.tsx 구조로 수정 페이지를 만들었다.&lt;/p&gt;
&lt;p data-end=&quot;3391&quot; data-start=&quot;3311&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3460&quot; data-start=&quot;3393&quot; data-ke-size=&quot;size16&quot;&gt;이 단계에서 처음엔 단순히 입력창만 띄워보는 수준이었지만, 곧 &lt;b&gt;&amp;ldquo;진짜 입력 가능한 수정 페이지&amp;rdquo;&lt;/b&gt;가 필요해졌다.&lt;/p&gt;
&lt;p data-end=&quot;3460&quot; data-start=&quot;3393&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3477&quot; data-start=&quot;3462&quot; data-ke-size=&quot;size16&quot;&gt;여기서 핵심은 두 가지였다.&lt;/p&gt;
&lt;p data-end=&quot;3477&quot; data-start=&quot;3462&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3497&quot; data-start=&quot;3479&quot; data-section-id=&quot;1pv4f0k&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;A. 뒤로가기 버튼 붙이기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3521&quot; data-start=&quot;3498&quot; data-ke-size=&quot;size16&quot;&gt;이건 페이지 이동 흐름을 만드는 단계였다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3545&quot; data-start=&quot;3523&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3533&quot; data-start=&quot;3523&quot; data-section-id=&quot;1f2iotx&quot;&gt;상세로 돌아가기&lt;/li&gt;
&lt;li data-end=&quot;3545&quot; data-start=&quot;3534&quot; data-section-id=&quot;fam490&quot;&gt;목록으로 돌아가기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3566&quot; data-start=&quot;3547&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;내비게이션&lt;/b&gt;의 문제였다.&lt;/p&gt;
&lt;p data-end=&quot;3566&quot; data-start=&quot;3547&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3601&quot; data-start=&quot;3568&quot; data-section-id=&quot;16odjpa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;B. useState로 진짜 수정 가능하게 만들기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3621&quot; data-start=&quot;3602&quot; data-ke-size=&quot;size16&quot;&gt;이건 입력 기능을 만드는 단계였다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3647&quot; data-start=&quot;3623&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3630&quot; data-start=&quot;3623&quot; data-section-id=&quot;1y89n91&quot;&gt;이름 수정&lt;/li&gt;
&lt;li data-end=&quot;3639&quot; data-start=&quot;3631&quot; data-section-id=&quot;1kcbys9&quot;&gt;이메일 수정&lt;/li&gt;
&lt;li data-end=&quot;3647&quot; data-start=&quot;3640&quot; data-section-id=&quot;m50b1k&quot;&gt;상태 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3670&quot; data-start=&quot;3649&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;폼 상태 관리&lt;/b&gt;의 문제였다.&lt;/p&gt;
&lt;p data-end=&quot;3670&quot; data-start=&quot;3649&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3736&quot; data-start=&quot;3672&quot; data-ke-size=&quot;size16&quot;&gt;이 둘의 차이를 정리하면서, 수정 페이지에는 &lt;b&gt;이동 기능과 입력 기능이 모두 필요하다&lt;/b&gt;는 걸 이해하게 됐다.&lt;/p&gt;
&lt;p data-end=&quot;3736&quot; data-start=&quot;3672&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3776&quot; data-start=&quot;3743&quot; data-section-id=&quot;66nldp&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;9. useParams와 useState의 차이&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3812&quot; data-start=&quot;3778&quot; data-ke-size=&quot;size16&quot;&gt;수정 페이지를 만들다가 처음 헷갈렸던 부분이 바로 이것이었다.&lt;/p&gt;
&lt;p data-end=&quot;3812&quot; data-start=&quot;3778&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3886&quot; data-start=&quot;3814&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 &amp;ldquo;진짜 입력 가능하게 만드는 것&amp;rdquo;이 useParams를 쓰는 건가 싶었는데, 정리해보면 둘은 역할이 완전히 달랐다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3960&quot; data-start=&quot;3888&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3925&quot; data-start=&quot;3888&quot; data-section-id=&quot;sm6gwq&quot;&gt;useParams &amp;rarr; URL에서 어떤 회원인지 확인하는 용도&lt;/li&gt;
&lt;li data-end=&quot;3960&quot; data-start=&quot;3926&quot; data-section-id=&quot;13i3jcl&quot;&gt;useState &amp;rarr; 입력값을 현재 상태로 저장하는 용도&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3964&quot; data-start=&quot;3962&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4021&quot; data-start=&quot;3966&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3992&quot; data-start=&quot;3966&quot; data-section-id=&quot;va1zqv&quot;&gt;useParams는 &amp;ldquo;누구를 수정하는지&amp;rdquo;&lt;/li&gt;
&lt;li data-end=&quot;4021&quot; data-start=&quot;3993&quot; data-section-id=&quot;8h3tr9&quot;&gt;useState는 &amp;ldquo;무엇을 어떻게 바꾸는지&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4030&quot; data-start=&quot;4023&quot; data-ke-size=&quot;size16&quot;&gt;를 담당한다.&lt;/p&gt;
&lt;p data-end=&quot;4030&quot; data-start=&quot;4023&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4066&quot; data-start=&quot;4032&quot; data-ke-size=&quot;size16&quot;&gt;이 차이를 이해하고 나니 수정 페이지 흐름이 훨씬 선명해졌다.&lt;/p&gt;
&lt;p data-end=&quot;4066&quot; data-start=&quot;4032&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4066&quot; data-start=&quot;4032&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4097&quot; data-start=&quot;4073&quot; data-section-id=&quot;t0oxbb&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4097&quot; data-start=&quot;4073&quot; data-section-id=&quot;t0oxbb&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;10. 저장 후 상세 페이지로 이동하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4167&quot; data-start=&quot;4099&quot; data-ke-size=&quot;size16&quot;&gt;수정 페이지에서 저장 버튼을 누르면 단순히 alert만 띄우는 게 아니라, 저장 후 상세 페이지로 이동하도록 만들었다.&lt;/p&gt;
&lt;p data-end=&quot;4167&quot; data-start=&quot;4099&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4194&quot; data-start=&quot;4169&quot; data-ke-size=&quot;size16&quot;&gt;여기서 사용한 것은 useRouter였다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336839670&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const router = useRouter()

router.push(`/admin/users/${id}`)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4284&quot; data-start=&quot;4270&quot; data-ke-size=&quot;size16&quot;&gt;이걸 통해 알게 된 것은,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4339&quot; data-start=&quot;4286&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4309&quot; data-start=&quot;4286&quot; data-section-id=&quot;1cqe50z&quot;&gt;Link &amp;rarr; 사용자가 클릭해서 이동&lt;/li&gt;
&lt;li data-end=&quot;4339&quot; data-start=&quot;4310&quot; data-section-id=&quot;19n4s28&quot;&gt;router.push() &amp;rarr; 코드로 자동 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4350&quot; data-start=&quot;4341&quot; data-ke-size=&quot;size16&quot;&gt;이라는 차이였다.&lt;/p&gt;
&lt;p data-end=&quot;4350&quot; data-start=&quot;4341&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4408&quot; data-start=&quot;4352&quot; data-ke-size=&quot;size16&quot;&gt;이때부터 단순히 화면을 만드는 것이 아니라 &lt;b&gt;관리자 페이지 흐름을 제어한다&lt;/b&gt;는 느낌을 받았다.&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4435&quot; data-start=&quot;4415&quot; data-section-id=&quot;8f6tf3&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;11. 회원 등록 페이지 만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4482&quot; data-start=&quot;4437&quot; data-ke-size=&quot;size16&quot;&gt;다음으로는 /admin/users/new 경로의 회원 등록 페이지를 만들었다.&lt;/p&gt;
&lt;p data-end=&quot;4519&quot; data-start=&quot;4484&quot; data-ke-size=&quot;size16&quot;&gt;수정 페이지와 등록 페이지는 구조가 비슷하지만 차이도 분명했다.&lt;/p&gt;
&lt;p data-end=&quot;4519&quot; data-start=&quot;4484&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4531&quot; data-start=&quot;4521&quot; data-section-id=&quot;lix16v&quot; data-ke-size=&quot;size16&quot;&gt;수정 페이지&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4570&quot; data-start=&quot;4532&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4546&quot; data-start=&quot;4532&quot; data-section-id=&quot;1hso7kc&quot;&gt;기존 데이터가 들어있음&lt;/li&gt;
&lt;li data-end=&quot;4560&quot; data-start=&quot;4547&quot; data-section-id=&quot;18m4cj1&quot;&gt;특정 id가 있음&lt;/li&gt;
&lt;li data-end=&quot;4570&quot; data-start=&quot;4561&quot; data-section-id=&quot;wwiyr0&quot;&gt;저장하면 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4582&quot; data-start=&quot;4572&quot; data-section-id=&quot;1cqsgsm&quot; data-ke-size=&quot;size16&quot;&gt;등록 페이지&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4624&quot; data-start=&quot;4583&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4594&quot; data-start=&quot;4583&quot; data-section-id=&quot;15ye5ui&quot;&gt;입력값이 비어있음&lt;/li&gt;
&lt;li data-end=&quot;4608&quot; data-start=&quot;4595&quot; data-section-id=&quot;1fhu2y&quot;&gt;아직 id가 없음&lt;/li&gt;
&lt;li data-end=&quot;4624&quot; data-start=&quot;4609&quot; data-section-id=&quot;4nhcr5&quot;&gt;저장하면 새 데이터 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4661&quot; data-start=&quot;4626&quot; data-ke-size=&quot;size16&quot;&gt;즉, 화면 구조는 비슷하지만 목적이 다르다는 걸 이해하게 됐다.&lt;/p&gt;
&lt;p data-end=&quot;4661&quot; data-start=&quot;4626&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4661&quot; data-start=&quot;4626&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4661&quot; data-start=&quot;4626&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4690&quot; data-start=&quot;4668&quot; data-section-id=&quot;4bgo3k&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;12. 더미데이터를 파일로 분리하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4786&quot; data-start=&quot;4692&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 users 배열을 목록 페이지 안에 직접 두고 썼다.&lt;br /&gt;하지만 상세 페이지와 수정 페이지에서도 같은 데이터를 써야 하다 보니, 중복이 생기기 시작했다.&lt;/p&gt;
&lt;p data-end=&quot;4786&quot; data-start=&quot;4692&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4804&quot; data-start=&quot;4788&quot; data-ke-size=&quot;size16&quot;&gt;그래서 아래 파일을 만들었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336894870&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;src/lib/dummy-data.ts&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4855&quot; data-start=&quot;4841&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4855&quot; data-start=&quot;4841&quot; data-ke-size=&quot;size16&quot;&gt;그리고 데이터를 분리했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336910798&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const users = [
    { id: 1, name: '홍길동', email: 'hong@test.com', status: '활성' },
    { id: 2, name: '김민지', email: 'kim@test.com', status: '비활성' },
    { id: 3, name: '이준호', email: 'lee@test.com', status: '활성' },
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5148&quot; data-start=&quot;5085&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하니 목록, 상세, 수정 페이지가 같은 데이터를 참조할 수 있게 됐고,&lt;br /&gt;페이지 코드도 훨씬 가벼워졌다.&lt;/p&gt;
&lt;p data-end=&quot;5148&quot; data-start=&quot;5085&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5148&quot; data-start=&quot;5085&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5185&quot; data-start=&quot;5155&quot; data-section-id=&quot;14dbhag&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;13. src 구조와 path alias 문제&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;5223&quot; data-start=&quot;5187&quot; data-ke-size=&quot;size16&quot;&gt;중간에 src 폴더를 구성하면서 또 하나 막힌 부분이 있었다.&lt;/p&gt;
&lt;p data-end=&quot;5223&quot; data-start=&quot;5187&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5241&quot; data-start=&quot;5225&quot; data-ke-size=&quot;size16&quot;&gt;다음과 같은 에러가 발생했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336933742&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Module not found: Can't resolve '@/lib/dummy-data'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5357&quot; data-start=&quot;5307&quot; data-ke-size=&quot;size16&quot;&gt;원인을 확인해보니 tsconfig.json의 path 설정에 src가 빠져 있었다.&lt;/p&gt;
&lt;p data-end=&quot;5357&quot; data-start=&quot;5307&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5371&quot; data-start=&quot;5359&quot; data-ke-size=&quot;size16&quot;&gt;해결은 아래처럼 했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777336964253&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;compilerOptions&quot;: {
        &quot;baseUrl&quot;: &quot;.&quot;,
        &quot;paths&quot;: {
        	&quot;@/*&quot;: [&quot;./src/*&quot;]
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5515&quot; data-start=&quot;5483&quot; data-ke-size=&quot;size16&quot;&gt;즉, @ 별칭이 src를 바라보도록 설정해야 했다.&lt;/p&gt;
&lt;p data-end=&quot;5515&quot; data-start=&quot;5483&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5584&quot; data-start=&quot;5517&quot; data-ke-size=&quot;size16&quot;&gt;이 과정에서 알게 된 것은, 폴더 구조를 바꾸면 &lt;b&gt;import alias 설정도 함께 맞춰줘야 한다&lt;/b&gt;는 점이었다.&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;515&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5620&quot; data-start=&quot;5591&quot; data-section-id=&quot;apxjgo&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;14. 등록/수정 폼을 공통 컴포넌트로 분리하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;5706&quot; data-start=&quot;5622&quot; data-ke-size=&quot;size16&quot;&gt;등록 페이지와 수정 페이지를 만들고 나니, 이름 input / 이메일 input / 상태 select / 버튼 구조가 거의 똑같다는 걸 알게 됐다.&lt;/p&gt;
&lt;p data-end=&quot;5706&quot; data-start=&quot;5622&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5729&quot; data-start=&quot;5708&quot; data-ke-size=&quot;size16&quot;&gt;그래서 아래 공통 컴포넌트를 만들었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1777337003966&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;src/components/admin/users/user-form.tsx&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5787&quot; data-start=&quot;5785&quot; data-ke-size=&quot;size16&quot;&gt;이후&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5828&quot; data-start=&quot;5789&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5804&quot; data-start=&quot;5789&quot; data-section-id=&quot;12fgaxq&quot;&gt;등록 페이지는 빈 초기값&lt;/li&gt;
&lt;li data-end=&quot;5828&quot; data-start=&quot;5805&quot; data-section-id=&quot;s290b&quot;&gt;수정 페이지는 기존 회원 데이터 초기값&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;5858&quot; data-start=&quot;5830&quot; data-ke-size=&quot;size16&quot;&gt;을 넘겨서 같은 폼을 재사용하도록 구조를 정리했다.&lt;/p&gt;
&lt;p data-end=&quot;5858&quot; data-start=&quot;5830&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5916&quot; data-start=&quot;5860&quot; data-ke-size=&quot;size16&quot;&gt;이 단계에서 특히 크게 느낀 건, &lt;b&gt;&amp;ldquo;작동하는 코드&amp;rdquo;와 &amp;ldquo;정리된 코드&amp;rdquo;는 다르다&lt;/b&gt;는 점이었다.&lt;/p&gt;
&lt;p data-end=&quot;5916&quot; data-start=&quot;5860&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5976&quot; data-start=&quot;5918&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 페이지 안에 전부 적는 게 쉬웠지만, 조금만 흐름이 늘어나도 공통 컴포넌트 분리가 필요해졌다.&lt;/p&gt;
&lt;p data-end=&quot;5976&quot; data-start=&quot;5918&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;5976&quot; data-start=&quot;5918&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;6004&quot; data-start=&quot;5983&quot; data-section-id=&quot;1nvnvlr&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;15. 이번 과정을 통해 느낀 점&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;6093&quot; data-start=&quot;6006&quot; data-ke-size=&quot;size16&quot;&gt;이번 작업을 하면서 느낀 가장 큰 점은,&lt;/p&gt;
&lt;p data-end=&quot;6093&quot; data-start=&quot;6006&quot; data-ke-size=&quot;size16&quot;&gt;Next.js를 처음 배울 때 중요한 건 복잡한 개념보다 &lt;b&gt;구조와 흐름을 직접 만들어보는 것&lt;/b&gt;이라는 점이다.&lt;/p&gt;
&lt;p data-end=&quot;6093&quot; data-start=&quot;6006&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;6123&quot; data-start=&quot;6095&quot; data-ke-size=&quot;size16&quot;&gt;특히 아래 흐름을 손으로 만들어보면서 많이 익혔다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;6231&quot; data-start=&quot;6125&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;6146&quot; data-start=&quot;6125&quot; data-section-id=&quot;1vit2oz&quot;&gt;/admin/users &amp;rarr; 목록&lt;/li&gt;
&lt;li data-end=&quot;6173&quot; data-start=&quot;6147&quot; data-section-id=&quot;16psu6i&quot;&gt;/admin/users/[id] &amp;rarr; 상세&lt;/li&gt;
&lt;li data-end=&quot;6205&quot; data-start=&quot;6174&quot; data-section-id=&quot;6eiozx&quot;&gt;/admin/users/[id]/edit &amp;rarr; 수정&lt;/li&gt;
&lt;li data-end=&quot;6231&quot; data-start=&quot;6206&quot; data-section-id=&quot;19yxtpk&quot;&gt;/admin/users/new &amp;rarr; 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;6264&quot; data-start=&quot;6233&quot; data-ke-size=&quot;size16&quot;&gt;그리고 이 과정에서 자연스럽게 익힌 것들은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;6411&quot; data-start=&quot;6266&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;6281&quot; data-start=&quot;6266&quot; data-section-id=&quot;ztvpxa&quot;&gt;App Router 구조&lt;/li&gt;
&lt;li data-end=&quot;6308&quot; data-start=&quot;6282&quot; data-section-id=&quot;1ihf5xd&quot;&gt;layout.tsx와 page.tsx&lt;/li&gt;
&lt;li data-end=&quot;6317&quot; data-start=&quot;6309&quot; data-section-id=&quot;17q4tl4&quot;&gt;Link&lt;/li&gt;
&lt;li data-end=&quot;6331&quot; data-start=&quot;6318&quot; data-section-id=&quot;1g6kjtj&quot;&gt;useParams&lt;/li&gt;
&lt;li data-end=&quot;6344&quot; data-start=&quot;6332&quot; data-section-id=&quot;q4gnks&quot;&gt;useState&lt;/li&gt;
&lt;li data-end=&quot;6358&quot; data-start=&quot;6345&quot; data-section-id=&quot;1stv8ao&quot;&gt;useRouter&lt;/li&gt;
&lt;li data-end=&quot;6369&quot; data-start=&quot;6359&quot; data-section-id=&quot;1047z20&quot;&gt;더미데이터 분리&lt;/li&gt;
&lt;li data-end=&quot;6384&quot; data-start=&quot;6370&quot; data-section-id=&quot;1ovhgr4&quot;&gt;공통 폼 컴포넌트 분리&lt;/li&gt;
&lt;li data-end=&quot;6411&quot; data-start=&quot;6385&quot; data-section-id=&quot;1ofvm7j&quot;&gt;tsconfig path alias 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/react</category>
      <author>아랄라랄라</author>
      <guid isPermaLink="true">https://studyhardgogo.tistory.com/374</guid>
      <comments>https://studyhardgogo.tistory.com/374#entry374comment</comments>
      <pubDate>Tue, 28 Apr 2026 09:31:54 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] 프로젝트 시작하기</title>
      <link>https://studyhardgogo.tistory.com/373</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 확인할 건 &lt;b&gt;Node.js 버전&lt;/b&gt;이다.&lt;br /&gt;현재 Next.js 공식 설치 문서는 &lt;b&gt;최소 Node.js 20.9&lt;/b&gt;를 요구한다. create-next-app으로 시작하면 기본적으로 TypeScript, Tailwind CSS, ESLint, App Router, Turbopack 등을 선택해서 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 원하는 위치로 이동한 다음:&lt;/p&gt;
&lt;pre id=&quot;code_1777008154294&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx create-next-app@latest admin-next&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;177&quot; data-start=&quot;158&quot; data-ke-size=&quot;size16&quot;&gt;질문이 나오면 이렇게 고르면 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;342&quot; data-start=&quot;179&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;201&quot; data-start=&quot;179&quot; data-section-id=&quot;fzfin6&quot;&gt;&lt;b&gt;TypeScript&lt;/b&gt; &amp;rarr; Yes&lt;/li&gt;
&lt;li data-end=&quot;220&quot; data-start=&quot;202&quot; data-section-id=&quot;t6r2vw&quot;&gt;&lt;b&gt;ESLint&lt;/b&gt; &amp;rarr; Yes&lt;/li&gt;
&lt;li data-end=&quot;244&quot; data-start=&quot;221&quot; data-section-id=&quot;ckcye4&quot;&gt;&lt;b&gt;Tailwind CSS&lt;/b&gt; &amp;rarr; No&lt;/li&gt;
&lt;li data-end=&quot;273&quot; data-start=&quot;245&quot; data-section-id=&quot;1i24435&quot;&gt;&lt;b&gt;src/ directory&lt;/b&gt; &amp;rarr; Yes&lt;/li&gt;
&lt;li data-end=&quot;296&quot; data-start=&quot;274&quot; data-section-id=&quot;chvzzz&quot;&gt;&lt;b&gt;App Router&lt;/b&gt; &amp;rarr; Yes&lt;/li&gt;
&lt;li data-end=&quot;318&quot; data-start=&quot;297&quot; data-section-id=&quot;15jklqq&quot;&gt;&lt;b&gt;Turbopack&lt;/b&gt; &amp;rarr; Yes&lt;/li&gt;
&lt;li data-end=&quot;342&quot; data-start=&quot;319&quot; data-section-id=&quot;g38isw&quot;&gt;&lt;b&gt;import alias&lt;/b&gt; &amp;rarr; No&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;설치 끝나면:&lt;/p&gt;
&lt;pre id=&quot;code_1777008177321&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd admin-next
npm run dev&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;브라우저에서&lt;br /&gt;http://localhost:3000 열면 된다.&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;현재 나의 상황!&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;사용자 프로젝트를 시작하기 전, 내부 관리자 페이지를 연습 삼아 만들어보게 되었다.&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;001&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/001.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/friends1/large/001.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;나에게 &lt;b&gt;제일 좋은 방식! &lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;템플릿 100% 의존 X, &lt;/b&gt;&lt;b&gt;맨땅 100% 제작 X &lt;/b&gt;딱 중간이 좋다.&lt;/p&gt;
&lt;p data-end=&quot;268&quot; data-start=&quot;219&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;276&quot; data-start=&quot;270&quot; data-ke-size=&quot;size16&quot;&gt;예를 들면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;384&quot; data-start=&quot;277&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;303&quot; data-start=&quot;277&quot; data-section-id=&quot;2bv1q0&quot;&gt;Next.js 프로젝트 기본 세팅은 가져가기&lt;/li&gt;
&lt;li data-end=&quot;323&quot; data-start=&quot;304&quot; data-section-id=&quot;15com73&quot;&gt;관리자 공통 레이아웃은 참고하기&lt;/li&gt;
&lt;li data-end=&quot;342&quot; data-start=&quot;324&quot; data-section-id=&quot;t036f3&quot;&gt;사이드바/헤더 구조는 참고하기&lt;/li&gt;
&lt;li data-end=&quot;362&quot; data-start=&quot;343&quot; data-section-id=&quot;17zmmk4&quot;&gt;대신 실제 페이지는 네가 만들기&lt;/li&gt;
&lt;li data-end=&quot;384&quot; data-start=&quot;363&quot; data-section-id=&quot;1jqhv0x&quot;&gt;테이블/폼/상세화면은 직접 구현하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;436&quot; data-start=&quot;386&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 해야 &lt;b&gt;넥스트 구조는 덜 헤매고&lt;/b&gt;, &lt;b&gt;실제 구현 감각은 제대로 남는다!&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;460&quot; data-start=&quot;438&quot; data-section-id=&quot;wmn7k3&quot; data-ke-size=&quot;size16&quot;&gt;왜 새로 다 만드는게 비효율적이냐면 초보일 때는 &amp;ldquo;공부&amp;rdquo;보다 &amp;ldquo;삽질&amp;rdquo; 비중이 너무 커지기 때문이다.&lt;/p&gt;
&lt;p data-end=&quot;491&quot; data-start=&quot;461&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;498&quot; data-start=&quot;493&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;623&quot; data-start=&quot;499&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;519&quot; data-start=&quot;499&quot; data-section-id=&quot;1an7du9&quot;&gt;layout을 어디에 둬야 하지?&lt;/li&gt;
&lt;li data-end=&quot;547&quot; data-start=&quot;520&quot; data-section-id=&quot;1jocrpc&quot;&gt;app router에서 이 경로가 왜 이러지?&lt;/li&gt;
&lt;li data-end=&quot;575&quot; data-start=&quot;548&quot; data-section-id=&quot;1fxtfxd&quot;&gt;client component는 왜 필요하지?&lt;/li&gt;
&lt;li data-end=&quot;601&quot; data-start=&quot;576&quot; data-section-id=&quot;ie1bis&quot;&gt;bootstrap js는 어디서 불러오지?&lt;/li&gt;
&lt;li data-end=&quot;623&quot; data-start=&quot;602&quot; data-section-id=&quot;1esen2j&quot;&gt;공통 레이아웃 분리는 어떻게 하지?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;681&quot; data-start=&quot;625&quot; data-ke-size=&quot;size16&quot;&gt;이런 걸 한 번에 다 맞닥뜨리면 정작 중요한 &lt;b&gt;관리자 화면 구현&lt;/b&gt;까지 못 가는 경우가 많다.&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;032&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/niniz/large/032.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/niniz/large/032.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-end=&quot;701&quot; data-start=&quot;683&quot; data-section-id=&quot;18leb14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;701&quot; data-start=&quot;683&quot; data-section-id=&quot;18leb14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;701&quot; data-start=&quot;683&quot; data-section-id=&quot;18leb14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;701&quot; data-start=&quot;683&quot; data-section-id=&quot;18leb14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그렇기 때문에 나에게 맞는 방식은 이거다!&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;701&quot; data-start=&quot;683&quot; data-section-id=&quot;18leb14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;725&quot; data-start=&quot;702&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Next.js 기본 틀은 사용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;766&quot; data-start=&quot;726&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;741&quot; data-start=&quot;726&quot; data-section-id=&quot;1w42r9a&quot;&gt;app router 구조&lt;/li&gt;
&lt;li data-end=&quot;754&quot; data-start=&quot;742&quot; data-section-id=&quot;182fk3n&quot;&gt;layout.tsx&lt;/li&gt;
&lt;li data-end=&quot;766&quot; data-start=&quot;755&quot; data-section-id=&quot;ohho0g&quot;&gt;기본 페이지 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;793&quot; data-start=&quot;768&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 관리자 공통 프레임만 먼저 만들기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;827&quot; data-start=&quot;794&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;803&quot; data-start=&quot;794&quot; data-section-id=&quot;1oqbko2&quot;&gt;sidebar&lt;/li&gt;
&lt;li data-end=&quot;812&quot; data-start=&quot;804&quot; data-section-id=&quot;139ov93&quot;&gt;header&lt;/li&gt;
&lt;li data-end=&quot;827&quot; data-start=&quot;813&quot; data-section-id=&quot;vkbzxy&quot;&gt;content area&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;852&quot; data-start=&quot;829&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 실제 업무 화면은 직접 만들기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;878&quot; data-start=&quot;853&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;857&quot; data-start=&quot;853&quot; data-section-id=&quot;yhylbw&quot;&gt;목록&lt;/li&gt;
&lt;li data-end=&quot;862&quot; data-start=&quot;858&quot; data-section-id=&quot;yiluwh&quot;&gt;상세&lt;/li&gt;
&lt;li data-end=&quot;870&quot; data-start=&quot;863&quot; data-section-id=&quot;1aj3s5i&quot;&gt;등록/수정&lt;/li&gt;
&lt;li data-end=&quot;878&quot; data-start=&quot;871&quot; data-section-id=&quot;doom3e&quot;&gt;검색/필터&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;900&quot; data-start=&quot;880&quot; data-ke-size=&quot;size16&quot;&gt;이러면 공부도 되고 결과물도 나온다.&lt;/p&gt;
&lt;p data-end=&quot;900&quot; data-start=&quot;880&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;914&quot; data-start=&quot;902&quot; data-section-id=&quot;1ejkcam&quot; data-ke-size=&quot;size16&quot;&gt;한 줄로 말하면&lt;/p&gt;
&lt;p data-end=&quot;978&quot; data-start=&quot;915&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;ldquo;새로 다 만들기&amp;rdquo;보다 &amp;ldquo;기본 틀은 참고하고, 실제 페이지는 직접 만들기&amp;rdquo;가 지금 나한테 제일 좋다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;978&quot; data-start=&quot;915&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1041&quot; data-start=&quot;980&quot; data-ke-size=&quot;size16&quot;&gt;진짜 추천은 &lt;b&gt;공통 레이아웃까지만 참고하고, 그 안의 관리자 페이지는 내가 직접 만드는 방식&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;직접 만들 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;129&quot; data-start=&quot;117&quot; data-section-id=&quot;1qgv77p&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 폴더 구조&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;142&quot; data-start=&quot;130&quot; data-ke-size=&quot;size16&quot;&gt;직접 만들어봐야 한다.&lt;/p&gt;
&lt;p data-end=&quot;368&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;이걸 직접 짜봐야&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;427&quot; data-start=&quot;369&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;385&quot; data-start=&quot;369&quot; data-section-id=&quot;k2eypi&quot;&gt;app router가 뭔지&lt;/li&gt;
&lt;li data-end=&quot;405&quot; data-start=&quot;386&quot; data-section-id=&quot;ovc41d&quot;&gt;layout이 어떻게 중첩되는지&lt;/li&gt;
&lt;li data-end=&quot;427&quot; data-start=&quot;406&quot; data-section-id=&quot;1jo8gtp&quot;&gt;동적 라우팅이 뭔지 감이 온다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;448&quot; data-start=&quot;434&quot; data-section-id=&quot;12apon5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;448&quot; data-start=&quot;434&quot; data-section-id=&quot;12apon5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 공통 레이아웃&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;467&quot; data-start=&quot;449&quot; data-ke-size=&quot;size16&quot;&gt;이건 꼭 직접 해보는 게 좋다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;501&quot; data-start=&quot;469&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;475&quot; data-start=&quot;469&quot; data-section-id=&quot;dgyh88&quot;&gt;사이드바&lt;/li&gt;
&lt;li data-end=&quot;480&quot; data-start=&quot;476&quot; data-section-id=&quot;yii55k&quot;&gt;헤더&lt;/li&gt;
&lt;li data-end=&quot;488&quot; data-start=&quot;481&quot; data-section-id=&quot;8w5ock&quot;&gt;본문 영역&lt;/li&gt;
&lt;li data-end=&quot;501&quot; data-start=&quot;489&quot; data-section-id=&quot;81rs3g&quot;&gt;페이지 타이틀 영역&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;536&quot; data-start=&quot;503&quot; data-ke-size=&quot;size16&quot;&gt;이걸 직접 만들면 관리자 페이지의 뼈대를 이해하게 된다.&lt;/p&gt;
&lt;p data-end=&quot;536&quot; data-start=&quot;503&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;536&quot; data-start=&quot;503&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;560&quot; data-start=&quot;543&quot; data-section-id=&quot;4y9jni&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 페이지 라우팅 연결&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;570&quot; data-start=&quot;561&quot; data-ke-size=&quot;size16&quot;&gt;직접 해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;610&quot; data-start=&quot;572&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;584&quot; data-start=&quot;572&quot; data-section-id=&quot;1k7kexm&quot;&gt;목록 &amp;rarr; 상세 이동&lt;/li&gt;
&lt;li data-end=&quot;597&quot; data-start=&quot;585&quot; data-section-id=&quot;grbp0v&quot;&gt;목록 &amp;rarr; 등록 이동&lt;/li&gt;
&lt;li data-end=&quot;610&quot; data-start=&quot;598&quot; data-section-id=&quot;1e6uywz&quot;&gt;상세 &amp;rarr; 수정 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;655&quot; data-start=&quot;612&quot; data-ke-size=&quot;size16&quot;&gt;Link 쓰고, 경로 연결하면서 넥스트 페이지 구조에 익숙해져야 한다.&lt;/p&gt;
&lt;p data-end=&quot;678&quot; data-start=&quot;662&quot; data-section-id=&quot;1lvjfw9&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;678&quot; data-start=&quot;662&quot; data-section-id=&quot;1lvjfw9&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;678&quot; data-start=&quot;662&quot; data-section-id=&quot;1lvjfw9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 실제 업무 페이지&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;698&quot; data-start=&quot;679&quot; data-ke-size=&quot;size16&quot;&gt;이건 무조건 직접 만드는 걸 추천.&lt;/p&gt;
&lt;p data-end=&quot;698&quot; data-start=&quot;679&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;702&quot; data-start=&quot;700&quot; data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;750&quot; data-start=&quot;703&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;710&quot; data-start=&quot;703&quot; data-section-id=&quot;jdlts&quot;&gt;회원 목록&lt;/li&gt;
&lt;li data-end=&quot;720&quot; data-start=&quot;711&quot; data-section-id=&quot;1dca6vc&quot;&gt;공지사항 목록&lt;/li&gt;
&lt;li data-end=&quot;731&quot; data-start=&quot;721&quot; data-section-id=&quot;1xc4p5x&quot;&gt;예약 관리 목록&lt;/li&gt;
&lt;li data-end=&quot;741&quot; data-start=&quot;732&quot; data-section-id=&quot;qw3ymy&quot;&gt;등록/수정 폼&lt;/li&gt;
&lt;li data-end=&quot;750&quot; data-start=&quot;742&quot; data-section-id=&quot;g9vpod&quot;&gt;상세 페이지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;799&quot; data-start=&quot;752&quot; data-ke-size=&quot;size16&quot;&gt;이 부분이 진짜 공부다!&lt;br /&gt;템플릿은 여기까지 대신 해주면 오히려 남는 게 적다.&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;821&quot; data-start=&quot;806&quot; data-section-id=&quot;1l3qibp&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 더미데이터 연결&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;832&quot; data-start=&quot;822&quot; data-ke-size=&quot;size16&quot;&gt;직접 해봐야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1777008590121&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const users = [
  { id: 1, name: '홍길동', status: 'active' },
  { id: 2, name: '김민지', status: 'inactive' },
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1007&quot; data-start=&quot;953&quot; data-ke-size=&quot;size16&quot;&gt;이걸 map 돌려서 테이블 만들고 상태값 뱃지 붙이고 빈 데이터 처리하는 게 중요하다.&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1025&quot; data-start=&quot;1014&quot; data-section-id=&quot;1nll312&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 폼 처리&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1038&quot; data-start=&quot;1026&quot; data-ke-size=&quot;size16&quot;&gt;직접 해보는 걸 강추.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1102&quot; data-start=&quot;1040&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1047&quot; data-start=&quot;1040&quot; data-section-id=&quot;162m18e&quot;&gt;input&lt;/li&gt;
&lt;li data-end=&quot;1056&quot; data-start=&quot;1048&quot; data-section-id=&quot;1m12z34&quot;&gt;select&lt;/li&gt;
&lt;li data-end=&quot;1067&quot; data-start=&quot;1057&quot; data-section-id=&quot;irqyle&quot;&gt;textarea&lt;/li&gt;
&lt;li data-end=&quot;1078&quot; data-start=&quot;1068&quot; data-section-id=&quot;12j6z7z&quot;&gt;onChange&lt;/li&gt;
&lt;li data-end=&quot;1086&quot; data-start=&quot;1079&quot; data-section-id=&quot;1grqgl1&quot;&gt;저장 버튼&lt;/li&gt;
&lt;li data-end=&quot;1102&quot; data-start=&quot;1087&quot; data-section-id=&quot;14jcrgb&quot;&gt;validation 기초&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1152&quot; data-start=&quot;1104&quot; data-ke-size=&quot;size16&quot;&gt;관리자는 결국 &lt;b&gt;조회 + 입력&lt;/b&gt;이라 폼을 직접 안 만들면 실력이 잘 안 는다.&lt;/p&gt;
&lt;p data-end=&quot;1152&quot; data-start=&quot;1104&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1152&quot; data-start=&quot;1104&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1152&quot; data-start=&quot;1104&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1152&quot; data-start=&quot;1104&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1173&quot; data-start=&quot;1159&quot; data-section-id=&quot;1dtwh7e&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1173&quot; data-start=&quot;1159&quot; data-section-id=&quot;1dtwh7e&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1173&quot; data-start=&quot;1159&quot; data-section-id=&quot;1dtwh7e&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1173&quot; data-start=&quot;1159&quot; data-section-id=&quot;1dtwh7e&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1173&quot; data-start=&quot;1159&quot; data-section-id=&quot;1dtwh7e&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1173&quot; data-start=&quot;1159&quot; data-section-id=&quot;1dtwh7e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가져다 써도 되는 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1197&quot; data-start=&quot;1175&quot; data-ke-size=&quot;size16&quot;&gt;이건 굳이 처음부터 다 안 만들어도 된다.&lt;/p&gt;
&lt;p data-end=&quot;1197&quot; data-start=&quot;1175&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1197&quot; data-start=&quot;1175&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1215&quot; data-start=&quot;1199&quot; data-section-id=&quot;1plspmc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 스타일 기본 세팅&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1226&quot; data-start=&quot;1216&quot; data-ke-size=&quot;size16&quot;&gt;가져다 써도 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1294&quot; data-start=&quot;1228&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1239&quot; data-start=&quot;1228&quot; data-section-id=&quot;1i7xl8a&quot;&gt;Bootstrap&lt;/li&gt;
&lt;li data-end=&quot;1247&quot; data-start=&quot;1240&quot; data-section-id=&quot;16o789p&quot;&gt;reset&lt;/li&gt;
&lt;li data-end=&quot;1257&quot; data-start=&quot;1248&quot; data-section-id=&quot;1ivy889&quot;&gt;spacing&lt;/li&gt;
&lt;li data-end=&quot;1264&quot; data-start=&quot;1258&quot; data-section-id=&quot;1j3hhww&quot;&gt;grid&lt;/li&gt;
&lt;li data-end=&quot;1280&quot; data-start=&quot;1265&quot; data-section-id=&quot;16x6w5q&quot;&gt;button 기본 스타일&lt;/li&gt;
&lt;li data-end=&quot;1294&quot; data-start=&quot;1281&quot; data-section-id=&quot;1r4vlbi&quot;&gt;form 기본 스타일&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1323&quot; data-start=&quot;1296&quot; data-ke-size=&quot;size16&quot;&gt;이건 처음부터 손으로 다 짜면 너무 오래 걸린다.&lt;/p&gt;
&lt;p data-end=&quot;1323&quot; data-start=&quot;1296&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1340&quot; data-start=&quot;1330&quot; data-section-id=&quot;466vde&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1340&quot; data-start=&quot;1330&quot; data-section-id=&quot;466vde&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1340&quot; data-start=&quot;1330&quot; data-section-id=&quot;466vde&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 아이콘&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1354&quot; data-start=&quot;1341&quot; data-ke-size=&quot;size16&quot;&gt;직접 만들 필요 없다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1394&quot; data-start=&quot;1356&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1373&quot; data-start=&quot;1356&quot; data-section-id=&quot;pnq4wy&quot;&gt;Bootstrap Icons&lt;/li&gt;
&lt;li data-end=&quot;1382&quot; data-start=&quot;1374&quot; data-section-id=&quot;1pif4vu&quot;&gt;Lucide&lt;/li&gt;
&lt;li data-end=&quot;1394&quot; data-start=&quot;1383&quot; data-section-id=&quot;a0cn5s&quot;&gt;Heroicons&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1414&quot; data-start=&quot;1396&quot; data-ke-size=&quot;size16&quot;&gt;아이콘은 가져다 쓰는 게 맞다.&lt;/p&gt;
&lt;p data-end=&quot;1414&quot; data-start=&quot;1396&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1414&quot; data-start=&quot;1396&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1436&quot; data-start=&quot;1421&quot; data-section-id=&quot;xzfwqm&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 기본 UI 조각&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1455&quot; data-start=&quot;1437&quot; data-ke-size=&quot;size16&quot;&gt;어느 정도 가져다 써도 괜찮다.&lt;/p&gt;
&lt;p data-end=&quot;1455&quot; data-start=&quot;1437&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1459&quot; data-start=&quot;1457&quot; data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1493&quot; data-start=&quot;1460&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1464&quot; data-start=&quot;1460&quot; data-section-id=&quot;yhyk8c&quot;&gt;모달&lt;/li&gt;
&lt;li data-end=&quot;1470&quot; data-start=&quot;1465&quot; data-section-id=&quot;2i0a6s&quot;&gt;토스트&lt;/li&gt;
&lt;li data-end=&quot;1474&quot; data-start=&quot;1471&quot; data-section-id=&quot;3751s5&quot;&gt;탭&lt;/li&gt;
&lt;li data-end=&quot;1481&quot; data-start=&quot;1475&quot; data-section-id=&quot;1w5xvm1&quot;&gt;드롭다운&lt;/li&gt;
&lt;li data-end=&quot;1493&quot; data-start=&quot;1482&quot; data-section-id=&quot;10wezf4&quot;&gt;페이지네이션 UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1547&quot; data-start=&quot;1495&quot; data-ke-size=&quot;size16&quot;&gt;이건 &amp;ldquo;왜 이렇게 동작하는지&amp;rdquo;만 이해하면 되고, 초반엔 직접 구현보다 활용이 더 중요하다.&lt;/p&gt;
&lt;p data-end=&quot;1547&quot; data-start=&quot;1495&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1575&quot; data-start=&quot;1554&quot; data-section-id=&quot;1ako3av&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1575&quot; data-start=&quot;1554&quot; data-section-id=&quot;1ako3av&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 관리자 샘플 레이아웃 참고&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1593&quot; data-start=&quot;1576&quot; data-ke-size=&quot;size16&quot;&gt;이건 적극적으로 참고해도 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1646&quot; data-start=&quot;1595&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1604&quot; data-start=&quot;1595&quot; data-section-id=&quot;xeolio&quot;&gt;사이드바 배치&lt;/li&gt;
&lt;li data-end=&quot;1612&quot; data-start=&quot;1605&quot; data-section-id=&quot;1mx69np&quot;&gt;헤더 구성&lt;/li&gt;
&lt;li data-end=&quot;1620&quot; data-start=&quot;1613&quot; data-section-id=&quot;r0b83s&quot;&gt;카드 배치&lt;/li&gt;
&lt;li data-end=&quot;1638&quot; data-start=&quot;1621&quot; data-section-id=&quot;1w9rrwf&quot;&gt;테이블 상단 검색/버튼 영역&lt;/li&gt;
&lt;li data-end=&quot;1646&quot; data-start=&quot;1639&quot; data-section-id=&quot;1qpdbls&quot;&gt;필터 UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1691&quot; data-start=&quot;1648&quot; data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;복붙해서 끝내는 건 비추천&lt;/b&gt;이고 &amp;ldquo;구조 참고&amp;rdquo; 정도가 좋다.&lt;/p&gt;
&lt;p data-end=&quot;1691&quot; data-start=&quot;1648&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1691&quot; data-start=&quot;1648&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1719&quot; data-start=&quot;1698&quot; data-section-id=&quot;695chd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 공통 컴포넌트 디자인 패턴&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1731&quot; data-start=&quot;1720&quot; data-ke-size=&quot;size16&quot;&gt;이건 가져와도 된다.&lt;/p&gt;
&lt;p data-end=&quot;1731&quot; data-start=&quot;1720&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1735&quot; data-start=&quot;1733&quot; data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1800&quot; data-start=&quot;1736&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1750&quot; data-start=&quot;1736&quot; data-section-id=&quot;c51x6s&quot;&gt;PageHeader&lt;/li&gt;
&lt;li data-end=&quot;1764&quot; data-start=&quot;1751&quot; data-section-id=&quot;1wmz6w6&quot;&gt;DataTable&lt;/li&gt;
&lt;li data-end=&quot;1780&quot; data-start=&quot;1765&quot; data-section-id=&quot;1olxbdl&quot;&gt;StatusBadge&lt;/li&gt;
&lt;li data-end=&quot;1800&quot; data-start=&quot;1781&quot; data-section-id=&quot;1nbg4tz&quot;&gt;SearchFilterBar&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1846&quot; data-start=&quot;1802&quot; data-ke-size=&quot;size16&quot;&gt;이름이나 구조 아이디어는 참고하고, 내용은 내 프로젝트에 맞게 바꾸면 된다.&lt;/p&gt;
&lt;p data-end=&quot;1846&quot; data-start=&quot;1802&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1846&quot; data-start=&quot;1802&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1877&quot; data-start=&quot;1853&quot; data-section-id=&quot;1i0raxe&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;절대 처음부터 다 안 만들어도 되는 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1896&quot; data-start=&quot;1879&quot; data-ke-size=&quot;size16&quot;&gt;이건 초반에 손대면 피곤해진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1999&quot; data-start=&quot;1898&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1909&quot; data-start=&quot;1898&quot; data-section-id=&quot;1bk0kah&quot;&gt;인증 시스템 전체&lt;/li&gt;
&lt;li data-end=&quot;1926&quot; data-start=&quot;1910&quot; data-section-id=&quot;cc9cyd&quot;&gt;복잡한 상태관리 라이브러리&lt;/li&gt;
&lt;li data-end=&quot;1938&quot; data-start=&quot;1927&quot; data-section-id=&quot;hgwrmg&quot;&gt;고급 테이블 기능&lt;/li&gt;
&lt;li data-end=&quot;1952&quot; data-start=&quot;1939&quot; data-section-id=&quot;18m4kv0&quot;&gt;서버 액션 고급 패턴&lt;/li&gt;
&lt;li data-end=&quot;1966&quot; data-start=&quot;1953&quot; data-section-id=&quot;1m5acwo&quot;&gt;권한 관리 전체 구조&lt;/li&gt;
&lt;li data-end=&quot;1985&quot; data-start=&quot;1967&quot; data-section-id=&quot;1d3u4jk&quot;&gt;차트 라이브러리 세세한 커스텀&lt;/li&gt;
&lt;li data-end=&quot;1999&quot; data-start=&quot;1986&quot; data-section-id=&quot;1dop8pk&quot;&gt;완벽한 폴더 아키텍처&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2037&quot; data-start=&quot;2001&quot; data-ke-size=&quot;size16&quot;&gt;초보일 때는 이거 붙잡으면 핵심인 관리자 화면 제작이 밀린다.&lt;/p&gt;
&lt;p data-end=&quot;2037&quot; data-start=&quot;2001&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2037&quot; data-start=&quot;2001&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2037&quot; data-start=&quot;2001&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;2061&quot; data-start=&quot;2044&quot; data-section-id=&quot;f0denc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2061&quot; data-start=&quot;2044&quot; data-section-id=&quot;f0denc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2061&quot; data-start=&quot;2044&quot; data-section-id=&quot;f0denc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2061&quot; data-start=&quot;2044&quot; data-section-id=&quot;f0denc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나한테 가장 추천하는 방식&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2061&quot; data-start=&quot;2044&quot; data-section-id=&quot;f0denc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2072&quot; data-start=&quot;2063&quot; data-section-id=&quot;1ehahbl&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가져올 것&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2122&quot; data-start=&quot;2073&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2088&quot; data-start=&quot;2073&quot; data-section-id=&quot;1h9vlz6&quot;&gt;Bootstrap 스타일&lt;/li&gt;
&lt;li data-end=&quot;2094&quot; data-start=&quot;2089&quot; data-section-id=&quot;2jiwqo&quot;&gt;아이콘&lt;/li&gt;
&lt;li data-end=&quot;2105&quot; data-start=&quot;2095&quot; data-section-id=&quot;1c43tb4&quot;&gt;기본 UI 일부&lt;/li&gt;
&lt;li data-end=&quot;2122&quot; data-start=&quot;2106&quot; data-section-id=&quot;1d9vz7v&quot;&gt;관리자 레이아웃 참고 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2135&quot; data-start=&quot;2124&quot; data-section-id=&quot;fh7e59&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;직접 만들 것&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2230&quot; data-start=&quot;2136&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2151&quot; data-start=&quot;2136&quot; data-section-id=&quot;w20nok&quot;&gt;Next.js 폴더 구조&lt;/li&gt;
&lt;li data-end=&quot;2171&quot; data-start=&quot;2152&quot; data-section-id=&quot;1ii3jxv&quot;&gt;app router 페이지 구성&lt;/li&gt;
&lt;li data-end=&quot;2186&quot; data-start=&quot;2172&quot; data-section-id=&quot;183l2il&quot;&gt;admin layout&lt;/li&gt;
&lt;li data-end=&quot;2203&quot; data-start=&quot;2187&quot; data-section-id=&quot;yijc3v&quot;&gt;목록/상세/등록/수정 화면&lt;/li&gt;
&lt;li data-end=&quot;2215&quot; data-start=&quot;2204&quot; data-section-id=&quot;1jd9gg9&quot;&gt;더미데이터 렌더링&lt;/li&gt;
&lt;li data-end=&quot;2222&quot; data-start=&quot;2216&quot; data-section-id=&quot;abq2m8&quot;&gt;폼 처리&lt;/li&gt;
&lt;li data-end=&quot;2230&quot; data-start=&quot;2223&quot; data-section-id=&quot;ezvpu0&quot;&gt;링크 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2244&quot; data-start=&quot;2232&quot; data-ke-size=&quot;size16&quot;&gt;이 조합이 제일 좋다~!&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;2690&quot; data-start=&quot;2681&quot; data-section-id=&quot;103gs7h&quot; data-ke-style=&quot;style3&quot;&gt;직접 만들 것&lt;br /&gt;&lt;b&gt;&amp;ldquo;넥스트 구조를 이해하는 데 필요한 것&amp;rdquo;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;가져다 써도 되는 것&lt;br /&gt;&lt;b&gt;&amp;ldquo;시간만 잡아먹고 학습효율은 낮은 것&amp;rdquo;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-end=&quot;2773&quot; data-start=&quot;2748&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2793&quot; data-start=&quot;2780&quot; data-section-id=&quot;125tduc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2793&quot; data-start=&quot;2780&quot; data-section-id=&quot;125tduc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2852&quot; data-start=&quot;2795&quot; data-ke-size=&quot;size16&quot;&gt;나는 지금&lt;br /&gt;&lt;b&gt;UI를 처음 만드는 사람&lt;/b&gt;이 아니라 &lt;b&gt;넥스트 구조를 처음 배우는 사람&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;2928&quot; data-start=&quot;2854&quot; data-ke-size=&quot;size16&quot;&gt;그래서&lt;br /&gt;&lt;b&gt;디자인 시스템이나 잔기술을 새로 만드는 것보다, Next.js에서 페이지와 레이아웃을 직접 짜보는 게 훨씬 중요하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;035&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/niniz/large/035.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/axz_keditor/emoticon/niniz/large/035.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;화이팅-!!&lt;/b&gt;&lt;/p&gt;</description>
      <category>Web/react</category>
      <author>아랄라랄라</author>
      <guid isPermaLink="true">https://studyhardgogo.tistory.com/373</guid>
      <comments>https://studyhardgogo.tistory.com/373#entry373comment</comments>
      <pubDate>Fri, 24 Apr 2026 15:51:12 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] 공부 시작 전, 내 현재 수준과 학습 방향 정리</title>
      <link>https://studyhardgogo.tistory.com/372</link>
      <description>&lt;p data-end=&quot;251&quot; data-start=&quot;123&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;251&quot; data-start=&quot;123&quot; data-ke-size=&quot;size16&quot;&gt;요즘 Next.js를 공부해보려고 한다.&lt;br /&gt;예전에 React 강의를 조금 들은 적이 있어서 프레임워크의 아주 기본적인 개념은 어렴풋이 알고 있지만, JavaScript는 아직 초보다. 대신 HTML과 CSS는 꽤 익숙한 편이다.&lt;/p&gt;
&lt;p data-end=&quot;350&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;그래서 내 목표는 &lt;b&gt;&amp;ldquo;Next.js를 깊이 있게 마스터하는 것&amp;rdquo;&lt;/b&gt; 보다는,&lt;br /&gt;우선 &lt;b&gt;Next.js로 웹사이트 프론트엔드를 직접 만들 수 있는 수준까지 가는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;350&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;350&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;350&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;350&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;350&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;367&quot; data-start=&quot;357&quot; data-section-id=&quot;fk64mc&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;내 현재 상태&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;367&quot; data-start=&quot;357&quot; data-section-id=&quot;fk64mc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;388&quot; data-start=&quot;369&quot; data-ke-size=&quot;size16&quot;&gt;지금 나의 상태를 정리하면 이렇다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;509&quot; data-start=&quot;390&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;408&quot; data-start=&quot;390&quot; data-section-id=&quot;41q0r1&quot;&gt;HTML / CSS는 능숙하다&lt;/li&gt;
&lt;li data-end=&quot;426&quot; data-start=&quot;409&quot; data-section-id=&quot;4dk6vr&quot;&gt;JavaScript는 초보다&lt;/li&gt;
&lt;li data-end=&quot;446&quot; data-start=&quot;427&quot; data-section-id=&quot;8gao60&quot;&gt;React는 아주 조금 접해봤다&lt;/li&gt;
&lt;li data-end=&quot;468&quot; data-start=&quot;447&quot; data-section-id=&quot;1hrpu0t&quot;&gt;프레임워크의 개념은 살짝 알고 있다&lt;/li&gt;
&lt;li data-end=&quot;509&quot; data-start=&quot;469&quot; data-section-id=&quot;1hmi5s8&quot;&gt;목표는 &lt;b&gt;실제로 웹사이트를 구현할 수 있는 프론트엔드 개발 수준&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;583&quot; data-start=&quot;511&quot; data-ke-size=&quot;size16&quot;&gt;이런 경우에는 처음부터 너무 어려운 개념을 한꺼번에 집어넣기보다,&lt;br /&gt;&lt;b&gt;필요한 만큼만 순서대로 배우는 방식&lt;/b&gt;이 훨씬 잘 맞다.&lt;/p&gt;
&lt;p data-end=&quot;583&quot; data-start=&quot;511&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;583&quot; data-start=&quot;511&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;598&quot; data-start=&quot;590&quot; data-section-id=&quot;1atsy6d&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;590&quot; data-section-id=&quot;1atsy6d&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;공부 목표&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;598&quot; data-start=&quot;590&quot; data-section-id=&quot;1atsy6d&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;626&quot; data-start=&quot;600&quot; data-ke-size=&quot;size16&quot;&gt;최종 목표는 아래처럼 잡는 게 가장 현실적이다.&lt;/p&gt;
&lt;blockquote data-end=&quot;690&quot; data-start=&quot;628&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;690&quot; data-start=&quot;630&quot; data-ke-size=&quot;size16&quot;&gt;디자인 시안이나 참고 사이트를 보고&lt;br /&gt;Next.js로 반응형 웹사이트 프론트엔드를 구현할 수 있는 상태&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;706&quot; data-start=&quot;692&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;706&quot; data-start=&quot;692&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;706&quot; data-start=&quot;692&quot; data-ke-size=&quot;size16&quot;&gt;좀 더 구체적으로 말하면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;823&quot; data-start=&quot;708&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;725&quot; data-start=&quot;708&quot; data-section-id=&quot;hb8xi8&quot;&gt;여러 페이지를 만들 수 있고&lt;/li&gt;
&lt;li data-end=&quot;745&quot; data-start=&quot;726&quot; data-section-id=&quot;17vuu4a&quot;&gt;공통 레이아웃을 구성할 수 있고&lt;/li&gt;
&lt;li data-end=&quot;766&quot; data-start=&quot;746&quot; data-section-id=&quot;xu7tk0&quot;&gt;컴포넌트로 UI를 분리할 수 있고&lt;/li&gt;
&lt;li data-end=&quot;794&quot; data-start=&quot;767&quot; data-section-id=&quot;beisrw&quot;&gt;더미 데이터나 간단한 API를 연결할 수 있고&lt;/li&gt;
&lt;li data-end=&quot;823&quot; data-start=&quot;795&quot; data-section-id=&quot;1ygrweb&quot;&gt;로딩/에러 처리까지 기본적으로 할 수 있는 수준&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;878&quot; data-start=&quot;825&quot; data-ke-size=&quot;size16&quot;&gt;여기까지 되면 &amp;ldquo;Next.js로 프론트엔드 웹사이트를 만든다&amp;rdquo;는 목표에는 충분히 도달한 것이다.&lt;/p&gt;
&lt;p data-end=&quot;878&quot; data-start=&quot;825&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;878&quot; data-start=&quot;825&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;878&quot; data-start=&quot;825&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;901&quot; data-start=&quot;885&quot; data-section-id=&quot;3ekyj&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;901&quot; data-start=&quot;885&quot; data-section-id=&quot;3ekyj&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;어떤 순서로 공부해야 할까&lt;/b&gt;&lt;/h4&gt;
&lt;p data-end=&quot;901&quot; data-start=&quot;885&quot; data-section-id=&quot;3ekyj&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;948&quot; data-start=&quot;903&quot; data-section-id=&quot;4pdiuu&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. JavaScript를 React/Next.js에 필요한 만큼만 공부하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;948&quot; data-start=&quot;903&quot; data-section-id=&quot;4pdiuu&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1055&quot; data-start=&quot;950&quot; data-ke-size=&quot;size16&quot;&gt;지금 단계에서 중요한 건 JavaScript를 완벽하게 공부하는 게 아니다.&lt;br /&gt;&lt;b&gt;React와 Next.js 코드를 읽고, 수정하고, 직접 작성할 수 있을 정도&lt;/b&gt;로 익히는 게 목표다.&lt;/p&gt;
&lt;p data-end=&quot;1055&quot; data-start=&quot;950&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1071&quot; data-start=&quot;1057&quot; data-ke-size=&quot;size16&quot;&gt;우선 꼭 익혀야 할 것들:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1216&quot; data-start=&quot;1073&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1094&quot; data-start=&quot;1073&quot; data-section-id=&quot;1nb6091&quot;&gt;변수 (let, const)&lt;/li&gt;
&lt;li data-end=&quot;1099&quot; data-start=&quot;1095&quot; data-section-id=&quot;yii57c&quot;&gt;함수&lt;/li&gt;
&lt;li data-end=&quot;1105&quot; data-start=&quot;1100&quot; data-section-id=&quot;2j3dp0&quot;&gt;조건문&lt;/li&gt;
&lt;li data-end=&quot;1115&quot; data-start=&quot;1106&quot; data-section-id=&quot;8sx3d6&quot;&gt;객체 / 배열&lt;/li&gt;
&lt;li data-end=&quot;1142&quot; data-start=&quot;1116&quot; data-section-id=&quot;1nkxu2x&quot;&gt;배열 메서드 (map, filter)&lt;/li&gt;
&lt;li data-end=&quot;1151&quot; data-start=&quot;1143&quot; data-section-id=&quot;18zn9b1&quot;&gt;구조분해할당&lt;/li&gt;
&lt;li data-end=&quot;1163&quot; data-start=&quot;1152&quot; data-section-id=&quot;leo9ec&quot;&gt;spread 문법&lt;/li&gt;
&lt;li data-end=&quot;1181&quot; data-start=&quot;1164&quot; data-section-id=&quot;1yablum&quot;&gt;import / export&lt;/li&gt;
&lt;li data-end=&quot;1206&quot; data-start=&quot;1182&quot; data-section-id=&quot;xjfwur&quot;&gt;비동기 처리 (async/await)&lt;/li&gt;
&lt;li data-end=&quot;1216&quot; data-start=&quot;1207&quot; data-section-id=&quot;19f85g4&quot;&gt;fetch&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1236&quot; data-start=&quot;1218&quot; data-ke-size=&quot;size16&quot;&gt;특히 아래 3개는 정말 중요하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1275&quot; data-start=&quot;1238&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1245&quot; data-start=&quot;1238&quot; data-section-id=&quot;168ldmc&quot;&gt;map&lt;/li&gt;
&lt;li data-end=&quot;1259&quot; data-start=&quot;1246&quot; data-section-id=&quot;1hvzkra&quot;&gt;객체 / 배열 다루기&lt;/li&gt;
&lt;li data-end=&quot;1275&quot; data-start=&quot;1260&quot; data-section-id=&quot;13s8anf&quot;&gt;async/await&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1315&quot; data-start=&quot;1277&quot; data-ke-size=&quot;size16&quot;&gt;이건 React, Next.js에 들어가면 계속 보게 되는 기본기다.&lt;/p&gt;
&lt;p data-end=&quot;1315&quot; data-start=&quot;1277&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1315&quot; data-start=&quot;1277&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1337&quot; data-start=&quot;1317&quot; data-section-id=&quot;14woo2w&quot; data-ke-size=&quot;size16&quot;&gt;이 단계에서 해보면 좋은 연습&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1392&quot; data-start=&quot;1338&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1350&quot; data-start=&quot;1338&quot; data-section-id=&quot;1rhty5k&quot;&gt;카드 리스트 만들기&lt;/li&gt;
&lt;li data-end=&quot;1361&quot; data-start=&quot;1351&quot; data-section-id=&quot;83x2rl&quot;&gt;탭 UI 만들기&lt;/li&gt;
&lt;li data-end=&quot;1372&quot; data-start=&quot;1362&quot; data-section-id=&quot;zmrlik&quot;&gt;아코디언 만들기&lt;/li&gt;
&lt;li data-end=&quot;1392&quot; data-start=&quot;1373&quot; data-section-id=&quot;1f71e1p&quot;&gt;JSON 데이터로 목록 출력하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1420&quot; data-start=&quot;1399&quot; data-section-id=&quot;giyj4w&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. React 핵심 개념 익히기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1420&quot; data-start=&quot;1399&quot; data-section-id=&quot;giyj4w&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1526&quot; data-start=&quot;1422&quot; data-ke-size=&quot;size16&quot;&gt;Next.js는 React 기반이라 React를 아예 모르고 들어가면 힘들다.&lt;br /&gt;하지만 지금 내 목표상 React를 깊게 파는 것보다는 &lt;b&gt;자주 쓰는 핵심 개념 위주&lt;/b&gt;로 익히면 된다.&lt;/p&gt;
&lt;p data-end=&quot;1526&quot; data-start=&quot;1422&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1539&quot; data-start=&quot;1528&quot; data-ke-size=&quot;size16&quot;&gt;우선 배워야 할 것:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1624&quot; data-start=&quot;1541&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1546&quot; data-start=&quot;1541&quot; data-section-id=&quot;1o49u1&quot;&gt;JSX&lt;/li&gt;
&lt;li data-end=&quot;1553&quot; data-start=&quot;1547&quot; data-section-id=&quot;c2jdhg&quot;&gt;컴포넌트&lt;/li&gt;
&lt;li data-end=&quot;1561&quot; data-start=&quot;1554&quot; data-section-id=&quot;16jm0ee&quot;&gt;props&lt;/li&gt;
&lt;li data-end=&quot;1569&quot; data-start=&quot;1562&quot; data-section-id=&quot;16n889r&quot;&gt;state&lt;/li&gt;
&lt;li data-end=&quot;1578&quot; data-start=&quot;1570&quot; data-section-id=&quot;xyoztg&quot;&gt;이벤트 처리&lt;/li&gt;
&lt;li data-end=&quot;1588&quot; data-start=&quot;1579&quot; data-section-id=&quot;7gl5lh&quot;&gt;조건부 렌더링&lt;/li&gt;
&lt;li data-end=&quot;1598&quot; data-start=&quot;1589&quot; data-section-id=&quot;1kdhxnl&quot;&gt;리스트 렌더링&lt;/li&gt;
&lt;li data-end=&quot;1607&quot; data-start=&quot;1599&quot; data-section-id=&quot;13fw6ge&quot;&gt;입력값 처리&lt;/li&gt;
&lt;li data-end=&quot;1624&quot; data-start=&quot;1608&quot; data-section-id=&quot;1uzd58k&quot;&gt;useEffect 기초&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1696&quot; data-start=&quot;1626&quot; data-ke-size=&quot;size16&quot;&gt;이 단계에서 중요한 건&lt;br /&gt;&lt;b&gt;HTML을 그대로 길게 쓰는 방식에서, 컴포넌트 단위로 나누는 사고방식으로 바꾸는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;1696&quot; data-start=&quot;1626&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1716&quot; data-start=&quot;1698&quot; data-section-id=&quot;1ahefi&quot; data-ke-size=&quot;size16&quot;&gt;React 단계 실습 예시&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1761&quot; data-start=&quot;1717&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1725&quot; data-start=&quot;1717&quot; data-section-id=&quot;8hio5n&quot;&gt;좋아요 버튼&lt;/li&gt;
&lt;li data-end=&quot;1730&quot; data-start=&quot;1726&quot; data-section-id=&quot;yhyk8c&quot;&gt;모달&lt;/li&gt;
&lt;li data-end=&quot;1741&quot; data-start=&quot;1731&quot; data-section-id=&quot;c1bpz6&quot;&gt;FAQ 아코디언&lt;/li&gt;
&lt;li data-end=&quot;1749&quot; data-start=&quot;1742&quot; data-section-id=&quot;domjrp&quot;&gt;검색 필터&lt;/li&gt;
&lt;li data-end=&quot;1761&quot; data-start=&quot;1750&quot; data-section-id=&quot;pfktd9&quot;&gt;상품 리스트 UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1786&quot; data-start=&quot;1768&quot; data-section-id=&quot;1kgjmhp&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. Next.js 입문하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1786&quot; data-start=&quot;1768&quot; data-section-id=&quot;1kgjmhp&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1866&quot; data-start=&quot;1788&quot; data-ke-size=&quot;size16&quot;&gt;React 핵심을 어느 정도 익힌 뒤에는 Next.js로 넘어간다.&lt;br /&gt;최신 기준으로는 &lt;b&gt;App Router 중심&lt;/b&gt;으로 배우는 게 좋다.&lt;/p&gt;
&lt;p data-end=&quot;1866&quot; data-start=&quot;1788&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1884&quot; data-start=&quot;1868&quot; data-ke-size=&quot;size16&quot;&gt;이 단계에서 익혀야 할 것들:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2033&quot; data-start=&quot;1886&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1900&quot; data-start=&quot;1886&quot; data-section-id=&quot;1xjolq2&quot;&gt;app/ 폴더 구조&lt;/li&gt;
&lt;li data-end=&quot;1912&quot; data-start=&quot;1901&quot; data-section-id=&quot;dxtmrw&quot;&gt;page.js&lt;/li&gt;
&lt;li data-end=&quot;1926&quot; data-start=&quot;1913&quot; data-section-id=&quot;206d9h&quot;&gt;layout.js&lt;/li&gt;
&lt;li data-end=&quot;1938&quot; data-start=&quot;1927&quot; data-section-id=&quot;g85k8p&quot;&gt;파일 기반 라우팅&lt;/li&gt;
&lt;li data-end=&quot;1948&quot; data-start=&quot;1939&quot; data-section-id=&quot;1hqsu1f&quot;&gt;공통 레이아웃&lt;/li&gt;
&lt;li data-end=&quot;1957&quot; data-start=&quot;1949&quot; data-section-id=&quot;17q4tl4&quot;&gt;Link&lt;/li&gt;
&lt;li data-end=&quot;1967&quot; data-start=&quot;1958&quot; data-section-id=&quot;1r1pfyk&quot;&gt;컴포넌트 분리&lt;/li&gt;
&lt;li data-end=&quot;2008&quot; data-start=&quot;1968&quot; data-section-id=&quot;177gchj&quot;&gt;Server Component / Client Component 개념&lt;/li&gt;
&lt;li data-end=&quot;2033&quot; data-start=&quot;2009&quot; data-section-id=&quot;15rulh2&quot;&gt;&quot;use client&quot;가 필요한 상황&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2062&quot; data-start=&quot;2035&quot; data-ke-size=&quot;size16&quot;&gt;여기서 초보 입장에서 가장 중요한 감각은 이거다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2165&quot; data-start=&quot;2064&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2115&quot; data-start=&quot;2064&quot; data-section-id=&quot;1iql2fu&quot;&gt;클릭, 입력, 탭 전환처럼 &lt;b&gt;사용자 인터랙션이 있으면 Client Component&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2165&quot; data-start=&quot;2116&quot; data-section-id=&quot;1muzg8i&quot;&gt;데이터 읽어서 화면만 그리는 용도면 &lt;b&gt;Server Component부터 생각하기&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2190&quot; data-start=&quot;2167&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 이 정도 감각만 있어도 충분하다.&lt;/p&gt;
&lt;p data-end=&quot;2190&quot; data-start=&quot;2167&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2190&quot; data-start=&quot;2167&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2190&quot; data-start=&quot;2167&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2190&quot; data-start=&quot;2167&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2210&quot; data-start=&quot;2197&quot; data-section-id=&quot;euzlbr&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 데이터 다루기&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2210&quot; data-start=&quot;2197&quot; data-section-id=&quot;euzlbr&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2270&quot; data-start=&quot;2212&quot; data-ke-size=&quot;size16&quot;&gt;Next.js 공부가 어느 정도 되면,&lt;br /&gt;정적인 화면만 만드는 단계에서 벗어나 데이터를 붙여봐야 한다.&lt;/p&gt;
&lt;p data-end=&quot;2270&quot; data-start=&quot;2212&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2292&quot; data-start=&quot;2272&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 아주 간단하게 시작하면 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2366&quot; data-start=&quot;2294&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2310&quot; data-start=&quot;2294&quot; data-section-id=&quot;syc09p&quot;&gt;JSON 파일 import&lt;/li&gt;
&lt;li data-end=&quot;2322&quot; data-start=&quot;2311&quot; data-section-id=&quot;fkiy5s&quot;&gt;더미 데이터 연결&lt;/li&gt;
&lt;li data-end=&quot;2344&quot; data-start=&quot;2323&quot; data-section-id=&quot;19nyuup&quot;&gt;fetch()로 데이터 가져오기&lt;/li&gt;
&lt;li data-end=&quot;2355&quot; data-start=&quot;2345&quot; data-section-id=&quot;103qdbo&quot;&gt;로딩 상태 처리&lt;/li&gt;
&lt;li data-end=&quot;2366&quot; data-start=&quot;2356&quot; data-section-id=&quot;1d5v41p&quot;&gt;에러 상태 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2403&quot; data-start=&quot;2368&quot; data-ke-size=&quot;size16&quot;&gt;이 단계에서는 아직 아래 내용까지 무리해서 들어갈 필요는 없다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2454&quot; data-start=&quot;2405&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2416&quot; data-start=&quot;2405&quot; data-section-id=&quot;1r5uvt8&quot;&gt;데이터베이스 연결&lt;/li&gt;
&lt;li data-end=&quot;2421&quot; data-start=&quot;2417&quot; data-section-id=&quot;yilg7h&quot;&gt;인증&lt;/li&gt;
&lt;li data-end=&quot;2430&quot; data-start=&quot;2422&quot; data-section-id=&quot;1lrfge9&quot;&gt;복잡한 캐싱&lt;/li&gt;
&lt;li data-end=&quot;2441&quot; data-start=&quot;2431&quot; data-section-id=&quot;1m4gtip&quot;&gt;서버 액션 심화&lt;/li&gt;
&lt;li data-end=&quot;2454&quot; data-start=&quot;2442&quot; data-section-id=&quot;13mk15p&quot;&gt;상태관리 라이브러리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2518&quot; data-start=&quot;2456&quot; data-ke-size=&quot;size16&quot;&gt;지금 목표는 &lt;b&gt;프론트엔드 웹사이트 구현&lt;/b&gt;이기 때문에,&lt;br /&gt;처음부터 백엔드 개념까지 다 끌어안지 않아도 된다.&lt;/p&gt;
&lt;p data-end=&quot;2518&quot; data-start=&quot;2456&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2518&quot; data-start=&quot;2456&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2518&quot; data-start=&quot;2456&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h2 data-end=&quot;2548&quot; data-start=&quot;2525&quot; data-section-id=&quot;1b011kj&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-end=&quot;2548&quot; data-start=&quot;2525&quot; data-section-id=&quot;1b011kj&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-end=&quot;2548&quot; data-start=&quot;2525&quot; data-section-id=&quot;1b011kj&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5. 실제 웹사이트를 만들어보는 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2548&quot; data-start=&quot;2525&quot; data-section-id=&quot;1b011kj&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2614&quot; data-start=&quot;2550&quot; data-ke-size=&quot;size16&quot;&gt;결국 공부는 프로젝트를 해봐야 내 것이 된다.&lt;br /&gt;개념만 계속 보면 &amp;ldquo;아는 것 같은데 못 만드는 상태&amp;rdquo;가 오래간다.&lt;/p&gt;
&lt;p data-end=&quot;2648&quot; data-start=&quot;2616&quot; data-ke-size=&quot;size16&quot;&gt;그래서 작은 사이트라도 직접 만들어보는 게 가장 중요하다.&lt;/p&gt;
&lt;p data-end=&quot;2648&quot; data-start=&quot;2616&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2648&quot; data-start=&quot;2616&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2675&quot; data-start=&quot;2650&quot; data-section-id=&quot;ryxeaf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로젝트 1. 브랜드/회사 소개 사이트&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2675&quot; data-start=&quot;2650&quot; data-section-id=&quot;ryxeaf&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2682&quot; data-start=&quot;2676&quot; data-ke-size=&quot;size16&quot;&gt;구성 예시:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2702&quot; data-start=&quot;2683&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2686&quot; data-start=&quot;2683&quot; data-section-id=&quot;3752ao&quot;&gt;홈&lt;/li&gt;
&lt;li data-end=&quot;2691&quot; data-start=&quot;2687&quot; data-section-id=&quot;yilqd4&quot;&gt;소개&lt;/li&gt;
&lt;li data-end=&quot;2697&quot; data-start=&quot;2692&quot; data-section-id=&quot;2kk1ck&quot;&gt;서비스&lt;/li&gt;
&lt;li data-end=&quot;2702&quot; data-start=&quot;2698&quot; data-section-id=&quot;yhyx8o&quot;&gt;문의&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2719&quot; data-start=&quot;2704&quot; data-ke-size=&quot;size16&quot;&gt;이 프로젝트에서 배우는 것:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2763&quot; data-start=&quot;2720&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2728&quot; data-start=&quot;2720&quot; data-section-id=&quot;1yhx89&quot;&gt;페이지 구성&lt;/li&gt;
&lt;li data-end=&quot;2739&quot; data-start=&quot;2729&quot; data-section-id=&quot;1kfb41r&quot;&gt;공통 헤더/푸터&lt;/li&gt;
&lt;li data-end=&quot;2750&quot; data-start=&quot;2740&quot; data-section-id=&quot;19857tb&quot;&gt;반응형 레이아웃&lt;/li&gt;
&lt;li data-end=&quot;2763&quot; data-start=&quot;2751&quot; data-section-id=&quot;f9v4fh&quot;&gt;섹션 컴포넌트 분리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2793&quot; data-start=&quot;2770&quot; data-section-id=&quot;14epbq7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로젝트 2. 콘텐츠 리스트 사이트&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2793&quot; data-start=&quot;2770&quot; data-section-id=&quot;14epbq7&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2800&quot; data-start=&quot;2794&quot; data-ke-size=&quot;size16&quot;&gt;구성 예시:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2828&quot; data-start=&quot;2801&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2809&quot; data-start=&quot;2801&quot; data-section-id=&quot;114bqwg&quot;&gt;목록 페이지&lt;/li&gt;
&lt;li data-end=&quot;2818&quot; data-start=&quot;2810&quot; data-section-id=&quot;g9vpod&quot;&gt;상세 페이지&lt;/li&gt;
&lt;li data-end=&quot;2828&quot; data-start=&quot;2819&quot; data-section-id=&quot;x137d4&quot;&gt;카테고리 필터&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2845&quot; data-start=&quot;2830&quot; data-ke-size=&quot;size16&quot;&gt;이 프로젝트에서 배우는 것:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2878&quot; data-start=&quot;2846&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2854&quot; data-start=&quot;2846&quot; data-section-id=&quot;102sc55&quot;&gt;동적 라우팅&lt;/li&gt;
&lt;li data-end=&quot;2864&quot; data-start=&quot;2855&quot; data-section-id=&quot;1ypmp7p&quot;&gt;데이터 렌더링&lt;/li&gt;
&lt;li data-end=&quot;2878&quot; data-start=&quot;2865&quot; data-section-id=&quot;1yaxipx&quot;&gt;카드 컴포넌트 재사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2906&quot; data-start=&quot;2885&quot; data-section-id=&quot;1ari72v&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로젝트 3. 실무형 UI 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2906&quot; data-start=&quot;2885&quot; data-section-id=&quot;1ari72v&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2910&quot; data-start=&quot;2907&quot; data-ke-size=&quot;size16&quot;&gt;구성 예시:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2954&quot; data-start=&quot;2911&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2923&quot; data-start=&quot;2911&quot; data-section-id=&quot;1xwrn3b&quot;&gt;상품 목록 + 상세&lt;/li&gt;
&lt;li data-end=&quot;2932&quot; data-start=&quot;2924&quot; data-section-id=&quot;10uqb81&quot;&gt;예약 페이지&lt;/li&gt;
&lt;li data-end=&quot;2942&quot; data-start=&quot;2933&quot; data-section-id=&quot;kxhfk0&quot;&gt;대시보드 일부&lt;/li&gt;
&lt;li data-end=&quot;2954&quot; data-start=&quot;2943&quot; data-section-id=&quot;9ye2w&quot;&gt;관리자 화면 일부&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2971&quot; data-start=&quot;2956&quot; data-ke-size=&quot;size16&quot;&gt;이 프로젝트에서 배우는 것:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3028&quot; data-start=&quot;2972&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2982&quot; data-start=&quot;2972&quot; data-section-id=&quot;kwwbjo&quot;&gt;화면 구조 설계&lt;/li&gt;
&lt;li data-end=&quot;2992&quot; data-start=&quot;2983&quot; data-section-id=&quot;1r1x77o&quot;&gt;컴포넌트 설계&lt;/li&gt;
&lt;li data-end=&quot;3009&quot; data-start=&quot;2993&quot; data-section-id=&quot;1ifb8ip&quot;&gt;유지보수 가능한 폴더 구조&lt;/li&gt;
&lt;li data-end=&quot;3028&quot; data-start=&quot;3010&quot; data-section-id=&quot;dmilp8&quot;&gt;실제 서비스형 UI 구현 감각&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h1 data-end=&quot;3048&quot; data-start=&quot;3035&quot; data-section-id=&quot;b0fhzp&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3048&quot; data-start=&quot;3035&quot; data-section-id=&quot;b0fhzp&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;내게 맞는 공부 방식&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3048&quot; data-start=&quot;3035&quot; data-section-id=&quot;b0fhzp&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3109&quot; data-start=&quot;3050&quot; data-ke-size=&quot;size16&quot;&gt;내 경우에는 HTML/CSS가 강점이기 때문에&lt;br /&gt;그 강점을 버릴 필요가 전혀 없다. 오히려 큰 장점이다.&lt;/p&gt;
&lt;p data-end=&quot;3134&quot; data-start=&quot;3111&quot; data-ke-size=&quot;size16&quot;&gt;그래서 가장 잘 맞는 공부 방식은 이거다.&lt;/p&gt;
&lt;p data-end=&quot;3134&quot; data-start=&quot;3111&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;3156&quot; data-start=&quot;3136&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;3156&quot; data-start=&quot;3138&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개념 30%, 구현 70%&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;3160&quot; data-start=&quot;3158&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3160&quot; data-start=&quot;3158&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3263&quot; data-start=&quot;3162&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3176&quot; data-start=&quot;3162&quot; data-section-id=&quot;702vtd&quot;&gt;문법만 오래 보지 말고&lt;/li&gt;
&lt;li data-end=&quot;3194&quot; data-start=&quot;3177&quot; data-section-id=&quot;67ihxp&quot;&gt;작은 화면이라도 직접 만들고&lt;/li&gt;
&lt;li data-end=&quot;3222&quot; data-start=&quot;3195&quot; data-section-id=&quot;8t2u9s&quot;&gt;정적인 HTML을 React 컴포넌트로 바꾸고&lt;/li&gt;
&lt;li data-end=&quot;3263&quot; data-start=&quot;3223&quot; data-section-id=&quot;1gbd12w&quot;&gt;그걸 Next.js 페이지로 조립하는 식으로 가는 게 가장 효율적이다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;3285&quot; data-start=&quot;3270&quot; data-section-id=&quot;wdivkd&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-end=&quot;3285&quot; data-start=&quot;3270&quot; data-section-id=&quot;wdivkd&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;공부할 때 기억할 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3285&quot; data-start=&quot;3270&quot; data-section-id=&quot;wdivkd&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3318&quot; data-start=&quot;3287&quot; data-ke-size=&quot;size16&quot;&gt;Next.js 공부는 아래 흐름으로 이해하면 훨씬 쉽다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;3457&quot; data-start=&quot;3320&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;3337&quot; data-start=&quot;3320&quot; data-section-id=&quot;ce7lg3&quot;&gt;HTML로 화면 만든다&lt;/li&gt;
&lt;li data-end=&quot;3362&quot; data-start=&quot;3338&quot; data-section-id=&quot;1fud3so&quot;&gt;반복되는 UI를 컴포넌트로 분리한다&lt;/li&gt;
&lt;li data-end=&quot;3383&quot; data-start=&quot;3363&quot; data-section-id=&quot;1v89h0m&quot;&gt;props로 데이터 연결한다&lt;/li&gt;
&lt;li data-end=&quot;3406&quot; data-start=&quot;3384&quot; data-section-id=&quot;7odk4v&quot;&gt;Next.js 페이지로 배치한다&lt;/li&gt;
&lt;li data-end=&quot;3436&quot; data-start=&quot;3407&quot; data-section-id=&quot;ef1gle&quot;&gt;fetch나 더미 데이터로 내용을 붙인다&lt;/li&gt;
&lt;li data-end=&quot;3457&quot; data-start=&quot;3437&quot; data-section-id=&quot;26ts8d&quot;&gt;실제 사이트처럼 다듬고 배포한다&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;3540&quot; data-start=&quot;3459&quot; data-ke-size=&quot;size16&quot;&gt;이 흐름이 잡히면&lt;br /&gt;Next.js가 갑자기 어려운 기술처럼 느껴지지 않고,&lt;br /&gt;&amp;ldquo;익숙한 퍼블리싱에서 한 단계 확장된 방식&amp;rdquo;으로 보이기 시작한다.&lt;/p&gt;
&lt;p data-end=&quot;3540&quot; data-start=&quot;3459&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3540&quot; data-start=&quot;3459&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3540&quot; data-start=&quot;3459&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3540&quot; data-start=&quot;3459&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3540&quot; data-start=&quot;3459&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h1 data-end=&quot;3573&quot; data-start=&quot;3547&quot; data-section-id=&quot;hyr5kq&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3573&quot; data-start=&quot;3547&quot; data-section-id=&quot;hyr5kq&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;지금 단계에서 너무 욕심내지 않아도 되는 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3573&quot; data-start=&quot;3547&quot; data-section-id=&quot;hyr5kq&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3605&quot; data-start=&quot;3575&quot; data-ke-size=&quot;size16&quot;&gt;처음부터 아래 내용까지 다 하려고 하면 오히려 지친다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3697&quot; data-start=&quot;3607&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3622&quot; data-start=&quot;3607&quot; data-section-id=&quot;a86x5z&quot;&gt;TypeScript 심화&lt;/li&gt;
&lt;li data-end=&quot;3640&quot; data-start=&quot;3623&quot; data-section-id=&quot;6fu3ga&quot;&gt;Redux / Zustand&lt;/li&gt;
&lt;li data-end=&quot;3649&quot; data-start=&quot;3641&quot; data-section-id=&quot;1rajk9c&quot;&gt;테스트 코드&lt;/li&gt;
&lt;li data-end=&quot;3658&quot; data-start=&quot;3650&quot; data-section-id=&quot;1y5uo21&quot;&gt;인증 시스템&lt;/li&gt;
&lt;li data-end=&quot;3669&quot; data-start=&quot;3659&quot; data-section-id=&quot;1m4gtip&quot;&gt;서버 액션 심화&lt;/li&gt;
&lt;li data-end=&quot;3678&quot; data-start=&quot;3670&quot; data-section-id=&quot;5r8bzd&quot;&gt;SEO 심화&lt;/li&gt;
&lt;li data-end=&quot;3685&quot; data-start=&quot;3679&quot; data-section-id=&quot;1t73ieg&quot;&gt;미들웨어&lt;/li&gt;
&lt;li data-end=&quot;3697&quot; data-start=&quot;3686&quot; data-section-id=&quot;1i53a5s&quot;&gt;복잡한 캐싱 전략&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3769&quot; data-start=&quot;3699&quot; data-ke-size=&quot;size16&quot;&gt;이건 나중 단계에서 필요할 때 추가하면 된다.&lt;br /&gt;지금은 &lt;b&gt;프론트엔드 웹사이트 구현 능력&lt;/b&gt;을 먼저 만드는 게 더 중요하다.&lt;/p&gt;
&lt;p data-end=&quot;3769&quot; data-start=&quot;3699&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3769&quot; data-start=&quot;3699&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3769&quot; data-start=&quot;3699&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3769&quot; data-start=&quot;3699&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3769&quot; data-start=&quot;3699&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;3793&quot; data-start=&quot;3776&quot; data-section-id=&quot;1wnxman&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3793&quot; data-start=&quot;3776&quot; data-section-id=&quot;1wnxman&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3793&quot; data-start=&quot;3776&quot; data-section-id=&quot;1wnxman&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3793&quot; data-start=&quot;3776&quot; data-section-id=&quot;1wnxman&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3793&quot; data-start=&quot;3776&quot; data-section-id=&quot;1wnxman&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;8주 정도로 보면 이런 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3793&quot; data-start=&quot;3776&quot; data-section-id=&quot;1wnxman&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3803&quot; data-start=&quot;3795&quot; data-section-id=&quot;zgo08c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1~2주차&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3873&quot; data-start=&quot;3804&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3819&quot; data-start=&quot;3804&quot; data-section-id=&quot;hwxgf7&quot;&gt;JavaScript 기초&lt;/li&gt;
&lt;li data-end=&quot;3829&quot; data-start=&quot;3820&quot; data-section-id=&quot;ll0bl6&quot;&gt;배열 / 객체&lt;/li&gt;
&lt;li data-end=&quot;3847&quot; data-start=&quot;3830&quot; data-section-id=&quot;1lj3048&quot;&gt;map, filter&lt;/li&gt;
&lt;li data-end=&quot;3863&quot; data-start=&quot;3848&quot; data-section-id=&quot;13s8anf&quot;&gt;async/await&lt;/li&gt;
&lt;li data-end=&quot;3873&quot; data-start=&quot;3864&quot; data-section-id=&quot;19f85g4&quot;&gt;fetch&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3881&quot; data-start=&quot;3875&quot; data-section-id=&quot;1hrs2oy&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3주차&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3944&quot; data-start=&quot;3882&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3892&quot; data-start=&quot;3882&quot; data-section-id=&quot;u4h34h&quot;&gt;React 기초&lt;/li&gt;
&lt;li data-end=&quot;3899&quot; data-start=&quot;3893&quot; data-section-id=&quot;c2jdhg&quot;&gt;컴포넌트&lt;/li&gt;
&lt;li data-end=&quot;3915&quot; data-start=&quot;3900&quot; data-section-id=&quot;1i8tizi&quot;&gt;props / state&lt;/li&gt;
&lt;li data-end=&quot;3924&quot; data-start=&quot;3916&quot; data-section-id=&quot;xyoztg&quot;&gt;이벤트 처리&lt;/li&gt;
&lt;li data-end=&quot;3934&quot; data-start=&quot;3925&quot; data-section-id=&quot;7gl5lh&quot;&gt;조건부 렌더링&lt;/li&gt;
&lt;li data-end=&quot;3944&quot; data-start=&quot;3935&quot; data-section-id=&quot;1kdhxnl&quot;&gt;리스트 렌더링&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3952&quot; data-start=&quot;3946&quot; data-section-id=&quot;1hrs3ol&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4주차&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3985&quot; data-start=&quot;3953&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3968&quot; data-start=&quot;3953&quot; data-section-id=&quot;1xhy9l0&quot;&gt;React 미니 프로젝트&lt;/li&gt;
&lt;li data-end=&quot;3985&quot; data-start=&quot;3969&quot; data-section-id=&quot;j30ueh&quot;&gt;모달 / 탭 / 필터 UI&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3993&quot; data-start=&quot;3987&quot; data-section-id=&quot;1hrpnl0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5주차&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4066&quot; data-start=&quot;3994&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4006&quot; data-start=&quot;3994&quot; data-section-id=&quot;1ub8k39&quot;&gt;Next.js 시작&lt;/li&gt;
&lt;li data-end=&quot;4022&quot; data-start=&quot;4007&quot; data-section-id=&quot;ztvpxa&quot;&gt;App Router 구조&lt;/li&gt;
&lt;li data-end=&quot;4047&quot; data-start=&quot;4023&quot; data-section-id=&quot;4xum31&quot;&gt;page.js, layout.js&lt;/li&gt;
&lt;li data-end=&quot;4056&quot; data-start=&quot;4048&quot; data-section-id=&quot;17q4tl4&quot;&gt;Link&lt;/li&gt;
&lt;li data-end=&quot;4066&quot; data-start=&quot;4057&quot; data-section-id=&quot;1r1pfyk&quot;&gt;컴포넌트 분리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4074&quot; data-start=&quot;4068&quot; data-section-id=&quot;1hrs59j&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6주차&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4109&quot; data-start=&quot;4075&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4086&quot; data-start=&quot;4075&quot; data-section-id=&quot;1yn7vht&quot;&gt;정적 사이트 제작&lt;/li&gt;
&lt;li data-end=&quot;4096&quot; data-start=&quot;4087&quot; data-section-id=&quot;1hqsu1f&quot;&gt;공통 레이아웃&lt;/li&gt;
&lt;li data-end=&quot;4109&quot; data-start=&quot;4097&quot; data-section-id=&quot;b3micl&quot;&gt;반응형 페이지 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4117&quot; data-start=&quot;4111&quot; data-section-id=&quot;1hrs4h2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7주차&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4148&quot; data-start=&quot;4118&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4126&quot; data-start=&quot;4118&quot; data-section-id=&quot;yf7p4s&quot;&gt;데이터 연결&lt;/li&gt;
&lt;li data-end=&quot;4135&quot; data-start=&quot;4127&quot; data-section-id=&quot;g9vpod&quot;&gt;상세 페이지&lt;/li&gt;
&lt;li data-end=&quot;4148&quot; data-start=&quot;4136&quot; data-section-id=&quot;lsro4a&quot;&gt;로딩 / 에러 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4156&quot; data-start=&quot;4150&quot; data-section-id=&quot;1hrriy1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8주차&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4181&quot; data-start=&quot;4157&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4169&quot; data-start=&quot;4157&quot; data-section-id=&quot;4synpc&quot;&gt;실전 프로젝트 완성&lt;/li&gt;
&lt;li data-end=&quot;4174&quot; data-start=&quot;4170&quot; data-section-id=&quot;yi0sc4&quot;&gt;배포&lt;/li&gt;
&lt;li data-end=&quot;4181&quot; data-start=&quot;4175&quot; data-section-id=&quot;1sz2ij0&quot;&gt;리팩토링&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h1 data-end=&quot;4209&quot; data-start=&quot;4188&quot; data-section-id=&quot;qoqnlp&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1 data-end=&quot;4209&quot; data-start=&quot;4188&quot; data-section-id=&quot;qoqnlp&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-end=&quot;4209&quot; data-start=&quot;4188&quot; data-section-id=&quot;qoqnlp&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;내가 앞으로 공부할 때 체크할 기준&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4209&quot; data-start=&quot;4188&quot; data-section-id=&quot;qoqnlp&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4209&quot; data-start=&quot;4188&quot; data-section-id=&quot;qoqnlp&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4225&quot; data-start=&quot;4211&quot; data-section-id=&quot;6qcv99&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;잘 가고 있다는 신호&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4344&quot; data-start=&quot;4226&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4254&quot; data-start=&quot;4226&quot; data-section-id=&quot;gmat7h&quot;&gt;HTML을 보면 어떤 컴포넌트로 나눌지 떠오른다&lt;/li&gt;
&lt;li data-end=&quot;4278&quot; data-start=&quot;4255&quot; data-section-id=&quot;1575ec7&quot;&gt;반복 UI를 props로 바꿀 수 있다&lt;/li&gt;
&lt;li data-end=&quot;4300&quot; data-start=&quot;4279&quot; data-section-id=&quot;1n8644k&quot;&gt;폴더 구조로 페이지를 만들 수 있다&lt;/li&gt;
&lt;li data-end=&quot;4325&quot; data-start=&quot;4301&quot; data-section-id=&quot;14quezs&quot;&gt;더미 데이터로 먼저 화면을 만들 수 있다&lt;/li&gt;
&lt;li data-end=&quot;4344&quot; data-start=&quot;4326&quot; data-section-id=&quot;10hly8x&quot;&gt;콘솔 에러가 나와도 덜 겁난다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4365&quot; data-start=&quot;4346&quot; data-section-id=&quot;1pl2gnw&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아직 더 익숙해져야 하는 신호&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4460&quot; data-start=&quot;4366&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4383&quot; data-start=&quot;4366&quot; data-section-id=&quot;1snmz0r&quot;&gt;map()이 아직 낯설다&lt;/li&gt;
&lt;li data-end=&quot;4404&quot; data-start=&quot;4384&quot; data-section-id=&quot;tkgl24&quot;&gt;state가 왜 필요한지 흐릿하다&lt;/li&gt;
&lt;li data-end=&quot;4440&quot; data-start=&quot;4405&quot; data-section-id=&quot;1ilhadp&quot;&gt;Client / Server Component 구분이 어렵다&lt;/li&gt;
&lt;li data-end=&quot;4460&quot; data-start=&quot;4441&quot; data-section-id=&quot;1nsifr0&quot;&gt;폴더 구조를 매번 감으로 만든다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4471&quot; data-start=&quot;4467&quot; data-section-id=&quot;yi4awm&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4471&quot; data-start=&quot;4467&quot; data-section-id=&quot;yi4awm&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4551&quot; data-start=&quot;4473&quot; data-ke-size=&quot;size16&quot;&gt;지금 내 상황에서 Next.js 공부는&lt;br /&gt;&amp;ldquo;처음부터 완벽하게 이해하는 공부&amp;rdquo;보다&lt;br /&gt;&lt;b&gt;실제로 만들 수 있게 되는 공부&lt;/b&gt;가 더 중요하다.&lt;/p&gt;
&lt;p data-end=&quot;4628&quot; data-start=&quot;4553&quot; data-ke-size=&quot;size16&quot;&gt;내 강점은 HTML/CSS이고,&lt;br /&gt;부족한 부분은 JavaScript와 React 기본기다.&lt;/p&gt;
&lt;p data-end=&quot;4628&quot; data-start=&quot;4553&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그래서 가장 좋은 순서는 아래와 같다.&lt;/p&gt;
&lt;p data-end=&quot;4702&quot; data-start=&quot;4630&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;JavaScript 기초 &amp;rarr; React 핵심 &amp;rarr; Next.js App Router &amp;rarr; 작은 프로젝트 &amp;rarr; 실제 웹사이트 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4730&quot; data-start=&quot;4704&quot; data-ke-size=&quot;size16&quot;&gt;결국 가장 중요한 건 이 한 문장으로 정리된다.&lt;/p&gt;
&lt;p data-end=&quot;4730&quot; data-start=&quot;4704&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;4794&quot; data-start=&quot;4732&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;4794&quot; data-start=&quot;4734&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정적인 HTML을 React 컴포넌트로 바꾸고, 그걸 Next.js 페이지로 조립하는 힘을 기르는 것&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;4859&quot; data-start=&quot;4796&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4859&quot; data-start=&quot;4796&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4859&quot; data-start=&quot;4796&quot; data-ke-size=&quot;size16&quot;&gt;이 방향으로 가면&lt;br /&gt;초보자여도 충분히 Next.js로 웹사이트 프론트엔드를 만들 수 있는 수준까지 갈 수 있다.&lt;/p&gt;</description>
      <category>Web/react</category>
      <author>아랄라랄라</author>
      <guid isPermaLink="true">https://studyhardgogo.tistory.com/372</guid>
      <comments>https://studyhardgogo.tistory.com/372#entry372comment</comments>
      <pubDate>Tue, 21 Apr 2026 09:57:10 +0900</pubDate>
    </item>
    <item>
      <title>[Figma] 이미지 Export 설정 항목 설명</title>
      <link>https://studyhardgogo.tistory.com/370</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dB033o/btsPAOcllB8/XcRWM35AUIHI4GFcRrMlok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dB033o/btsPAOcllB8/XcRWM35AUIHI4GFcRrMlok/img.png&quot; data-alt=&quot;피그마 Export 창&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dB033o/btsPAOcllB8/XcRWM35AUIHI4GFcRrMlok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdB033o%2FbtsPAOcllB8%2FXcRWM35AUIHI4GFcRrMlok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;270&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;피그마 Export 창&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;90&quot; data-start=&quot;62&quot; data-section-id=&quot;1dsqq4h&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;  왼쪽 설정창 (세부 Export 옵션)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;125&quot; data-start=&quot;91&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Ignore overlapping layers&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-end=&quot;138&quot; data-start=&quot;126&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;겹치는 레이어 무시&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;223&quot; data-start=&quot;139&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;180&quot; data-start=&quot;139&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;체크 시: &lt;b&gt;겹쳐진 레이어 중 가려진 부분은 렌더링에서 제외&lt;/b&gt;됨&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;223&quot; data-start=&quot;181&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;용도: 불필요한 픽셀 연산을 줄이고 &lt;b&gt;최적화된 출력 이미지 생성&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;254&quot; data-start=&quot;225&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Include bounding box&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-end=&quot;266&quot; data-start=&quot;255&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;바운딩 박스 포함&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;355&quot; data-start=&quot;267&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;305&quot; data-start=&quot;267&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;체크 시: &lt;b&gt;레이어의 바운딩 박스를 기준으로 Export&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;355&quot; data-start=&quot;306&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;예: 실제 요소보다 &lt;b&gt;드롭 섀도우 등으로 영역이 넓어진 경우&lt;/b&gt;, 그 영역까지 포함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;399&quot; data-start=&quot;357&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Color profile: sRGB (standard)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;499&quot; data-start=&quot;400&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;422&quot; data-start=&quot;400&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이미지에 색상 프로파일 포함 여부&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;469&quot; data-start=&quot;423&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;sRGB는 &lt;b&gt;웹표준 색상 공간&lt;/b&gt;으로, 일반적인 PNG나 JPG에 적합&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;499&quot; data-start=&quot;470&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;인쇄용은 CMYK, 웹/모바일은 sRGB 권장&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;539&quot; data-start=&quot;501&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Image resampling: Detailed&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;661&quot; data-start=&quot;540&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;564&quot; data-start=&quot;540&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이미지 크기 변경 시 품질 보정 방식&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;615&quot; data-start=&quot;565&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Detailed: 고해상도에서 더 나은 결과를 얻기 위한 고품질 보간 방식 사용&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;661&quot; data-start=&quot;616&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;옵션에 따라 Simple, Detailed, Smooth 등이 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;688&quot; data-start=&quot;663&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Suffix: None&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;765&quot; data-start=&quot;689&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;714&quot; data-start=&quot;689&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Export 되는 파일명에 붙는 접미사&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;753&quot; data-start=&quot;715&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;예: @2x, _web, _dark 등을 설정 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;792&quot; data-start=&quot;772&quot; data-section-id=&quot;sb0hkr&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;  &lt;b&gt;오른쪽 Export 패널&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-end=&quot;820&quot; data-start=&quot;793&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2x / PNG / Export 메인&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;942&quot; data-start=&quot;821&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;860&quot; data-start=&quot;821&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2x: &lt;b&gt;2배 크기로 출력&lt;/b&gt; (고해상도 디스플레이 대응)&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;889&quot; data-start=&quot;861&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;PNG: 투명 배경이 가능한 이미지 형식&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;942&quot; data-start=&quot;890&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Export 메인: 현재 선택된 프레임(이름이 '메인')을 Export하겠다는 의미&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요에 따라 설정값을 바꾸면 다음과 같은 목적에 맞게 Export 가능&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;웹/앱 썸네일&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;PNG, 1x 또는 2x, sRGB, Include bounding box O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;투명 배경 아이콘&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;PNG, Ignore overlapping O, Include bounding box X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;최고 화질 포스터&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;PNG or JPG, 2x 이상, Image resampling = Detailed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT/more</category>
      <category>figma export</category>
      <category>이미지 추출</category>
      <category>피그마</category>
      <category>피그마 이미지 추출</category>
      <author>아랄라랄라</author>
      <guid isPermaLink="true">https://studyhardgogo.tistory.com/370</guid>
      <comments>https://studyhardgogo.tistory.com/370#entry370comment</comments>
      <pubDate>Tue, 29 Jul 2025 09:01:31 +0900</pubDate>
    </item>
  </channel>
</rss>