<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Devjun's Devlog</title>
    <link>https://devjun.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 7 Jun 2026 06:50:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>JunGi Jeong</managingEditor>
    <image>
      <title>Devjun's Devlog</title>
      <url>https://tistory1.daumcdn.net/tistory/3467899/attach/6e8cf8594cf047a6847f13c64dab9270</url>
      <link>https://devjun.tistory.com</link>
    </image>
    <item>
      <title>VSCode 에러, eslint prettier 충돌 에러로 빨간줄 지우기</title>
      <link>https://devjun.tistory.com/552</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드 팩토리님의 Nestjs 강의 진행중 vscode에 빨간줄이 넘친다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;.eslintrc.js에 하기 코드 추가&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724162833484&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rules: {
    'prettier/prettier': [
      'error',
      {
        endOfLine: 'auto'
      }
    ]
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724162888818&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: 'tsconfig.json',
    tsconfigRootDir: __dirname,
    sourceType: 'module',
  },
  plugins: ['@typescript-eslint/eslint-plugin'],
  extends: [
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
  ],
  root: true,
  env: {
    node: true,
    jest: true,
  },
  ignorePatterns: ['.eslintrc.js'],
  rules: {
    'prettier/prettier': [
      'error',
      {
        endOfLine: 'auto'
      }
    ],
    '@typescript-eslint/interface-name-prefix': 'off',
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-explicit-any': 'off',
  },
};&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해결&lt;/span&gt;&lt;/p&gt;</description>
      <category>Programming/Tools</category>
      <author>JunGi Jeong</author>
      <guid isPermaLink="true">https://devjun.tistory.com/552</guid>
      <comments>https://devjun.tistory.com/552#entry552comment</comments>
      <pubDate>Tue, 20 Aug 2024 23:08:15 +0900</pubDate>
    </item>
    <item>
      <title>리눅스 로그 검색</title>
      <link>https://devjun.tistory.com/551</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TARGET이라는 메시지를 검색하고 TARGET을 포함한 50번째 줄까지의 로그를 확인할 수 있는 명령어&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단순 확인용으로 사용시 GREP이 적합한 선택&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1723558362142&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;grep -n &quot;TARGET&quot; sample.log | head -n 1 | cut -d: -f1 | xargs -I {} sed -n '{} , {}+50p' sample.log&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1723558644083&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;grep -n &quot;S6F11&quot; sample.log:

sample.log 파일에서 &quot;S6F11&quot; 문자열이 포함된 줄을 검색합니다.
-n 옵션은 해당 줄 번호를 함께 출력합니다. 출력 형식은 줄번호:내용입니다.
head -n 1:

grep 명령어의 결과에서 첫 번째 줄만 가져옵니다. 이는 &quot;S6F11&quot;이 처음 등장하는 줄입니다.
cut -d: -f1:

head 명령어의 결과에서 줄 번호만 추출합니다. :를 구분자로 사용하여 첫 번째 필드(줄 번호)만 가져옵니다.
xargs -I {} sed -n '{} , {}+50p' sample.log:

xargs -I {}는 앞에서 추출한 줄 번호({})를 sed 명령어의 위치에 대입합니다.
sed -n '{} , {}+50p' sample.log는 {}번 줄부터 {} 줄 이후 50줄까지 출력합니다. {}는 S6F11이 포함된 줄 번호로 대체됩니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723558520055&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;awk '/TARGET/ {found=NR} found &amp;amp;&amp;amp; NR&amp;lt;=found+50' sample.log&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723558699003&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;명령어 분석:
/TARGET/:

awk는 각 줄을 처리할 때 주어진 패턴과 일치하는지 확인합니다.
여기서는 &quot;TARGET&quot;이라는 패턴을 찾고 있습니다. &quot;TARGET&quot;이 포함된 줄을 찾으면 그 줄에 대해 지정된 작업이 수행됩니다.
{found=NR}:

&quot;TARGET&quot;이 포함된 줄이 발견되면, found라는 변수를 현재 줄 번호(NR)로 설정합니다.
NR은 awk의 내장 변수로, 현재 처리 중인 줄 번호를 나타냅니다.
이 단계에서는 &quot;TARGET&quot;이 처음 나타난 줄의 번호를 found에 저장합니다.
found &amp;amp;&amp;amp; NR&amp;lt;=found+50:

이 부분은 조건문으로 작동합니다. 조건이 참일 경우에만 해당 줄을 출력합니다.
found가 설정되어 있는지(found는 0이 아니므로 참), 그리고 현재 줄 번호(NR)가 found 줄 번호부터 50번째 줄 이내인지 확인합니다.
즉, &quot;TARGET&quot;이 포함된 줄부터 시작하여 그 줄 번호에서 50줄을 넘어가지 않는 경우에만 출력됩니다.
sample.log:

awk 명령어의 입력 파일입니다. sample.log 파일을 줄 단위로 처리하면서 &quot;TARGET&quot;이 포함된 줄과 그 이후의 50줄을 출력합니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. &lt;b&gt;Grep&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;특징:&lt;/b&gt; grep은 매우 빠르고 효율적으로 텍스트 파일에서 특정 패턴을 검색하는 데 특화된 도구입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;장점:&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대량의 데이터를 빠르게 처리할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;간단한 패턴 매칭 작업에 매우 적합합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;단점:&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;grep은 텍스트를 검색하고 일치하는 줄을 출력하는 데 주로 사용되며, 이후 특정 줄 수를 출력하는 기능은 직접 지원하지 않습니다. 따라서 패턴 매칭 후 추가적인 텍스트 조작이 필요할 때는 추가 도구(예: xargs, sed)와 함께 사용해야 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;적합한 상황:&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;로그 파일에서 특정 문자열을 빠르게 찾고자 할 때.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단순한 패턴 매칭이 필요할 때.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. &lt;b&gt;Awk&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;특징:&lt;/b&gt; awk는 더 복잡한 텍스트 처리 작업을 지원하는 프로그래밍 언어에 가까운 도구입니다. 패턴 매칭뿐 아니라 다양한 조건과 계산, 필드 조작 등이 가능합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;장점:&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;복잡한 조건 처리와 데이터를 구문 분석할 때 유용합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패턴 매칭 후 후속 작업(예: 줄 출력, 계산)을 바로 수행할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;단점:&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;간단한 작업에서는 오히려 과도할 수 있으며, 복잡한 스크립트를 작성해야 하는 경우도 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다른 도구에 비해 약간 느릴 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;적합한 상황:&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특정 패턴을 찾은 후 추가적인 작업이 필요한 경우(예: 특정 필드만 추출, 특정 조건에 따른 출력).&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;텍스트의 특정 구조를 기반으로 복잡한 처리가 필요할 때.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. &lt;b&gt;Sed&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;특징:&lt;/b&gt; sed는 스트림 편집기(스트림을 읽으면서 처리)로, 텍스트를 일괄적으로 편집하거나 특정 범위의 줄을 추출하는 작업에 적합합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;장점:&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;텍스트 파일의 대규모 편집 작업에 매우 효율적입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;텍스트의 특정 범위를 빠르게 추출할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;단점:&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;awk보다는 덜 직관적일 수 있으며, 복잡한 작업에서는 더 복잡한 명령어를 필요로 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;복잡한 텍스트 처리에는 적합하지 않을 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;적합한 상황:&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특정 줄 범위를 빠르게 추출하거나 텍스트를 대규모로 치환할 때.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;파일 내에서 특정 위치부터 연속된 줄을 출력할 때.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요약&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Grep&lt;/b&gt;: &lt;b&gt;가장 빠르고 간단한 패턴 매칭&lt;/b&gt;이 필요할 때, 긴 로그 파일에서도 효율적으로 작동합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Awk&lt;/b&gt;: &lt;b&gt;복잡한 조건 처리 및 데이터 조작&lt;/b&gt;이 필요한 경우 적합합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Sed&lt;/b&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;긴 로그 파일의 경우&lt;/b&gt;:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단순히 특정 패턴을 찾는 경우 grep이 가장 적합합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특정 패턴 이후의 줄을 출력하거나 복잡한 텍스트 처리 작업이 필요한 경우 awk가 더 적합할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특정 패턴 이후의 &lt;b&gt;정확한 줄 범위&lt;/b&gt;를 추출하고자 한다면 sed도 좋은 선택이 될 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Programming</category>
      <author>JunGi Jeong</author>
      <guid isPermaLink="true">https://devjun.tistory.com/551</guid>
      <comments>https://devjun.tistory.com/551#entry551comment</comments>
      <pubDate>Tue, 13 Aug 2024 23:20:05 +0900</pubDate>
    </item>
    <item>
      <title>연차 관리 캘린더 프로젝트 With ChatGpt #1</title>
      <link>https://devjun.tistory.com/550</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 1. 프로젝트 초기 설정 &lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1718286175271&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx create-react-app leave-management
cd leave-management
npm install react-router-dom tailwindcss postcss autoprefixer&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;상태관리를 위한 react-router-dom과 디자인에 크게 신경쓰지 않기에 tailwindcss를 사용할 예정 (bootstrap 에 익숙하기도 하다)&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; npm audit fix --force&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;프로젝트의 패키지 종속성에서 발견된 보안 취약점을 자동으로 수정하는 명령어이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;보안 강화, 자동화, 최신 버전의 패키지 사용 등의 이점이 있지만&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;호환성 문제 및 불안정성으로 인한 버그, 예상치 못한 변경으로 앱 동작 변경이 야기될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt; 본인은 위 명령어를 사용하지 않을 예정이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>FrontEnd/React</category>
      <author>JunGi Jeong</author>
      <guid isPermaLink="true">https://devjun.tistory.com/550</guid>
      <comments>https://devjun.tistory.com/550#entry550comment</comments>
      <pubDate>Thu, 13 Jun 2024 23:32:23 +0900</pubDate>
    </item>
    <item>
      <title>연차 관리 캘린더 프로젝트 With ChatGpt #0</title>
      <link>https://devjun.tistory.com/549</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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개인적으로 근태 관리 프로그램이 필요하여 리액트로 간단하게 만들어 보려 한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 퇴근 후 만사가 귀찮으니 ChatGpt로 기획안부터 최대한 가이드를 받아 제작해보자.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우선적 목표는 본인이 사용하고자 함이니 사용자와 관리자의 역할을 통합시킨 프로그램을 작성할 예정&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대규모 보다는 소규모 팀에 적합할 것이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하기 문서는 chatgpt로 작성하였으며 일부 수정하여 작성하였다.&lt;/span&gt;&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연차관리 프로그램 기획안(사용자와 관리자의 역할 통합)&lt;/span&gt;&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연차관리 프로그램은 직원들이 연차를 신청하고, 자신의 연차를 관리할 수 있는 시스템입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 모든 사용자는 자신뿐만 아니라 다른 직원들의 연차도 관리할 수 있는 권한을 가집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 이를 통해 작은 팀에서 효율적으로 연차를 관리하고 투명하게 정보를 공유할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 주요 기능&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;공통 기능 (사용자 겸 관리자)&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;연차 신청&lt;/b&gt;: 사용자가 자신의 연차를 신청하고 필요한 세부 정보를 입력할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;연차 조회&lt;/b&gt;: 자신의 연차 잔여 일수 및 사용 내역을 확인할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;연차 승인/거절&lt;/b&gt;: 다른 사용자의 연차 신청을 승인하거나 거절할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;연차 취소&lt;/b&gt;: 승인 대기 중인 연차를 취소할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;통계 및 보고서&lt;/b&gt;: 팀의 연차 사용 현황에 대한 통계 자료 및 보고서를 생성할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;알림 기능&lt;/b&gt;: 연차 신청 및 승인 상태에 대한 알림을 받을 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. 시스템 아키텍처&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;프론트엔드&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;React&lt;/b&gt;: 사용자 인터페이스를 구축하는 데 사용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Redux&lt;/b&gt;: 상태 관리를 위해 사용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;React Router&lt;/b&gt;: 페이지 라우팅을 관리합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;백엔드&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Node.js&lt;/b&gt;: 서버 측 로직을 처리합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Express.js&lt;/b&gt;: API 서버를 구축합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;MongoDB&lt;/b&gt;: 데이터베이스로 사용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인증 및 보안&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;JWT (JSON Web Tokens)&lt;/b&gt;: 인증 및 세션 관리를 위해 사용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;bcrypt&lt;/b&gt;: 비밀번호 암호화를 위해 사용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4. 페이지 구성&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;로그인 페이지&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이메일 및 비밀번호 입력&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;회원 가입 링크 및 비밀번호 재설정 링크&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대시보드&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전체 연차 현황 요약&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;최근 연차 신청 내역&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연차 신청 페이지&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연차 신청 폼 (날짜, 사유 입력)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;신청 버튼&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연차 조회 페이지&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자신의 연차 사용 내역 및 잔여 연차 표시&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연차 신청 상태 (승인 대기, 승인됨, 거절됨)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연차 승인/거절 페이지&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;팀원들의 연차 신청 목록&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;승인 및 거절 버튼&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;통계 및 보고서 페이지&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연차 사용 현황에 대한 통계 자료&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;연차 사용 내역 보고서 생성 기능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5. 개발 일정&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1단계: 요구사항 분석 및 기획 (1주)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요구사항 수집 및 분석&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기획안 작성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2단계: 디자인 및 설계 (2주)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;UI/UX 디자인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터베이스 설계&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;API 설계&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3단계: 프론트엔드 개발 (3주)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;React 컴포넌트 개발&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Redux 상태 관리 구현&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;페이지 라우팅 설정&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4단계: 백엔드 개발 (3주)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Node.js 및 Express.js 서버 구축&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;API 엔드포인트 구현&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;MongoDB 데이터베이스 연동&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5단계: 통합 및 테스트 (2주)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;프론트엔드와 백엔드 통합&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기능별 테스트 및 디버깅&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자 피드백 반영&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;6단계: 배포 및 유지보수 (1주)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서버 배포&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자 교육 및 지원&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;유지보수 및 업데이트 계획 수립&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;6. 결론&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 연차관리 프로그램은 직원들이 자신의 연차를 관리하고, 다른 직원들의 연차도 함께 관리할 수 있도록 설계되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 이를 통해 팀 내에서 연차 사용의 투명성을 높이고, 효율적으로 휴가 계획을 세울 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 철저한 기획과 단계별 개발을 통해 안정적이고 사용자 친화적인 시스템을 구축할 수 있습니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아래 이미지는 Dalle로 생성한 컨셉 이미지이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z8K83/btsHOmAiDWt/4hNQ3pkt2Ker9oTLKaNVMK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z8K83/btsHOmAiDWt/4hNQ3pkt2Ker9oTLKaNVMK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z8K83/btsHOmAiDWt/4hNQ3pkt2Ker9oTLKaNVMK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz8K83%2FbtsHOmAiDWt%2F4hNQ3pkt2Ker9oTLKaNVMK%2Fimg.webp&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;1024&quot; height=&quot;1024&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실제로는 React Calendar 라이브러리를 활용하여 아래 이미지에서 약간의 대시보드 형식을 추가한 느낌이 될 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ASEUV/btsHO3tj2OZ/uJ8QkgTIHaeCgWK2cJjWTK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ASEUV/btsHO3tj2OZ/uJ8QkgTIHaeCgWK2cJjWTK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ASEUV/btsHO3tj2OZ/uJ8QkgTIHaeCgWK2cJjWTK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FASEUV%2FbtsHO3tj2OZ%2FuJ8QkgTIHaeCgWK2cJjWTK%2Fimg.jpg&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;872&quot; height=&quot;796&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;796&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>FrontEnd/React</category>
      <author>JunGi Jeong</author>
      <guid isPermaLink="true">https://devjun.tistory.com/549</guid>
      <comments>https://devjun.tistory.com/549#entry549comment</comments>
      <pubDate>Tue, 4 Jun 2024 22:28:17 +0900</pubDate>
    </item>
    <item>
      <title>리액트 18 버전 정리</title>
      <link>https://devjun.tistory.com/548</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Automatic Batching&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;기존 방식&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2336&quot; data-origin-height=&quot;672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4K24z/btsHIcpMA1m/zMT5PBkvAPigjUkUHY8MWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4K24z/btsHIcpMA1m/zMT5PBkvAPigjUkUHY8MWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4K24z/btsHIcpMA1m/zMT5PBkvAPigjUkUHY8MWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4K24z%2FbtsHIcpMA1m%2FzMT5PBkvAPigjUkUHY8MWK%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;650&quot; height=&quot;187&quot; data-origin-width=&quot;2336&quot; data-origin-height=&quot;672&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Automatic Batching 적용&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1984&quot; data-origin-height=&quot;904&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baenTH/btsHHpcjMRP/oNWNYUenY3X3ielgkynoW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baenTH/btsHHpcjMRP/oNWNYUenY3X3ielgkynoW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baenTH/btsHHpcjMRP/oNWNYUenY3X3ielgkynoW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaenTH%2FbtsHHpcjMRP%2FoNWNYUenY3X3ielgkynoW1%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;650&quot; height=&quot;296&quot; data-origin-width=&quot;1984&quot; data-origin-height=&quot;904&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716989360686&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 기존 버전
setTimeout(() =&amp;gt; {
    setCount((count) =&amp;gt; count + 1);
    setIsFull((isFull) =&amp;gt; !isFull);
    // 각 state의 업데이트 마다 재렌더링이 발생
}, 1000)

// 현재 버전
setTimeout(() =&amp;gt; {
    setCount((count) =&amp;gt; count + 1);
    setIsFull((isFull) =&amp;gt; !isFull);
    // 재렌더링이 마지막에 한 번만 발생 (Automatic Batching)
}, 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Transitions&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;긴급한 업데이트와 긴급하지 않은 업데이트&lt;/b&gt;&lt;/u&gt;&lt;u&gt;를 구분해서 처리하기 위한 개념&lt;/u&gt;&lt;/span&gt;&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;업데이트의 종류&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;긴급한 업데이트&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자와 직접적인 인터랙션이 일어나는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예) 글자 입력, 버튼 클릭 등&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;긴급하지 않은 업데이트&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자와 직접적인 인터랙션이 일어나지 않는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예) 서버로부터 결과를 받아와서 보여주는 경우&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716992879982&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { startTransition } from &quot;react&quot;;

// 긴급 업데이트: 입력한 글자를 화면에 보여주어야 함
setInputValue(input);

// 함수 내에 있는 모든 업데이트는 Transition 업데이트가 됨
startTransition(() =&amp;gt; {
    // Transition 업데이트: 검색 결과를 보여주어야 함
    setSearchQuery(input);
});&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Suspense&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;하위 컴포넌트(children)&lt;/b&gt;가 &lt;b&gt;준비되기 전까지 렌더링을 중단&lt;/b&gt;하는 것&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;웹사이트 규모 &amp;uarr; / 컴포넌트 사이즈 &amp;uarr; / 로딩 시간 &amp;uarr;&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Code Splitting&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Lazy Loading / Dynamic Loading&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1717073232197&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { lazy, Suspense } from &quot;react&quot;;
import LoadingSpinner from './LoadingSpinner';
const OtherComponent = lazy(() =&amp;gt; import('./OtherComponent'));

function MyComponent(props) {
    return (
        &amp;lt;Suspense fallback={LoadingSpinner /&amp;gt;}&amp;gt;
            &amp;lt;OtherComponent /&amp;gt;
        &amp;lt;/Suspense&amp;gt;
    );
}

export default MyComponent;
// OtherComponent가 준비되기 전까지 
// fallback 속성에 들어가있는 LoadingSpinner라는 컴포넌트를 화면에 보여주고
// OtherComponent가 준비되면 그때 OtherComponent를 보여줌&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;클라이언트와 서버 렌더링 API 업데이트&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;리액트 DOM 클라이언트 변경사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;기존방식 (리액트 버전17)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1717077384933&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
    &amp;lt;React.StrictMode&amp;gt;
        &amp;lt;App /&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;,
    document.getElementById('root')
);&lt;/code&gt;&lt;/pre&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;새로운 방식 (리액트 버전 18)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1717077486748&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    &amp;lt;React.StrictMode&amp;gt;
        &amp;lt;App /&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;리액트 DOM 서버&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;renderToPipeableStream&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;NodeJS 환경에서 스트리밍을 위한 함수&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;renderToReadableStream&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Edge runtime 환경(예: Deno, Cloudflare workers)을 위한 함수&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;새로운 Strict 모드 작동 방식&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Strict Mode&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;언마운트(unmount) &lt;/b&gt;시켰다가 다시 한 번 &lt;b&gt;마운트(mount)&lt;/b&gt; 시킴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트 생명주기 함수들이 예상과 다르게 여러번 호출 될 수 있음&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;새롭게 추가된 훅들&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;useId()&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서버와 클라이언트에서 고유한 id값을 생성하기 위한 hook &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;list rendering시 map함수 내에서 반환하는 element key사용 용도는 아님&lt;/p&gt;
&lt;pre id=&quot;code_1717078145900&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useId } from 'react';

function MyComponent() {
  const id = useId();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;label htmlFor={id}&amp;gt;이름:&amp;lt;/label&amp;gt;
      &amp;lt;input id={id} type=&quot;text&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;useTransitions()&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;긴급하지 않은 update를 위한 hook&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717078136092&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState, useTransition } from 'react';

function MyComponent() {
  const [isPending, startTransition] = useTransition();
  const [count, setCount] = useState(0);

  const handleClick = () =&amp;gt; {
    startTransition(() =&amp;gt; {
      setCount(count + 1);
    });
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={handleClick}&amp;gt;카운트 증가&amp;lt;/button&amp;gt;
      {isPending ? &amp;lt;p&amp;gt;업데이트 중...&amp;lt;/p&amp;gt; : &amp;lt;p&amp;gt;카운트: {count}&amp;lt;/p&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;useDeferredValue()&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴급하지 않은 update를 재렌더링 하는것을 연기할 수 있게 해주는 hook&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;짧은 시간에 한 가지 상태의 update가 여러번 발생 했을 경우 최종 상태값만 update하면 됨 &lt;b&gt;(debouncing)&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지연된 렌더링은 중단 가능하며 사용자의 입력을 차단하지 않음&lt;/p&gt;
&lt;pre id=&quot;code_1717078322542&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState, useDeferredValue } from 'react';

function MyComponent() {
  const [text, setText] = useState('');
  const deferredText = useDeferredValue(text);

  const handleChange = (e) =&amp;gt; {
    setText(e.target.value);
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input type=&quot;text&quot; value={text} onChange={handleChange} /&amp;gt;
      &amp;lt;p&amp;gt;입력한 텍스트: {deferredText}&amp;lt;/p&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;useSyncExternalStore()&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 저장소를 구독 할 수 있게 해주는 hook&lt;/p&gt;
&lt;pre id=&quot;code_1717078378007&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useSyncExternalStore } from 'react';

function useMyStore(selector) {
  return useSyncExternalStore(
    myStore.subscribe,
    () =&amp;gt; selector(myStore.getState()),
    () =&amp;gt; selector(myStore.getSnapshot())
  );
}&lt;/code&gt;&lt;/pre&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;useInsertionEffect()&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS-in-JS 라이브러리를 위한 hook&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링 과정에서 스타일 삽입의 성능 문제를 해결 할 수 있게 해줌&lt;/p&gt;
&lt;pre id=&quot;code_1717078414200&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useInsertionEffect } from 'react';

function MyComponent() {
  useInsertionEffect(() =&amp;gt; {
    const style = document.createElement('style');
    style.textContent = `
      .my-class {
        color: red;
      }
    `;
    document.head.appendChild(style);
    return () =&amp;gt; {
      document.head.removeChild(style);
    };
  }, []);

  return &amp;lt;div className=&quot;my-class&quot;&amp;gt;안녕하세요, 세계!&amp;lt;/div&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>FrontEnd/React</category>
      <author>JunGi Jeong</author>
      <guid isPermaLink="true">https://devjun.tistory.com/548</guid>
      <comments>https://devjun.tistory.com/548#entry548comment</comments>
      <pubDate>Wed, 29 May 2024 23:29:34 +0900</pubDate>
    </item>
    <item>
      <title>Mini Project</title>
      <link>https://devjun.tistory.com/547</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;미니 블로그 만들기&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;요구사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글 목록 보기 기능 (리스트 형태)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글 보기 기능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;댓글 보기 기능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글 작성 기능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&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-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;화면 디자인&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r4EjM/btsHwu6K0q9/DAyOKyszNg9FQTKkSMfNlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r4EjM/btsHwu6K0q9/DAyOKyszNg9FQTKkSMfNlk/img.png&quot; data-alt=&quot;피그마 활용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r4EjM/btsHwu6K0q9/DAyOKyszNg9FQTKkSMfNlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr4EjM%2FbtsHwu6K0q9%2FDAyOKyszNg9FQTKkSMfNlk%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;975&quot; height=&quot;490&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;피그마 활용&lt;/figcaption&gt;
&lt;/figure&gt;
&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;프로젝트 생성하기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1716299597940&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx create-react-app mini-blog&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1821&quot; data-origin-height=&quot;921&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQU6UK/btsHwggBvym/bqlXvZ4KNjkkQXEM6KQ7G1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQU6UK/btsHwggBvym/bqlXvZ4KNjkkQXEM6KQ7G1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQU6UK/btsHwggBvym/bqlXvZ4KNjkkQXEM6KQ7G1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQU6UK%2FbtsHwggBvym%2FbqlXvZ4KNjkkQXEM6KQ7G1%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;459&quot; height=&quot;232&quot; data-origin-width=&quot;1821&quot; data-origin-height=&quot;921&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;프로젝트 디렉터리에 들어가서 앱 실행하기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1716299715150&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd mini-blog
npm start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k2ck0/btsHv48xJ6k/ltAGnqaksHp2cU0ZSfQwHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k2ck0/btsHv48xJ6k/ltAGnqaksHp2cU0ZSfQwHk/img.png&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;786&quot; data-is-animation=&quot;false&quot; style=&quot;width: 60.0786%; margin-right: 10px;&quot; data-widthpercent=&quot;60.79&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k2ck0/btsHv48xJ6k/ltAGnqaksHp2cU0ZSfQwHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk2ck0%2FbtsHv48xJ6k%2FltAGnqaksHp2cU0ZSfQwHk%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;1750&quot; height=&quot;786&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nLZKy/btsHxeoOs1M/FCWEhVtFT8ZCa1qPS93rH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nLZKy/btsHxeoOs1M/FCWEhVtFT8ZCa1qPS93rH1/img.png&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;440&quot; data-is-animation=&quot;false&quot; style=&quot;width: 38.7586%;&quot; data-widthpercent=&quot;39.21&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nLZKy/btsHxeoOs1M/FCWEhVtFT8ZCa1qPS93rH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnLZKy%2FbtsHxeoOs1M%2FFCWEhVtFT8ZCa1qPS93rH1%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;632&quot; height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;필요한 패키지 설치&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;react-router-dom v6&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리액트 앱에서 페이지 전환을 위해 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;거의 모든 리액트 앱에 필수&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;styled-components v5&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스타일링 라이브러리&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716300047070&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install --save react-router-dom styled-components&lt;/code&gt;&lt;/pre&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;999&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGOisO/btsHxGZe8np/ai4Kj8MOhBWjySFWjndgHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGOisO/btsHxGZe8np/ai4Kj8MOhBWjySFWjndgHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGOisO/btsHxGZe8np/ai4Kj8MOhBWjySFWjndgHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGOisO%2FbtsHxGZe8np%2Fai4Kj8MOhBWjySFWjndgHk%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;332&quot; height=&quot;299&quot; data-origin-width=&quot;999&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;주요 컴포넌트 및 폴더 구성하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글 목록 보기 기능 (리스트 형태)&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;PostList, PostListItem&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글 보기 기능&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Post&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;댓글 보기 기능&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;CommentList, CommentListItem&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;글 작성 기능&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;PostWrite&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;댓글 작성 기능&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;CommentWrite&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;폴더 구성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;src&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;component&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;list : 리스트와 관련된 Component들을 모아놓은 폴더&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;page : 페이지와 관련된 Component들을 모아놓은 폴더&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;ui : UI Component들을 모아놓은 폴더&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;UI Component 구현하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;필요한 UI Component&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Button Component&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Text Input Component&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Button 컴포넌트 만들기&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ui &amp;gt; Button.jsx&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716545052986&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import styeld from &quot;styled-components&quot;;

const StyledButton = styeld.button`
    padding: 8px 16px;
    font-size: 16px;
    border-widht: 1px;
    border-radius: 8px;
    cursor: pointer;
`;

function Button(props) {
    const { title, onClick } = props;

    return &amp;lt;StyledButton onClick={onClick}&amp;gt;{title || &quot;button&quot;}&amp;lt;/StyledButton&amp;gt;
}

export default Button;&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;TextInput 컴포넌트 만들기&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;ui &amp;gt; TextInput.jsx&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716545299906&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import styeld from &quot;styled-components&quot;;

const StyledTextArea = styeld.textarea`
    width: calc(100% - 32px);
    ${(props) =&amp;gt;
        props.height &amp;amp;&amp;amp;
        `
        height: ${props.height}px;
    `}
    padding: 16px;
    font-size: 16px;
    line-height: 20px;
`;

function TextInput(props) {
    const { height, value, onChange } = props;

    return &amp;lt;StyledTextArea height={height} value={value} onChange={onChange} /&amp;gt;;
}

export default TextInput;&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;List 컴포넌트 구현하기&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;PostListItem 컴포넌트 만들기&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;list &amp;gt; PostListItem.jsx&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716545413377&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import styled from &quot;styled-components&quot;;

const Wrapper = styled.div`
    width: calc(100% - 32px);
    padding: 16px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    border: 1px solid grey;
    border-radius: 8px;
    cursor: pointer;
    background: white;
    :hover {
        background: lightgrey;
    }
`;

const TitleText = styled.p`
    font-size: 20px;
    font-weight: 500;
`;

function PostListItem(props) {
    const { post, onClick } = props;

    return (
        &amp;lt;Wrapper onClick={onClick}&amp;gt;
            &amp;lt;TitleText&amp;gt;{post.title}&amp;lt;/TitleText&amp;gt;
        &amp;lt;/Wrapper&amp;gt;
    );
}

export default PostListItem;&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; &lt;b&gt;PostList 컴포넌트 만들기&lt;/b&gt; &lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;list &amp;gt; PostList.jsx&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716545507204&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import styled from 'styled-components';
import PostListItem from './PostListItem';

const Wrapper = styled.div`
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;

    :not(:last-child) {
        margin-bottom: 16px;
    }
`;

function PostList(props) {
    const { posts, onClickItem } = props;

    return (
        &amp;lt;Wrapper&amp;gt;
            {posts.map((post, index) =&amp;gt; {
                return (
                    &amp;lt;PostListItem
                        key={post.id}
                        post={post}
                        onClick={() =&amp;gt; {
                            onClickItem(post);
                        }}
                    /&amp;gt;
                );
            })}
        &amp;lt;/Wrapper&amp;gt;
    );
}

export default PostList;&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;CommentListItem 컴포넌트 만들기&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;ui &amp;gt; CommentListItem&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716545623954&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import styled from &quot;styled-components&quot;;

const Wrapper = styled.div`
    width: calc(100% - 32px);
    padding: 8px 16px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    border: 1px solid grey;
    border-radius: 8px;
    cursor: pointer;
    background: white;
    :hover {
        background: lightgrey;
    }
`;

const ContentText = styled.p`
    font-size: 16px;
    white-space: pre-wrap;
`;

function CommentListItem(props) {
    const { comment } = props;

    return (
        &amp;lt;Wrapper&amp;gt;
            &amp;lt;ContentText&amp;gt;{comment.content}&amp;lt;/ContentText&amp;gt;
        &amp;lt;/Wrapper&amp;gt;
    );
}

export default CommentListItem;&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;CommentList 컴포넌트 만들기&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;list &amp;gt; CommentList.jsx&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716545665078&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import styled from 'styled-components';
import CommentListItem from './CommentListItem';

const Wrapper = styled.div`
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;

    :not(:last-child) {
        margin-bottom: 16px;
    }
`;

function CommentList(props) {
    const { comments } = props;

    return (
        &amp;lt;Wrapper&amp;gt;
            {comments.map((comment, index) =&amp;gt; {
                return (
                    &amp;lt;CommentListItem
                        key={comment.id}
                        comment={comment}
                    /&amp;gt;
                );
            })}
        &amp;lt;/Wrapper&amp;gt;
    );
}

export default CommentList;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;더미 데이터 만들기&lt;/b&gt;&lt;/h3&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;b&gt;src &amp;gt; data.json&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://raw.githubusercontent.com/soaple/mini-blog/master/src/data.json&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://raw.githubusercontent.com/soaple/mini-blog/master/src/data.json&lt;/a&gt;&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;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Page 컴포넌트 구현하기&lt;/b&gt;&lt;/h3&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;MainPage 만들기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;page &amp;gt; MainPage.jsx&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716548271309&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import PostList from '../list/PostList';
import Button from '../ui/Button';
import data from '../../data.json';

const Wrapper = styled.div`
    padding: 16px;
    width: calc(100% - 32px);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
`;

const Container = styled.div`
    width: 100%;
    max-width: 720px;

    :not(:last-child) {
        margin-bottom: 16px;
    }
`;

function MainPage(props) {
    const navigate = useNavigate();

    return (
        &amp;lt;Wrapper&amp;gt;
            &amp;lt;Container&amp;gt;
                &amp;lt;Button
                    title='글 작성하기'
                    onClick={() =&amp;gt; {
                        navigate('/post-write');
                    }}
                /&amp;gt;

                &amp;lt;PostList
                    posts={data}
                    onClickItem={(item) =&amp;gt; {
                        navigate(`/post/${item.id}`);
                    }}
                /&amp;gt;
            &amp;lt;/Container&amp;gt;
        &amp;lt;/Wrapper&amp;gt;
    );
}

export default MainPage;&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;PostWritePage 만들기&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;page &amp;gt; PostWritePage.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1716548354516&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import TextInput from '../ui/TextInput';
import Button from '../ui/Button';

const Wrapper = styled.div`
    padding: 16px;
    width: calc(100% - 32px);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
`;

const Container = styled.div`
    width: 100%;
    max-width: 720px;

    :not(:last-child) {
        margin-bottom: 16px;
    }
`;

function PostWritePage(props) {
    const navigate = useNavigate();

    const [title, setTitle] = useState('');
    const [content, setContent] = useState('');

    return (
        &amp;lt;Wrapper&amp;gt;
            &amp;lt;Container&amp;gt;
                &amp;lt;TextInput
                    height={20}
                    value={title}
                    onChange={(event) =&amp;gt; {
                        setTitle(event.target.value);
                    }}
                /&amp;gt;

                &amp;lt;TextInput
                    height={480}
                    value={content}
                    onChange={(event) =&amp;gt; {
                        setContent(event.target.value);
                    }}
                /&amp;gt;

                &amp;lt;Button
                    title='글 작성하기'
                    onClick={() =&amp;gt; {
                        navigate('/');
                    }}
                /&amp;gt;
            &amp;lt;/Container&amp;gt;
        &amp;lt;/Wrapper&amp;gt;
    );
}

export default PostWritePage;&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;PostViewPage 만들기&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;page &amp;gt; PostViewPage.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1716548385625&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import styled from 'styled-components';
import CommentList from '../list/CommentList';
import TextInput from '../ui/TextInput';
import Button from '../ui/Button';
import data from '../../data.json';

const Wrapper = styled.div`
    padding: 16px;
    width: calc(100% - 32px);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
`;

const Container = styled.div`
    width: 100%;
    max-width: 720px;

    :not(:last-child) {
        margin-bottom: 16px;
    }
`;

const PostContainer = styled.div`
    padding: 8px 16px;
    border: 1px solid grey;
    border-radius: 8px;
`;

const TitleText = styled.p`
    font-size: 28px;
    font-weight: 500;
`;

const ContentText = styled.p`
    font-size: 20px;
    line-height: 32px;
    white-space: pre-wrap;
`;

const CommentLabel = styled.p`
    font-size: 16px;
    font-weight: 500;
`;

function PostViewPage(props) {
    const navigate = useNavigate();
    const { postId } = useParams();

    const post = data.find((item) =&amp;gt; {
        return item.id == postId;
    });

    const [comment, setComment] = useState('');

    return (
        &amp;lt;Wrapper&amp;gt;
            &amp;lt;Container&amp;gt;
                &amp;lt;Button
                    title='뒤로 가기'
                    onClick={() =&amp;gt; {
                        navigate('/');
                    }}
                /&amp;gt;
                &amp;lt;PostContainer&amp;gt;
                    &amp;lt;TitleText&amp;gt;{post.title}&amp;lt;/TitleText&amp;gt;
                    &amp;lt;ContentText&amp;gt;{post.content}&amp;lt;/ContentText&amp;gt;
                &amp;lt;/PostContainer&amp;gt;

                &amp;lt;CommentLabel&amp;gt;댓글&amp;lt;/CommentLabel&amp;gt;
                &amp;lt;CommentList comments={post.comments} /&amp;gt;

                &amp;lt;TextInput
                    height={40}
                    value={comment}
                    onChange={(event) =&amp;gt; {
                        setComment(event.target.value);
                    }}
                /&amp;gt;
                &amp;lt;Button
                    title='댓글 작성하기'
                    onClick={() =&amp;gt; {
                        navigate('/');
                    }}
                /&amp;gt;
            &amp;lt;/Container&amp;gt;
        &amp;lt;/Wrapper&amp;gt;
    );
}

export default PostViewPage;&lt;/code&gt;&lt;/pre&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;각 페이지별 경고 구성하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;react-router-dom를 이용한 라우팅 구성 예시&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716548577521&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;BrowserRouter&amp;gt;
    &amp;lt;Routes&amp;gt;
    	&amp;lt;Route index element={&amp;lt;Mainpage /&amp;gt;} /&amp;gt;
        &amp;lt;Route path=&quot;places&quot; element={&amp;lt;PlacePage /&amp;gt;} /&amp;gt;
        &amp;lt;Route path=&quot;games&quot; element={&amp;lt;GamePage /&amp;gt;} /&amp;gt;
    &amp;lt;/Routes&amp;gt;
&amp;lt;/BrowserRouter&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;useNavigate()&lt;/p&gt;
&lt;pre id=&quot;code_1716548688576&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function SampleNavigate(props) {
    const navigate = useNavigate();
    
    const moveToMain = () =&amp;gt; {
    	navigate(&quot;/&quot;);
    }
    
    return (
    	...
    );
}&lt;/code&gt;&lt;/pre&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;App.js 파일 수정하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1716548872350&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import {
    BrowserRouter,
    Routes,
    Route
} from &quot;react-router-dom&quot;;
import styled from &quot;styled-components&quot;;
// Pages
import MainPage from './component/page/MainPage';
import PostWritePage from './component/page/PostWritePage';
import PostViewPage from './component/page/PostViewPage';

const MainTitleText = styled.p`
    font-size: 24px;
    font-weight: bold;
    text-align: center;
`;

function App(props) {
    return (
        &amp;lt;BrowserRouter&amp;gt;
            &amp;lt;MainTitleText&amp;gt;소플의 미니 블로그&amp;lt;/MainTitleText&amp;gt;
            &amp;lt;Routes&amp;gt;
                &amp;lt;Route index element={&amp;lt;MainPage /&amp;gt;} /&amp;gt;
                &amp;lt;Route path=&quot;post-write&quot; element={&amp;lt;PostWritePage /&amp;gt;} /&amp;gt;
                &amp;lt;Route path=&quot;post/:postId&quot; element={&amp;lt;PostViewPage /&amp;gt;} /&amp;gt;
            &amp;lt;/Routes&amp;gt;
        &amp;lt;/BrowserRouter&amp;gt;
    );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716548891097&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd mini-blog
npm start&lt;/code&gt;&lt;/pre&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;Production 빌드하기&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;코드와 애플리케이션이 사용하는 이미지, CSS 파일 등의 파일을 모두 모아서 패키징 하는 과정&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;pre id=&quot;code_1716548963777&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run build&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;b&gt;serve 설치하기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716549006624&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install -g serve&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;b&gt;serve 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716549042356&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;serve -s build&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;References&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716298485248&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[지금 무료] 처음 만난 리액트(React) | Inje Lee (소플) - 인프런&quot; data-og-description=&quot;Inje Lee (소플) | 자바스크립트와 CSS 기초 문법과 함께 리액트의 기초를 탄탄하게 다질 수 있습니다., 깔끔한 강의자료, 꼼꼼한 설명으로쉽게 배우는 리액트 강의입니다.  &amp;zwj;  리액트의 세계로&quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; data-og-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cCVyUu/hyV6cqsAJx/JQHKCWinVqAu4JwqVXxIq1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/daaXXf/hyV6hL3gM3/AsJggQaGVRZ8GUEFUQyVf1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/j5Fpy/hyV9VUTkB4/ZKDGMcL1eIClEmqRnaUer1/img.png?width=958&amp;amp;height=717&amp;amp;face=145_56_607_490&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cCVyUu/hyV6cqsAJx/JQHKCWinVqAu4JwqVXxIq1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/daaXXf/hyV6hL3gM3/AsJggQaGVRZ8GUEFUQyVf1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/j5Fpy/hyV9VUTkB4/ZKDGMcL1eIClEmqRnaUer1/img.png?width=958&amp;amp;height=717&amp;amp;face=145_56_607_490');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[지금 무료] 처음 만난 리액트(React) | Inje Lee (소플) - 인프런&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Inje Lee (소플) | 자바스크립트와 CSS 기초 문법과 함께 리액트의 기초를 탄탄하게 다질 수 있습니다., 깔끔한 강의자료, 꼼꼼한 설명으로쉽게 배우는 리액트 강의입니다.  &amp;zwj;  리액트의 세계로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://github.com/soaple/mini-blog&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/soaple/mini-blog&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716298390114&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - soaple/mini-blog: 소플의 처음 만난 리액트 실습 프로젝트&quot; data-og-description=&quot;소플의 처음 만난 리액트 실습 프로젝트. Contribute to soaple/mini-blog development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/soaple/mini-blog&quot; data-og-url=&quot;https://github.com/soaple/mini-blog&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/beGmmm/hyV91HAW1Q/MUmjnSgbtPWzjUtbdDJ0k1/img.png?width=1200&amp;amp;height=600&amp;amp;face=995_138_1038_184&quot;&gt;&lt;a href=&quot;https://github.com/soaple/mini-blog&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/soaple/mini-blog&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/beGmmm/hyV91HAW1Q/MUmjnSgbtPWzjUtbdDJ0k1/img.png?width=1200&amp;amp;height=600&amp;amp;face=995_138_1038_184');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - soaple/mini-blog: 소플의 처음 만난 리액트 실습 프로젝트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소플의 처음 만난 리액트 실습 프로젝트. Contribute to soaple/mini-blog development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://reactrouter.com/&quot;&gt;https://reactrouter.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716548708815&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Home v6.23.1 | React Router&quot; data-og-description=&quot;&quot; data-og-host=&quot;reactrouter.com&quot; data-og-source-url=&quot;https://reactrouter.com/&quot; data-og-url=&quot;https://reactrouter.com/en/main&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fOwKP/hyV9TQ8lid/OJCXtCDuE3tsfjG65USCb0/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://reactrouter.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://reactrouter.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fOwKP/hyV9TQ8lid/OJCXtCDuE3tsfjG65USCb0/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Home v6.23.1 | React Router&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;reactrouter.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>FrontEnd/React</category>
      <author>JunGi Jeong</author>
      <guid isPermaLink="true">https://devjun.tistory.com/547</guid>
      <comments>https://devjun.tistory.com/547#entry547comment</comments>
      <pubDate>Tue, 21 May 2024 23:03:41 +0900</pubDate>
    </item>
    <item>
      <title>Styling</title>
      <link>https://devjun.tistory.com/546</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;CSS와 selector&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Cascading Style Sheets&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;웹페이지의 디자인, 레이아웃 및 스타일을 정의하기 위한 언어&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1715608611142&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;h1 { color: green; font-size: 16px; }

h1 : Selector(선택자)
color, font-size : property(속성)
green, 16px : Value(값)

color: green; / font-size: 16px; =&amp;gt; Declaration(선언)&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Selector의 유형&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 221px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 8.33335%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;유형&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 8.33335%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Element&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ID&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Class&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Universal&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Grouping&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 102px;&quot;&gt;
&lt;td style=&quot;width: 8.33335%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 8.33335%; height: 102px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;h1 { color: green; }&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 102px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;div id=&quot;section&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 102px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;span class=&quot;medium&quot;&amp;gt; ...&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;p class=&quot;medium&quot;&amp;gt; ...&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 102px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* {&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;font-size: 20px;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;color: blue;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 102px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; h1, h2, p {&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;color:black;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;text-align: center;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;}&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 102px;&quot;&gt;
&lt;td style=&quot;width: 8.33335%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 8.33335%; height: 102px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 102px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;#section {&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;background-color: black;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 102px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;.medium {&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;font-size: 20px;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;p.medium {&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;font-size: 20px;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 102px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 16.6667%; height: 102px;&quot;&gt;&lt;br /&gt;&lt;br /&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; Element의 상태와 관련된 selector&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;:hover&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마우스 커서가 element 위에 올라왔을 때&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;:active&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주로 &amp;lt;a&amp;gt; 태그(link)에 사용, element가 클릭됐을 때를 의미&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;:focus&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주로 &amp;lt;input&amp;gt; 태그에 사용, element가 초점을 갖고 있을 경우&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;:checked&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;radio button이나 checkbox 같은 유형의 &amp;lt;input&amp;gt; 태그가 체크되어 있는 경우&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;:first-child, :last-child&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;상위 element를 기준으로 각각 첫 번째 child, 마지막 child일 경우를 의미&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;레이아웃과 관련된 CSS 속성&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;레이아웃 : 구성 요소의 배치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;웹 화면에 요소들을 어떻게 배치할 것인가.&lt;/span&gt;&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;display 속성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1715609384454&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;div {
	display: none | block | inline | flex;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;display: none;&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;element를 화면에서 숨기기 위해 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;script&amp;gt; 태그의 display 속성 기본값은 display: none;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;display: block;&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;블록 단위로 element를 배치.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;p&amp;gt;, &amp;lt;div&amp;gt;, &amp;lt;h1&amp;gt;~&amp;lt;h6&amp;gt; 태그의 display 속성 기본값이 display: block;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;display: inline;&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;element를 라인 안에 넣는 것.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;span&amp;gt; 태그의 display 속성 기본값이 display: inline;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;display: flex;&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;element를 블록 레벨의 flex container로 표시.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;container이기 때문에 내부에 다른 element들을 포함.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;visibility 속성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1715609686979&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;div {
	visibility: visible | hidden;
}&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;visibility속성의 대표적인 값들&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;visibility: visible;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;element를 화면에 보이게 하는 것&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;visibility: hidden;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;화면에서 안 보이게 감추는 것&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;element를 안 보이게만 하는 것이고, &lt;b&gt;화면에서의 영역은 그대로 차지.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;position 속성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1715609787196&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;div {
	position: static | fixed | relative | absolute;
}&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;position속성의 대표적인 값들&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;static
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본값으로 element를 원래의 순서대로 위치시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;fixed
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;element를 브라우저 window에 상대적으로 위치시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;relative
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;element를 보통의 위치에 상대적으로 위치시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;absolute
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;element를 절대 위치에 위치시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;가로, 세로 길이와 관련된 속성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1715613403046&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;div {
    width: auto | value;
    height: auto | value;
    min-width: auto | value;
    min-height: auto | value;
    max-width: auto | value;
    max-height: auto | value;
}&lt;/code&gt;&lt;/pre&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;FlexBox&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIB8WP/btsHnkX1kl3/pmx4CsDHmNS9ylNLT4ZwYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIB8WP/btsHnkX1kl3/pmx4CsDHmNS9ylNLT4ZwYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIB8WP/btsHnkX1kl3/pmx4CsDHmNS9ylNLT4ZwYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIB8WP%2FbtsHnkX1kl3%2Fpmx4CsDHmNS9ylNLT4ZwYk%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;378&quot; height=&quot;185&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;185&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1715613514505&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;div {
    display: flex;
    flex-direction: row | column | row-reverse | column-reverse;
    align-items: stretch | flex-start | center | flex-end | baseline;
    justify-content: flex-start | center | flex-end | space-between | space-around;
}&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;FlexBox이해를 돕기 위한 사이트 &lt;s&gt;(개구리 옮기다 보면 이해 됨)&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://flexboxfroggy.com/#ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://flexboxfroggy.com/#ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715613942280&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Flexbox Froggy&quot; data-og-description=&quot;A game for learning CSS flexbox&quot; data-og-host=&quot;flexboxfroggy.com&quot; data-og-source-url=&quot;https://flexboxfroggy.com/#ko&quot; data-og-url=&quot;https://flexboxfroggy.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/to41K/hyV5620H8e/ryYzcMKFay6T01VQZj6Uk0/img.png?width=2214&amp;amp;height=1142&amp;amp;face=0_0_2214_1142,https://scrap.kakaocdn.net/dn/zKtYz/hyV6bwtgu2/DaQSfFpjYu6jOcJheVr4BK/img.png?width=2214&amp;amp;height=1142&amp;amp;face=0_0_2214_1142&quot;&gt;&lt;a href=&quot;https://flexboxfroggy.com/#ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://flexboxfroggy.com/#ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/to41K/hyV5620H8e/ryYzcMKFay6T01VQZj6Uk0/img.png?width=2214&amp;amp;height=1142&amp;amp;face=0_0_2214_1142,https://scrap.kakaocdn.net/dn/zKtYz/hyV6bwtgu2/DaQSfFpjYu6jOcJheVr4BK/img.png?width=2214&amp;amp;height=1142&amp;amp;face=0_0_2214_1142');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Flexbox Froggy&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A game for learning CSS flexbox&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;flexboxfroggy.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Font와 관련된 CSS 속성, 기타 많이 사용하는 CSS 속성&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1715868754018&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#title {
    font-family: &quot;사용할 글꼴 이름&quot;, &amp;lt;일반적인 글꼴 분류&amp;gt;;
    font-size: value;
    font-weight: normal | bold;
    font-style: normal | italic | oblique;
}

// font-family (글꼴)
#title1 {
    font-family: &quot;Times New Roman&quot;, Times, serif;
    // 순서대로 해당 폰트가 없을 시에 대비한 폰트, 뒤로 갈수록 일반적
}

// font-size (크기)
px(pixel), em, rem, vw(viewport width)
16 * em = pixels
#title1 {
    font-size: 16px;
    font-size: 1em;
    font-size: 10vw; /* viewport 가로 길이의 10%를 의미 */
}

// font-weight (두께)
#title1 {
    font-weight: bold;
    font-weight: 500;
}

// font-style (모양)
#title1 {
    font-style: italic;
    font-style: oblique;
}

// 기타
div {
    background-color: color | transparent;
    border: border-width border-style border-color;
}&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;styled-components&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;React와 React Native 애플리케이션에서 스타일링을 쉽게 할 수 있도록 도와주는 라이브러리입니다.&lt;br /&gt;이 라이브러리는 CSS를 JavaScript로 작성할 수 있게 해주며, 컴포넌트 기반 개발 패턴과 잘 어울립니다.&lt;/blockquote&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;설치방법&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1716298221837&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#npm 사용
npm install --save styled-components
// 만약 cannot read properties of null (reading 'usecontext') 에러 발생 시
// npm uninstall styled-components 후
// npm install styled-components@5.3.10 등 최신버전으로 재설치 요망
// 본인이 겪었음...

# yarn 사용
yarn add styled-components&lt;/code&gt;&lt;/pre&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;예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1716216028791&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import styled from 'styled-components';


const Wrapper = styled.div`
    padding: 1em;
    background: grey
`;

const Title = styled.h1`
    font-size: 1.5em;
    color: white;
    text-align: center;
`

function Mainpage(props) {
    return (
        &amp;lt;Wrapper&amp;gt;
            &amp;lt;Title&amp;gt;
                안녕, 리액트!
            &amp;lt;/Title&amp;gt;
        &amp;lt;/Wrapper&amp;gt;
    )
}

export default Mainpage;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;기본 사용법&lt;/b&gt;&lt;/h3&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;b&gt;Tagged Template Literals&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;literal : 소스 코드의 고정된 값 / let number = 20; (20 ==&amp;gt; literal)&lt;br /&gt;styled-components는 ES6의 템플릿 리터럴(tagged template literals)을 사용하여 스타일을 정의합니다.&lt;br /&gt;이는 CSS를 직접 자바스크립트 파일 안에 작성할 수 있게 해줍니다.&lt;/blockquote&gt;
&lt;pre id=&quot;code_1716216104635&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import styled from 'styled-components';

const Button = styled.button`
  background: palevioletred;
  color: white;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;&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 사용&lt;/p&gt;
&lt;pre id=&quot;code_1716219382784&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import styled from &quot;styled-components&quot;;

const Button = styled.button`
  background: ${props =&amp;gt; props.primary ? 'palevioletred' : 'white'};
  color: ${props =&amp;gt; props.primary ? 'white' : 'palevioletred'};
`;

function Sample(props) {
	return (
    	&amp;lt;div&amp;gt;
            &amp;lt;Button&amp;gt;Normal&amp;lt;/Button&amp;gt;
            &amp;lt;Button dark&amp;gt;Dark&amp;lt;/Button&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}

export default Sample;&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;styled-components의 스타일 확장&lt;/p&gt;
&lt;pre id=&quot;code_1716219666574&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 기본 버튼 컴포넌트 정의
import styled from 'styled-components';

const Button = styled.button`
  background: palevioletred;
  color: white;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;

export default Button;

// 2. 기본 버튼 컴포넌트를 확장

import styled from 'styled-components';
import Button from './Button';

const LargeButton = styled(Button)`
  font-size: 1.5em;
  padding: 0.5em 1.5em;
`;

const PrimaryButton = styled(Button)`
  background: blue;
  border: 2px solid blue;
`;

export { LargeButton, PrimaryButton };

// 3. 확장된 컴포넌트 사용

import React from 'react';
import Button from './Button';
import { LargeButton, PrimaryButton } from './ExtendedButtons';

const App = () =&amp;gt; (
  &amp;lt;div&amp;gt;
    &amp;lt;Button&amp;gt;Default Button&amp;lt;/Button&amp;gt;
    &amp;lt;LargeButton&amp;gt;Large Button&amp;lt;/LargeButton&amp;gt;
    &amp;lt;PrimaryButton&amp;gt;Primary Button&amp;lt;/PrimaryButton&amp;gt;
  &amp;lt;/div&amp;gt;
);

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716298472614&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[지금 무료] 처음 만난 리액트(React) | Inje Lee (소플) - 인프런&quot; data-og-description=&quot;Inje Lee (소플) | 자바스크립트와 CSS 기초 문법과 함께 리액트의 기초를 탄탄하게 다질 수 있습니다., 깔끔한 강의자료, 꼼꼼한 설명으로쉽게 배우는 리액트 강의입니다.  &amp;zwj;  리액트의 세계로&quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; data-og-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cCVyUu/hyV6cqsAJx/JQHKCWinVqAu4JwqVXxIq1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/daaXXf/hyV6hL3gM3/AsJggQaGVRZ8GUEFUQyVf1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/j5Fpy/hyV9VUTkB4/ZKDGMcL1eIClEmqRnaUer1/img.png?width=958&amp;amp;height=717&amp;amp;face=145_56_607_490&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cCVyUu/hyV6cqsAJx/JQHKCWinVqAu4JwqVXxIq1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/daaXXf/hyV6hL3gM3/AsJggQaGVRZ8GUEFUQyVf1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/j5Fpy/hyV9VUTkB4/ZKDGMcL1eIClEmqRnaUer1/img.png?width=958&amp;amp;height=717&amp;amp;face=145_56_607_490');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[지금 무료] 처음 만난 리액트(React) | Inje Lee (소플) - 인프런&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Inje Lee (소플) | 자바스크립트와 CSS 기초 문법과 함께 리액트의 기초를 탄탄하게 다질 수 있습니다., 깔끔한 강의자료, 꼼꼼한 설명으로쉽게 배우는 리액트 강의입니다.  &amp;zwj;  리액트의 세계로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/css/css_selectors.asp&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.w3schools.com/css/css_selectors.asp&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715609224584&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;CSS Selectors&quot; data-og-description=&quot;W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.&quot; data-og-host=&quot;www.w3schools.com&quot; data-og-source-url=&quot;https://www.w3schools.com/css/css_selectors.asp&quot; data-og-url=&quot;https://www.w3schools.com/css/css_selectors.asp&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bDvzSd/hyV2qB0Lqf/coHHZt5j5bkd22TRb5unp1/img.png?width=436&amp;amp;height=228&amp;amp;face=0_0_436_228,https://scrap.kakaocdn.net/dn/rRIiu/hyV2vDgEtU/vpNfkDrGO3MPJzH79Ehci1/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/bvnmiu/hyV6biRlpG/mCCWpQvuQgQvN5V6KjoFN0/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/css/css_selectors.asp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.w3schools.com/css/css_selectors.asp&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bDvzSd/hyV2qB0Lqf/coHHZt5j5bkd22TRb5unp1/img.png?width=436&amp;amp;height=228&amp;amp;face=0_0_436_228,https://scrap.kakaocdn.net/dn/rRIiu/hyV2vDgEtU/vpNfkDrGO3MPJzH79Ehci1/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/bvnmiu/hyV6biRlpG/mCCWpQvuQgQvN5V6KjoFN0/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CSS Selectors&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.w3schools.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/cssref/css_selectors.php&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.w3schools.com/cssref/css_selectors.php&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715609247325&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;CSS Selectors Reference&quot; data-og-description=&quot;W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.&quot; data-og-host=&quot;www.w3schools.com&quot; data-og-source-url=&quot;https://www.w3schools.com/cssref/css_selectors.php&quot; data-og-url=&quot;https://www.w3schools.com/cssref/css_selectors.php&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bfYpVj/hyV2zeIdWt/AVOmKl2ygy9TrxyYjqSuNK/img.png?width=436&amp;amp;height=228&amp;amp;face=0_0_436_228,https://scrap.kakaocdn.net/dn/zSwmg/hyV2wWykHs/MHmpc1DhMlHhv1t7qtfvJK/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/cssref/css_selectors.php&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.w3schools.com/cssref/css_selectors.php&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bfYpVj/hyV2zeIdWt/AVOmKl2ygy9TrxyYjqSuNK/img.png?width=436&amp;amp;height=228&amp;amp;face=0_0_436_228,https://scrap.kakaocdn.net/dn/zSwmg/hyV2wWykHs/MHmpc1DhMlHhv1t7qtfvJK/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CSS Selectors Reference&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.w3schools.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://flexboxfroggy.com/#ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://flexboxfroggy.com/#ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715613816838&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Flexbox Froggy&quot; data-og-description=&quot;A game for learning CSS flexbox&quot; data-og-host=&quot;flexboxfroggy.com&quot; data-og-source-url=&quot;https://flexboxfroggy.com/#ko&quot; data-og-url=&quot;https://flexboxfroggy.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/to41K/hyV5620H8e/ryYzcMKFay6T01VQZj6Uk0/img.png?width=2214&amp;amp;height=1142&amp;amp;face=0_0_2214_1142,https://scrap.kakaocdn.net/dn/zKtYz/hyV6bwtgu2/DaQSfFpjYu6jOcJheVr4BK/img.png?width=2214&amp;amp;height=1142&amp;amp;face=0_0_2214_1142&quot;&gt;&lt;a href=&quot;https://flexboxfroggy.com/#ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://flexboxfroggy.com/#ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/to41K/hyV5620H8e/ryYzcMKFay6T01VQZj6Uk0/img.png?width=2214&amp;amp;height=1142&amp;amp;face=0_0_2214_1142,https://scrap.kakaocdn.net/dn/zKtYz/hyV6bwtgu2/DaQSfFpjYu6jOcJheVr4BK/img.png?width=2214&amp;amp;height=1142&amp;amp;face=0_0_2214_1142');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Flexbox Froggy&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A game for learning CSS flexbox&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;flexboxfroggy.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/csSref/index.php&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.w3schools.com/csSref/index.php&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715869280795&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;CSS Reference&quot; data-og-description=&quot;W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.&quot; data-og-host=&quot;www.w3schools.com&quot; data-og-source-url=&quot;https://www.w3schools.com/csSref/index.php&quot; data-og-url=&quot;https://www.w3schools.com/csSref/index.php&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cOrsQb/hyV6akDOnt/kjv2oPjLmFUvoC7tsZEvk1/img.png?width=436&amp;amp;height=228&amp;amp;face=0_0_436_228,https://scrap.kakaocdn.net/dn/jgNnk/hyV57g98fu/CJIyjN5VrmguYv9n5H33gk/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/csSref/index.php&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.w3schools.com/csSref/index.php&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cOrsQb/hyV6akDOnt/kjv2oPjLmFUvoC7tsZEvk1/img.png?width=436&amp;amp;height=228&amp;amp;face=0_0_436_228,https://scrap.kakaocdn.net/dn/jgNnk/hyV57g98fu/CJIyjN5VrmguYv9n5H33gk/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CSS Reference&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.w3schools.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/web/javascript/reference/template_literals&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.mozilla.org/en-US/docs/web/javascript/reference/template_literals&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716219322833&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Template literals (Template strings) - JavaScript | MDN&quot; data-og-description=&quot;Template literals are literals delimited with backtick (&amp;#96;) characters, allowing for multi-line strings, string interpolation with embedded expressions, and special constructs called tagged templates.&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/en-US/docs/web/javascript/reference/template_literals&quot; data-og-url=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bYZt0e/hyV6iRBbwJ/SUVKXKKB7Uj3EAGOnGpFBK/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/web/javascript/reference/template_literals&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/en-US/docs/web/javascript/reference/template_literals&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bYZt0e/hyV6iRBbwJ/SUVKXKKB7Uj3EAGOnGpFBK/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Template literals (Template strings) - JavaScript | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Template literals are literals delimited with backtick (`) characters, allowing for multi-line strings, string interpolation with embedded expressions, and special constructs called tagged templates.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://styled-components.com/docs&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://styled-components.com/docs&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716219697846&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;styled-components: Documentation&quot; data-og-description=&quot;Learn how to use styled-components and to style your apps without stress&quot; data-og-host=&quot;styled-components.com&quot; data-og-source-url=&quot;https://styled-components.com/docs&quot; data-og-url=&quot;https://styled-components.com/docs&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xcUF5/hyV6c4TH4h/tkFi45VyBK81EkObUUSmBk/img.png?width=652&amp;amp;height=652&amp;amp;face=0_0_652_652,https://scrap.kakaocdn.net/dn/X2FFC/hyV9SwVW1j/EpQe48GTc7sBKzOR1Kt9oK/img.png?width=652&amp;amp;height=652&amp;amp;face=0_0_652_652&quot;&gt;&lt;a href=&quot;https://styled-components.com/docs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://styled-components.com/docs&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xcUF5/hyV6c4TH4h/tkFi45VyBK81EkObUUSmBk/img.png?width=652&amp;amp;height=652&amp;amp;face=0_0_652_652,https://scrap.kakaocdn.net/dn/X2FFC/hyV9SwVW1j/EpQe48GTc7sBKzOR1Kt9oK/img.png?width=652&amp;amp;height=652&amp;amp;face=0_0_652_652');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;styled-components: Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn how to use styled-components and to style your apps without stress&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;styled-components.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/soaple/first-met-react-practice/blob/master/src/chapter_15/Blocks.jsx&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/soaple/first-met-react-practice/blob/master/src/chapter_15/Blocks.jsx&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716296655486&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;first-met-react-practice/src/chapter_15/Blocks.jsx at master &amp;middot; soaple/first-met-react-practice&quot; data-og-description=&quot;소플의 처음 만난 리액트 실습 소스코드. Contribute to soaple/first-met-react-practice development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/soaple/first-met-react-practice/blob/master/src/chapter_15/Blocks.jsx&quot; data-og-url=&quot;https://github.com/soaple/first-met-react-practice/blob/master/src/chapter_15/Blocks.jsx&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/soaple/first-met-react-practice/blob/master/src/chapter_15/Blocks.jsx&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/soaple/first-met-react-practice/blob/master/src/chapter_15/Blocks.jsx&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;first-met-react-practice/src/chapter_15/Blocks.jsx at master &amp;middot; soaple/first-met-react-practice&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소플의 처음 만난 리액트 실습 소스코드. Contribute to soaple/first-met-react-practice development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@pcs/styled-component-%EC%98%A4%EB%A5%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@pcs/styled-component-%EC%98%A4%EB%A5%98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716298108958&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;styled-component 오류??&quot; data-og-description=&quot;styled-component를 사용하면서 마주친 오류SWIPE GAME을 만들기 위해서 그냥 바탕 화면먼저 그려볼려고 이렇게 작성했었다.정말 간단하게 위 처럼 배경전체를 \&amp;#96;\&amp;#96;\&amp;#96;cannot read properties of null (reading 'usecont&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@pcs/styled-component-%EC%98%A4%EB%A5%98&quot; data-og-url=&quot;https://velog.io/@pcs/styled-component-오류&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eBI3y/hyV92GtToK/KyKXAKVvEanbbvqg4Z3kSk/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500&quot;&gt;&lt;a href=&quot;https://velog.io/@pcs/styled-component-%EC%98%A4%EB%A5%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@pcs/styled-component-%EC%98%A4%EB%A5%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eBI3y/hyV92GtToK/KyKXAKVvEanbbvqg4Z3kSk/img.png?width=950&amp;amp;height=500&amp;amp;face=0_0_950_500');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;styled-component 오류??&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;styled-component를 사용하면서 마주친 오류SWIPE GAME을 만들기 위해서 그냥 바탕 화면먼저 그려볼려고 이렇게 작성했었다.정말 간단하게 위 처럼 배경전체를 \`\`\`cannot read properties of null (reading 'usecont&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>FrontEnd/React</category>
      <author>JunGi Jeong</author>
      <guid isPermaLink="true">https://devjun.tistory.com/546</guid>
      <comments>https://devjun.tistory.com/546#entry546comment</comments>
      <pubDate>Wed, 8 May 2024 23:06:49 +0900</pubDate>
    </item>
    <item>
      <title>Context</title>
      <link>https://devjun.tistory.com/545</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Context란?&lt;/b&gt;&lt;/h2&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를 통하여 단 방향 데이터 전달되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 컴포넌트를 거쳐 자주 사용되는 데이터의 경우 코드의 복잡성과 불편함을 야기한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 개선하고자 Context를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Component Tree를 통해 직접적으로 전달하여 위 문제점을 해결&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KJXXX/btsG4ggxEK2/SI2IufVlpma8GaNmUzJO80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KJXXX/btsG4ggxEK2/SI2IufVlpma8GaNmUzJO80/img.png&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;373&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.6848%; margin-right: 10px;&quot; data-widthpercent=&quot;44.2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KJXXX/btsG4ggxEK2/SI2IufVlpma8GaNmUzJO80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKJXXX%2FbtsG4ggxEK2%2FSI2IufVlpma8GaNmUzJO80%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;604&quot; height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vUhLv/btsG5IpJKG4/61kPYMDNv4Lzk8g7Rf12zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vUhLv/btsG5IpJKG4/61kPYMDNv4Lzk8g7Rf12zk/img.png&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;383&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.1525%;&quot; data-widthpercent=&quot;55.8&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vUhLv/btsG5IpJKG4/61kPYMDNv4Lzk8g7Rf12zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvUhLv%2FbtsG5IpJKG4%2F61kPYMDNv4Lzk8g7Rf12zk%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;783&quot; height=&quot;383&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;React Context&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;언제 Context를 사용해야 할까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러 개의 Component들이 접근해야 하는 데이터 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ex) 로그인 여부, 로그인 정보, UI테마, 현재 언어 등... &lt;/b&gt;&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;Context 적용 전&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1714475998743&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function App(props) {
    return &amp;lt;Toolbar theme=&quot;dark&quot; /&amp;gt;;
}

function Toolbar(props) {
    // 이 Toolbar 컴포넌트는 ThemedButton에 theme를 넘겨주기 위해서 'theme' prop을 가져야만 합니다.
    // 현재 테마를 알아야 하는 모든 버튼에 대해서 props로 전달하는 것은 굉장히 비효율적입니다.
    return (
      &amp;lt;div&amp;gt;
        &amp;lt;ThemedButton theme={props.theme} /&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
  
  function ThemedButton(props) {
    return &amp;lt;Button theme={props.theme} /&amp;gt;
  }&lt;/code&gt;&lt;/pre&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;Context 적용 후&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1714476320164&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 컨텍스트는 데이터를 매번 컴포넌트를 통해 전달할 필요 없이 컴포넌트 트리로 곧바로 전달하게 해줍니다.
// 여기에서는 현재 테마를 위한 컨텍스트를 생성하며, 기본값은 'light'입니다.
const ThemeContext = React.createContext('light');

function App(props) {
    return (
        &amp;lt;ThemeContext.Provider value=&quot;dark&quot;&amp;gt;
            &amp;lt;Toolbar /&amp;gt;
        &amp;lt;/ThemeContext.Provider&amp;gt;
    );
}

// 이제 중간에 위치한 컴포넌트는 테마 데이털르 하위 컴포넌트로 전달할 필요가 없습니다.
function Toolbar(props) {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;ThemedButton /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

function ThemeButton(props) {
    // 리액트는 가장 가까운 상위 테마 Provider를 찾아서 해당되는 값을 사용합니다.
    // 만약 해당되는 Provider가 없을 경우 기본값(여기에서는 'light')을 사용합니다.
    // 여기에서는 상위 Provider가 있기 때문에 현재 테마의 값은 'dark'가 됩니다.

    return (
        &amp;lt;ThemeContext.Consumer&amp;gt;
            {value =&amp;gt; &amp;lt;Button theme={value} /&amp;gt;}
        &amp;lt;/ThemeContext.Consumer&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Context를 사용하기 전에 고려할 점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context의 주 용도는 다양한 레벨에 네스팅된 많은 컴포넌트에게 데이터를 전달하는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context 사용시 재사용하기 어려워 지기에 필요시에만 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러 레벨에 걸쳐 props를 넘기는 것을 대체하기에 컴포넌트 합성이 더 간단할 수 도 있음&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1714476546518&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Page컴포넌트는 PageLayout컴포넌트를 렌더링
&amp;lt;Page user={user} avatarSize={avatarSize} /&amp;gt;

// PageLayout컴포넌트는 NavigationBar 컴포넌트를 렌더링
&amp;lt;PageLayout user={user} avatarSize={avatarSize} /&amp;gt;

// NavigationBar 컴포넌트는 Link컴포넌트를 렌더링
&amp;lt;NavigationBar user={user} avatarSize={avatarSize} /&amp;gt;

// Link컴포넌트는 Avatar컴포넌트를 렌더링
&amp;lt;Link href={user.permalink}&amp;gt;
    &amp;lt;Avatar user={user} size={avatarSize} /&amp;gt;
&amp;lt;/Link&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;b&gt;컴포넌트 합성 예제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1714476853804&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Page(props) {
    const user = props.user;

    const userLink = (
        &amp;lt;Link href={user.permalink}&amp;gt;
            &amp;lt;Avatar user={user} size={props.avatarSize} /&amp;gt;
        &amp;lt;/Link&amp;gt;
    );

    // Page 컴포넌트는 PageLayout 컴포넌트를 렌더링
    // 이때 props로 userLink를 함께 전달함
    return &amp;lt;PageLayout userLink={userLink} /&amp;gt;;
}

// PageLayout 컴포넌트는 NavigationBar 컴포넌트를 렌더링
&amp;lt;PageLayout userLink={...} /&amp;gt;

// NavigationBar 컴포넌트는 props로 전달받은 userLink element를 리턴
&amp;lt;NavigationBar userLink={...} /&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;&lt;b&gt;컴포넌트 합성 예제2&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1714477297821&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Page(props) {
    const user = props.user;

    const topBar = (
        &amp;lt;NavigationBar&amp;gt;
            &amp;lt;Link href={user.permalink}&amp;gt;
                &amp;lt;Avatar user={user} size={props.avatarSize} /&amp;gt;
            &amp;lt;/Link&amp;gt;
        &amp;lt;/NavigationBar&amp;gt;
    );
    const content = &amp;lt;Feed user={user} /&amp;gt;;
    
    return (
        &amp;lt;PageLayout // 하위 컴포넌트를 여러 개의 변수로 나눠서 전달!
            topBar={topBar}
            content={content}
        /&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Context API&lt;/b&gt;&lt;/h2&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;b&gt;Context 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 상위 레벨에 매칭되는 Provider가 없다면 기본값이 사용 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 값으로 undefined를 넣으면 기본값이 사용되지 않&lt;/p&gt;
&lt;pre id=&quot;code_1714659275304&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const MyContext = React.createContext(기본값);&lt;/code&gt;&lt;/pre&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;Context.Provider&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Provider 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1714659495254&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;MyContext.Provider value={/* some value */}&amp;gt;

/*
Provider Component로 감싸진 모든 Consuming Component는
Provider의 value prop이 바뀔 때 마다 재 렌더링 된다.
값이 변경되었을때 상위 컴포넌트가 변경 대상이 아니더라도
하위에 있는 컴포넌트가 Context를 사용한다면
하위 컴포넌트에서는 업데이트가 일어난다.
값의 변화 기준은 Reference의 MDN참조
*/&lt;/code&gt;&lt;/pre&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;Provider value에서 주의 사항&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1714660135210&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Provider 컴포넌트가 재렌더링될 때마다
// 모든 하위 consumer 컴포넌트가 재렌더링 됨
function App(props) {
    return (
        &amp;lt;MyContext.Provider value={{ something : 'something'}}&amp;gt;
            &amp;lt;ToolBar /&amp;gt;
        &amp;lt;/MyContext.Provider&amp;gt;
    );
}

// state를 사용하여 불필요한 재렌더링을 막음
function App(props) {
    const [value, setValue] = useState({ something : 'something'});

    return (
        &amp;lt;MyContext.Provider value={value}&amp;gt;
            &amp;lt;ToolBar /&amp;gt;
        &amp;lt;/MyContext.Provider&amp;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;&lt;b&gt;Class.context&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;provider하위에 있는 클래스 컴포넌트에서 context 데이터에 접근하기 위해 사용&lt;/p&gt;
&lt;pre id=&quot;code_1714660421288&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyClass extends React.Component {
    componentDidMount() {
        let value = this.context;
        /* MyContext의 값을 이용하여 원하는 작업을 수행 가능 */
    }
    componentDidUpdate() {
        let value = this.context;
        /* ... */
    }
    componentWillUnmount() {
        let value = this.context;
        /* ... */
    }
    render() {
        let value = this.context;
        /* MyContext의 값에 따라서 컴포넌트들을 렌더링 */
    }
}

MyClass.contextType = MyContext;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Context.Consumer&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1714660518590&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Component의 자식으로 함수가 올 수 있는데 이를 function as a child라 한다.
&amp;lt;MyContext.Consumer&amp;gt;
    {value =&amp;gt; /* 컨텍스트의 값에 따라서 컴포넌트들을 렌더링 */}
&amp;lt;/MyContext.Consumer&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Function as a child&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1714660878451&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// children이라는 prop을 직접 선언하는 방식
&amp;lt;Profile children={name =&amp;gt; &amp;lt;p&amp;gt;이름 : {name}&amp;lt;/p&amp;gt;} /&amp;gt;

// Profile 컴포넌트로 감싸서 children으로 만드는 방식
&amp;lt;Profile&amp;gt;{name =&amp;gt; &amp;lt;p&amp;gt;이름 : {name}&amp;lt;/p&amp;gt;}&amp;lt;/Profile&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Context.displayName&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1714661102432&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';

// 개발자 도구에 &quot;MyDisplayName.Provider&quot;로 표시됨
&amp;lt;MyContext.Provider /&amp;gt;

// 개발자 도구에 &quot;MyDisplay.Consumer&quot;로 표시됨
&amp;lt;MyContext.Consumer /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;여러 개의 Context 사용하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context.Provider의 중첩&lt;/p&gt;
&lt;pre id=&quot;code_1714661313380&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 테마를 위한 컨텍스트
const ThemeContext = React.createContext('light');

// 로그인한 유저 정보를 담는 UserContext
const UserContext = React.createContext({
  name: 'Guest',
});

class App extends React.Component {
  render() {
    const {signedInUser, theme} = this.props;

    // context 초기값을 제공하는 App 컴포넌트
    return (
      &amp;lt;ThemeContext.Provider value={theme}&amp;gt;
        &amp;lt;UserContext.Provider value={signedInUser}&amp;gt;
          &amp;lt;Layout /&amp;gt;
        &amp;lt;/UserContext.Provider&amp;gt;
      &amp;lt;/ThemeContext.Provider&amp;gt;
    );
  }
}

function Layout() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Sidebar /&amp;gt;
      &amp;lt;Content /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// 여러 context의 값을 받는 컴포넌트
function Content() {
  return (
    &amp;lt;ThemeContext.Consumer&amp;gt;
      {theme =&amp;gt; (
        &amp;lt;UserContext.Consumer&amp;gt;
          {user =&amp;gt; (
            &amp;lt;ProfilePage user={user} theme={theme} /&amp;gt;
          )}
        &amp;lt;/UserContext.Consumer&amp;gt;
      )}
    &amp;lt;/ThemeContext.Consumer&amp;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;&lt;b&gt;useContext()&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;useContext() Hook을 사용한 예시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1714661395890&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useContext } from &quot;react&quot;;

function MyComponent(props) {
    const value = useContext(MyComponent);

    return (
        ...
    )
}

// 올바른 사용법
useContext(MyContext);

// 잘못된 사용법
useContext(MyContext.Consumer);
useContext(MyContext.Provider);&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h2&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;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot;&gt;인프런 - 처음 만난 리액트(React)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1714474562947&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[지금 무료] 처음 만난 리액트(React) | Inje Lee (소플) - 인프런&quot; data-og-description=&quot;Inje Lee (소플) | 자바스크립트와 CSS 기초 문법과 함께 리액트의 기초를 탄탄하게 다질 수 있습니다., 깔끔한 강의자료, 꼼꼼한 설명으로쉽게 배우는 리액트 강의입니다.  &amp;zwj;  리액트의 세계로&quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; data-og-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/tPXud/hyVVF0oBz0/Jf4PCFD3G9J39asKhZUs91/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/buEHor/hyVVzy5Ghj/VRyoETpWTNobgaXQMGZa7K/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/VxNKn/hyVZubOJcN/jDqpjHCnhbXQwkVY9ZKpsk/img.png?width=958&amp;amp;height=717&amp;amp;face=145_56_607_490&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/tPXud/hyVVF0oBz0/Jf4PCFD3G9J39asKhZUs91/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/buEHor/hyVVzy5Ghj/VRyoETpWTNobgaXQMGZa7K/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/VxNKn/hyVZubOJcN/jDqpjHCnhbXQwkVY9ZKpsk/img.png?width=958&amp;amp;height=717&amp;amp;face=145_56_607_490');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[지금 무료] 처음 만난 리액트(React) | Inje Lee (소플) - 인프런&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Inje Lee (소플) | 자바스크립트와 CSS 기초 문법과 함께 리액트의 기초를 탄탄하게 다질 수 있습니다., 깔끔한 강의자료, 꼼꼼한 설명으로쉽게 배우는 리액트 강의입니다.  &amp;zwj;  리액트의 세계로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://ko.legacy.reactjs.org/docs/context.html#gatsby-focus-wrapper&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.legacy.reactjs.org/docs/context.html#gatsby-focus-wrapper&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1714474652496&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Context &amp;ndash; React&quot; data-og-description=&quot;A JavaScript library for building user interfaces&quot; data-og-host=&quot;ko.legacy.reactjs.org&quot; data-og-source-url=&quot;https://ko.legacy.reactjs.org/docs/context.html#gatsby-focus-wrapper&quot; data-og-url=&quot;https://ko.legacy.reactjs.org/docs/context.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c7R484/hyVZobB3zI/rKKLTfM80UJW6wkq8LxeVK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/context.html#gatsby-focus-wrapper&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.legacy.reactjs.org/docs/context.html#gatsby-focus-wrapper&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c7R484/hyVZobB3zI/rKKLTfM80UJW6wkq8LxeVK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Context &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A JavaScript library for building user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.legacy.reactjs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1714659584963&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Object.is() - JavaScript | MDN&quot; data-og-description=&quot;The Object.is() static method determines whether two values are the same value.&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is&quot; data-og-url=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/olnSG/hyVVHK3MZ0/6KFsUVMfTXUOhxnk0dXLTK/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/olnSG/hyVVHK3MZ0/6KFsUVMfTXUOhxnk0dXLTK/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Object.is() - JavaScript | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The Object.is() static method determines whether two values are the same value.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>FrontEnd/React</category>
      <author>JunGi Jeong</author>
      <guid isPermaLink="true">https://devjun.tistory.com/545</guid>
      <comments>https://devjun.tistory.com/545#entry545comment</comments>
      <pubDate>Tue, 30 Apr 2024 20:42:50 +0900</pubDate>
    </item>
    <item>
      <title>Composition vs Inheritacne</title>
      <link>https://devjun.tistory.com/544</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Composition&lt;/b&gt;&lt;/h2&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Containment&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하위 컴포넌트를 포함하는 형태의 합성 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sidebar나 Dialog 같은 Box형태의 컴포넌트는 자신의 하위 컴포넌트를 미리 알 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 컴포넌트에는 특수한 children prop을 사용하여 자식 엘리멘트를 출력에 그대로 전달하는 것이 좋다.&lt;/p&gt;
&lt;pre id=&quot;code_1714396275570&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// children이라는 prop을 사용해서 조합
// children prop을 사용한 FancyBorder 컴포넌트
function FancyBorder(props) {
    return (
        &amp;lt;div className={'FancyBorder FancyBorder-' + props.color}&amp;gt;
            {props.children}
        &amp;lt;/div&amp;gt;
    );
}

React.createElement(
    type,
    [props],
    [...children]
);

// FancyBorder 컴포넌트 안에 있는 모든 JSX 태그는 children으로 전달됨!
function WelcomeDialog(props) {
    return (
      &amp;lt;FancyBorder color=&quot;blue&quot;&amp;gt;
        &amp;lt;h1 className=&quot;Dialog-title&quot;&amp;gt;
          Welcome
        &amp;lt;/h1&amp;gt;
        &amp;lt;p className=&quot;Dialog-message&quot;&amp;gt;
          Thank you for visiting our spacecraft!
        &amp;lt;/p&amp;gt;
      &amp;lt;/FancyBorder&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;여러 개의 children 집합이 필요한 경우 별도로&amp;nbsp;props를&amp;nbsp;정의해&amp;nbsp;각각&amp;nbsp;원하는&amp;nbsp;컴포넌트를&amp;nbsp;넣어주면&amp;nbsp;됨&lt;/p&gt;
&lt;pre id=&quot;code_1714396520715&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function SplitPane(props) {
    return (
      &amp;lt;div className=&quot;SplitPane&quot;&amp;gt;
        &amp;lt;div className=&quot;SplitPane-left&quot;&amp;gt;
          {props.left}
        &amp;lt;/div&amp;gt;
        &amp;lt;div className=&quot;SplitPane-right&quot;&amp;gt;
          {props.right}
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
  
  function App(props) {
    return (
      &amp;lt;SplitPane
        left={
          &amp;lt;Contacts /&amp;gt;
        }
        right={
          &amp;lt;Chat /&amp;gt;
        } /&amp;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;&lt;b&gt;Specialization&lt;/b&gt;&lt;/h2&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;WelcomeDialog는 Dialog의 특수한 경우라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향의 경우 상속(Inheritance)을 통해 Specialization을 구현하나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React의 경우 합성(Containment)을 사용하여 Specialization을 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714396966547&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 더 구체적인 컴포넌트가 일반적인 컴포넌트를 렌더링하고 props를 통해 내용을 구성한다.
function Dialog(props) {
    return (
      &amp;lt;FancyBorder color=&quot;blue&quot;&amp;gt;
        &amp;lt;h1 className=&quot;Dialog-title&quot;&amp;gt;
          {props.title}
        &amp;lt;/h1&amp;gt;
        &amp;lt;p className=&quot;Dialog-message&quot;&amp;gt;
          {props.message}
        &amp;lt;/p&amp;gt;
      &amp;lt;/FancyBorder&amp;gt;
    );
  }
  
  function WelcomeDialog(props) {
    return (
      &amp;lt;Dialog
        title=&quot;Welcome&quot;
        message=&quot;Thank you for visiting our spacecraft!&quot; /&amp;gt;
    );
  }&lt;/code&gt;&lt;/pre&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;Containment와 Specialization을 같이 사용하기&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1714397237957&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from &quot;react&quot;;

function Dialog(props) {
    return (
      &amp;lt;FancyBorder color=&quot;blue&quot;&amp;gt;
        &amp;lt;h1 className=&quot;Dialog-title&quot;&amp;gt;
          {props.title}
        &amp;lt;/h1&amp;gt;
        &amp;lt;p className=&quot;Dialog-message&quot;&amp;gt;
          {props.message}
        &amp;lt;/p&amp;gt;
        {props.children}
      &amp;lt;/FancyBorder&amp;gt;
    );
  }

  function SignUpDialog(props) {
    const [nickname, setNickname] = useState('');

    const handleChange= (event) =&amp;gt; {
        setNickname(event.target.value);
    }

    const handleSignUp = () =&amp;gt; {
        alert('어서 오세요, ${nickname}님!');
    }

    return (
        &amp;lt;Dialog
        title=&quot;화성 탐사 프로그램&quot;
        message=&quot;닉네임을 입력해 주세요.&quot;&amp;gt;
        &amp;lt;input
            value={nickname}
            onChange={handleChange} /&amp;gt;
        &amp;lt;button onClick={handleSignUp}&amp;gt;
            가입하기
        &amp;lt;/button&amp;gt;
        &amp;lt;/Dialog&amp;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;&lt;b&gt;Inheriatance&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;상속&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 컴포넌트로부터 상속을 받아서 새로운 컴포넌트를 만드는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Meta에서 상속보다 합성을 추천&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;복잡한 컴포넌트를 쪼개서&lt;br /&gt;여러 개의 컴포넌트로 만들고,&lt;br /&gt;만든 컴포넌트를 조합해서&lt;br /&gt;새로운 컴포넌트를 만들자!&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;Reference&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot;&gt;인프런 - 처음 만난 리액트(React)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1714397416787&quot; style=&quot;color: #333333; text-align: start;&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLTvxz/hyVS3evtyV/YenDxHTT2XhEXtAJMxbjpK/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/EUbgt/hyVPYsnwiL/6jSQwecegFvS985MM20YK0/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781&quot; data-og-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8&quot; data-og-source-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; data-og-host=&quot;www.inflearn.com&quot; data-og-description=&quot;Inje Lee (소플) | 자바스크립트와 CSS 기초 문법과 함께 리액트의 기초를 탄탄하게 다질 수 있습니다., 깔끔한 강의자료, 꼼꼼한 설명으로쉽게 배우는 리액트 강의입니다.  &amp;zwj;  리액트의 세계로&quot; data-og-title=&quot;[지금 무료] 처음 만난 리액트(React) | Inje Lee (소플) - 인프런&quot; data-og-type=&quot;website&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; data-source-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLTvxz/hyVS3evtyV/YenDxHTT2XhEXtAJMxbjpK/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/EUbgt/hyVPYsnwiL/6jSQwecegFvS985MM20YK0/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;[지금 무료] 처음 만난 리액트(React) | Inje Lee (소플) - 인프런&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;Inje Lee (소플) | 자바스크립트와 CSS 기초 문법과 함께 리액트의 기초를 탄탄하게 다질 수 있습니다., 깔끔한 강의자료, 꼼꼼한 설명으로쉽게 배우는 리액트 강의입니다.  &amp;zwj;  리액트의 세계로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/composition-vs-inheritance.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.legacy.reactjs.org/docs/composition-vs-inheritance.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1714397432200&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;합성 (Composition) vs 상속 (Inheritance) &amp;ndash; React&quot; data-og-description=&quot;A JavaScript library for building user interfaces&quot; data-og-host=&quot;ko.legacy.reactjs.org&quot; data-og-source-url=&quot;https://ko.legacy.reactjs.org/docs/composition-vs-inheritance.html&quot; data-og-url=&quot;https://ko.legacy.reactjs.org/docs/composition-vs-inheritance.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cFuDkk/hyVVIikQFx/cqXLYrgNmytKZeGYQEvLP1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/composition-vs-inheritance.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.legacy.reactjs.org/docs/composition-vs-inheritance.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cFuDkk/hyVVIikQFx/cqXLYrgNmytKZeGYQEvLP1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;합성 (Composition) vs 상속 (Inheritance) &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A JavaScript library for building user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.legacy.reactjs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_13&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_13&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1714397498351&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;first-met-react-practice/src/chapter_13 at master &amp;middot; soaple/first-met-react-practice&quot; data-og-description=&quot;소플의 처음 만난 리액트 실습 소스코드. Contribute to soaple/first-met-react-practice development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_13&quot; data-og-url=&quot;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_13&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/AeSpy/hyVVB4Buez/b2LNlDYNhgEBYtIFyR3L1K/img.png?width=1200&amp;amp;height=600&amp;amp;face=995_138_1038_184&quot;&gt;&lt;a href=&quot;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_13&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/AeSpy/hyVVB4Buez/b2LNlDYNhgEBYtIFyR3L1K/img.png?width=1200&amp;amp;height=600&amp;amp;face=995_138_1038_184');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;first-met-react-practice/src/chapter_13 at master &amp;middot; soaple/first-met-react-practice&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소플의 처음 만난 리액트 실습 소스코드. Contribute to soaple/first-met-react-practice development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>FrontEnd/React</category>
      <author>JunGi Jeong</author>
      <guid isPermaLink="true">https://devjun.tistory.com/544</guid>
      <comments>https://devjun.tistory.com/544#entry544comment</comments>
      <pubDate>Mon, 29 Apr 2024 22:31:43 +0900</pubDate>
    </item>
    <item>
      <title>Lifting State Up</title>
      <link>https://devjun.tistory.com/543</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;여러개의 컴포넌트들 사이에서 State를 공유하는 방법&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Shared State&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;State에 있는 데이터를 여러 개의 하위 컴포넌트에서 공통적으로 사용하는 경우 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 데이터를 여러 개의 컴포넌트에서 표현&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;620&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l7duf/btsGTa88SoX/VqvfkgTFEOTCdsJgplCjsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l7duf/btsGTa88SoX/VqvfkgTFEOTCdsJgplCjsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l7duf/btsGTa88SoX/VqvfkgTFEOTCdsJgplCjsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl7duf%2FbtsGTa88SoX%2FVqvfkgTFEOTCdsJgplCjsK%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;468&quot; height=&quot;364&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;620&quot;/&gt;&lt;/span&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;하위 컴포넌트에서 State 공유하기&lt;/b&gt;&lt;/h2&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;pre id=&quot;code_1713966731533&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from &quot;react&quot;;

function BoilingVerdict(props) {
    if(props.celsius &amp;gt;= 100) {
        return &amp;lt;p&amp;gt;물이 끓습니다.&amp;lt;/p&amp;gt;;
    }
    return &amp;lt;p&amp;gt;물이 끓지 않습니다.&amp;lt;/p&amp;gt;;
}

function Calculator(props) {
    const [temperature, setTemperature] = useState('');

    const handleChange = (event) =&amp;gt; {
        setTemperature(event.target.value);
    }

    return (
        &amp;lt;fieldset&amp;gt;
            &amp;lt;legend&amp;gt;섭씨 온도를 입력하세요 : &amp;lt;/legend&amp;gt;
            &amp;lt;input value={temperature}
            onChange={handleChange} /&amp;gt;
            &amp;lt;BoilingVerdict
            celsius={parseFloat(temperature)} /&amp;gt;
        &amp;lt;/fieldset&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;입력 컴포넌트 추출하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1713968517929&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function TemperatureInput(props) {
    const [temperature, setTemperature] = useState('');

    const handleChange = (event) =&amp;gt; {
        setTemperature(event.target.value);
    }

    return (
        &amp;lt;fieldset&amp;gt;
            &amp;lt;legend&amp;gt;온도를 입력해 주세요(단위:{scaleNames[props.scale]}):&amp;lt;/legend&amp;gt;
            &amp;lt;input value={temperature}onChange={handleChange} /&amp;gt;
            celsius={parseFloat(temperature)} /&amp;gt;
        &amp;lt;/fieldset&amp;gt;
    )
}

function Calculator(props) {
    return (
        &amp;lt;div&amp;gt;
            &amp;lt;TemperatureInput scale=&quot;c&quot; /&amp;gt;
            &amp;lt;TemperatureInput scale=&quot;f&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;온도 변환 함수 작성하기&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1713968744045&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function toCelsius(fahrenheit) {
    return (fahrenheit - 32) * 5 / 9;
}

function toFahrenheit(celsius) {
    return (celsius * 9 / 5) + 32;
}

function tryConvert(temperature, convert) {
    const input = parseFloat(temperature);
    if (Number.isNaN(input)) {
        return '';
    }
    const output = convert(input);
    const rounded = Math.round(output * 1000) / 1000;
    return rounded.toString();
}

tryConvert('abc', toCelsius);       // empty string을 리턴
tryConvert('10.22', toFahrenheit)   // '50.396'을 리턴&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;&lt;b&gt;Shared State 적용하기&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1713969332709&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function TemperatureInput(props) {
   ...
    return (
            // 변경 전 : &amp;lt;input value={temperature}onChange={handleChange} /&amp;gt;
            &amp;lt;input value={props.temperature}onChange={handleChange} /&amp;gt;
   ...
    )
}

const handleChange = (event) =&amp;gt; {
        // 변경 전 : setTemperature(event.target.value);
        props.onTemperatureChange(event.target.value);
    }
    
function TemperatureInput(props) {
    const handleChange = (event) =&amp;gt; {
        props.onTemperatureChange(event.target.value);
    }

    return (
        &amp;lt;fieldset&amp;gt;
            &amp;lt;legend&amp;gt;온도를 입력해 주세요(단위:{scaleNames[props.scale]}):&amp;lt;/legend&amp;gt;
            &amp;lt;input value={props.temperature}onChange={handleChange} /&amp;gt;
        &amp;lt;/fieldset&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Calculator 컴포넌트 변경하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1713969835938&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Calculator(props) {
    const [temperature, setTemperatrue] = useState('');
    const [scale, setScale] = useState('c');

    const handleCelsiusChange = (temperature) =&amp;gt; {
        setTemperatrue(temperature);
        setScale('c');
    }

    const handleFahrenheitChange = (temperature) =&amp;gt; {
        setTemperatrue(temperature);
        setScale('f');
    }

    const celsius = scale == 'f' ? tryConvert(temperature, toCelsius) : temperature;
    const fahrenheit = scale == 'c' ? tryConvert(temperature, toFahrenheit) : temperature;

    return (
        &amp;lt;div&amp;gt;
            &amp;lt;TemperatureInput
            scale=&quot;c&quot;
            temperature={celsius}
            onTemperatureChange={handleCelsiusChange} /&amp;gt;
            &amp;lt;TemperatureInput
            scale=&quot;f&quot;
            temperature={fahrenheit}
            onTemperatureChange={handleFahrenheitChange} /&amp;gt;
            &amp;lt;BoilingVerdict
            celsius={parseFloat(celsius)} /&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;993&quot; data-origin-height=&quot;653&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8IJvB/btsGT8Jz9Ho/K4SW8UGelagVKXth5LxqIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8IJvB/btsGT8Jz9Ho/K4SW8UGelagVKXth5LxqIk/img.png&quot; data-alt=&quot;소플님의 강의 자료 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8IJvB/btsGT8Jz9Ho/K4SW8UGelagVKXth5LxqIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8IJvB%2FbtsGT8Jz9Ho%2FK4SW8UGelagVKXth5LxqIk%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;462&quot; height=&quot;304&quot; data-origin-width=&quot;993&quot; data-origin-height=&quot;653&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;소플님의 강의 자료 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot;&gt;인프런 - 처음 만난 리액트(React)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1713965447708&quot; style=&quot;color: #333333; text-align: start;&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[지금 무료] 처음 만난 리액트(React) | Inje Lee (소플) - 인프런&quot; data-og-description=&quot;Inje Lee (소플) | 자바스크립트와 CSS 기초 문법과 함께 리액트의 기초를 탄탄하게 다질 수 있습니다., 깔끔한 강의자료, 꼼꼼한 설명으로쉽게 배우는 리액트 강의입니다.  &amp;zwj;  리액트의 세계로&quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; data-og-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLTvxz/hyVS3evtyV/YenDxHTT2XhEXtAJMxbjpK/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/EUbgt/hyVPYsnwiL/6jSQwecegFvS985MM20YK0/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot; data-source-url=&quot;https://www.inflearn.com/course/%EC%B2%98%EC%9D%8C-%EB%A7%8C%EB%82%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLTvxz/hyVS3evtyV/YenDxHTT2XhEXtAJMxbjpK/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/EUbgt/hyVPYsnwiL/6jSQwecegFvS985MM20YK0/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;[지금 무료] 처음 만난 리액트(React) | Inje Lee (소플) - 인프런&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;Inje Lee (소플) | 자바스크립트와 CSS 기초 문법과 함께 리액트의 기초를 탄탄하게 다질 수 있습니다., 깔끔한 강의자료, 꼼꼼한 설명으로쉽게 배우는 리액트 강의입니다.  &amp;zwj;  리액트의 세계로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/lifting-state-up.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.legacy.reactjs.org/docs/lifting-state-up.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1713965464342&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;State 끌어올리기 &amp;ndash; React&quot; data-og-description=&quot;A JavaScript library for building user interfaces&quot; data-og-host=&quot;ko.legacy.reactjs.org&quot; data-og-source-url=&quot;https://ko.legacy.reactjs.org/docs/lifting-state-up.html&quot; data-og-url=&quot;https://ko.legacy.reactjs.org/docs/lifting-state-up.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cmnmVY/hyVS0Krvyc/ONTJsOkB8zmYW3XavXQ5i0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/lifting-state-up.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.legacy.reactjs.org/docs/lifting-state-up.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cmnmVY/hyVS0Krvyc/ONTJsOkB8zmYW3XavXQ5i0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;State 끌어올리기 &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A JavaScript library for building user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.legacy.reactjs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://react.dev/learn/sharing-state-between-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://react.dev/learn/sharing-state-between-components&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1713965915267&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Sharing State Between Components &amp;ndash; React&quot; data-og-description=&quot;The library for web and native user interfaces&quot; data-og-host=&quot;react.dev&quot; data-og-source-url=&quot;https://react.dev/learn/sharing-state-between-components&quot; data-og-url=&quot;https://react.dev/learn/sharing-state-between-components&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kw2QX/hyVVCumDtb/fsQrE8Z4fumoiIkVVGg2W1/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567,https://scrap.kakaocdn.net/dn/G4uT8/hyVVwVdjy1/nilT97UXubruDekU2Xuoa0/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567&quot;&gt;&lt;a href=&quot;https://react.dev/learn/sharing-state-between-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://react.dev/learn/sharing-state-between-components&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kw2QX/hyVVCumDtb/fsQrE8Z4fumoiIkVVGg2W1/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567,https://scrap.kakaocdn.net/dn/G4uT8/hyVVwVdjy1/nilT97UXubruDekU2Xuoa0/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Sharing State Between Components &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The library for web and native user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;react.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_12&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_12&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1713970084561&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;first-met-react-practice/src/chapter_12 at master &amp;middot; soaple/first-met-react-practice&quot; data-og-description=&quot;소플의 처음 만난 리액트 실습 소스코드. Contribute to soaple/first-met-react-practice development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_12&quot; data-og-url=&quot;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_12&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/soaple/first-met-react-practice/tree/master/src/chapter_12&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;first-met-react-practice/src/chapter_12 at master &amp;middot; soaple/first-met-react-practice&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소플의 처음 만난 리액트 실습 소스코드. Contribute to soaple/first-met-react-practice development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>FrontEnd/React</category>
      <author>JunGi Jeong</author>
      <guid isPermaLink="true">https://devjun.tistory.com/543</guid>
      <comments>https://devjun.tistory.com/543#entry543comment</comments>
      <pubDate>Wed, 24 Apr 2024 23:46:40 +0900</pubDate>
    </item>
  </channel>
</rss>