<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>minjoo_huh.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 11 Jun 2025 15:03:03 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>minjoo_huh.log</title>
            <url>https://velog.velcdn.com/images/minjoo_huh/profile/caf15a88-a814-4285-bb9b-13d9573cd668/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. minjoo_huh.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/minjoo_huh" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[📘 이벤트 버블링과 `stopPropagation()` — 구조적 이해와 실전 예시]]></title>
            <link>https://velog.io/@minjoo_huh/%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81%EA%B3%BC-stopPropagation-%EA%B5%AC%EC%A1%B0%EC%A0%81-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%8B%A4%EC%A0%84-%EC%98%88%EC%8B%9C</link>
            <guid>https://velog.io/@minjoo_huh/%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81%EA%B3%BC-stopPropagation-%EA%B5%AC%EC%A1%B0%EC%A0%81-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%8B%A4%EC%A0%84-%EC%98%88%EC%8B%9C</guid>
            <pubDate>Wed, 11 Jun 2025 15:03:03 GMT</pubDate>
            <description><![CDATA[<p>웹 개발에서 자주 마주치는 개념 중 하나가 <strong>이벤트 버블링(Event Bubbling)</strong>입니다.
클릭 이벤트 하나로 <strong>여러 요소가 함께 반응</strong>하는 상황, 혹시 경험해보셨나요?</p>
<p>이번 글에서는 이벤트 버블링의 개념을 구조적으로 정리하고,
회사 <strong>보고 체계</strong>에 빗대어 직관적인 예시와 함께 <code>stopPropagation()</code> 사용법까지 정리해보겠습니다.</p>
<hr>
<h2 id="✅-이벤트-버블링이란">✅ 이벤트 버블링이란?</h2>
<blockquote>
<p>하위 요소에서 발생한 이벤트가 부모, 조부모 등 <strong>상위 요소로 전파되는 현상</strong></p>
</blockquote>
<p>DOM은 계층적 구조로 되어 있기 때문에, 이벤트도 <strong>트리 구조를 따라 위로 전달</strong>됩니다.
이것이 바로 <strong>이벤트 버블링</strong>입니다.</p>
<h3 id="🔍-예시-코드">🔍 예시 코드</h3>
<pre><code class="language-tsx">&lt;div onClick={() =&gt; console.log(&quot;div 클릭&quot;)}&gt;
  &lt;button onClick={() =&gt; console.log(&quot;button 클릭&quot;)}&gt;클릭&lt;/button&gt;
&lt;/div&gt;</code></pre>
<p>버튼을 클릭하면 콘솔 출력:</p>
<pre><code class="language-css">button 클릭
div 클릭</code></pre>
<p>버튼을 눌렀을 뿐인데 div의 이벤트까지 발생했죠?
→ 이벤트가 <strong>버튼에서 시작해 상위 요소로 전달</strong>된 것입니다.</p>
<hr>
<h2 id="🏢-회사-보고-체계로-비교해보자">🏢 회사 보고 체계로 비교해보자</h2>
<p>회사엔 다음과 같은 계층이 있다고 해볼게요:</p>
<pre><code class="language-jsx">&lt;button&gt;   →    &lt;div&gt;    →    &lt;body&gt;
 신입사원         팀장           본부장</code></pre>
<p>이때 어떤 보고는 <strong>자연스럽게 위로 올라가야 하고</strong>,
어떤 일은 <strong>굳이 보고하지 않아도 되는 경우</strong>도 있죠.</p>
<hr>
<h3 id="✅-예시-1-자연스럽게-보고되는-일-버블링-허용">✅ 예시 1: 자연스럽게 보고되는 일 (버블링 허용)</h3>
<h4 id="📌-예-고객-문의-서버-오류-재무-관련-요청">📌 예: 고객 문의, 서버 오류, 재무 관련 요청</h4>
<ul>
<li>신입 사원이 고객의 불만 전화를 받음</li>
<li>팀장에게 보고 → 본부장에게 전달됨</li>
<li>이건 <strong>전파되는 게 당연한 흐름</strong>입니다</li>
</ul>
<pre><code class="language-tsx">&lt;div onClick={() =&gt; console.log(&quot;팀장도 반응함&quot;)}&gt;
  &lt;button onClick={() =&gt; console.log(&quot;신입이 먼저 반응함&quot;)}&gt;보고&lt;/button&gt;
&lt;/div&gt;</code></pre>
<p><strong>결과:</strong></p>
<pre><code>신입이 먼저 반응함  
팀장도 반응함</code></pre><p>✅ 이벤트가 위로 전파됨 → <strong>버블링 발생</strong></p>
<hr>
<h3 id="☕-예시-2-굳이-보고-안-해도-되는-일-버블링-차단">☕ 예시 2: 굳이 보고 안 해도 되는 일 (버블링 차단)</h3>
<h4 id="📌-예-커피가-떨어졌다--화분에-물-주기--사무실-청소">📌 예: 커피가 떨어졌다 / 화분에 물 주기 / 사무실 청소</h4>
<ul>
<li>신입이 혼자 처리해도 되고</li>
<li>오히려 팀장에게 보고하면 “그건 네가 알아서 해”라는 반응을 들을 수 있음 😅</li>
</ul>
<pre><code class="language-tsx">&lt;div onClick={() =&gt; console.log(&quot;팀장도 반응함&quot;)}&gt;
  &lt;div onClick={(e) =&gt; e.stopPropagation()}&gt;
    &lt;button onClick={() =&gt; console.log(&quot;신입이 처리함&quot;)}&gt;커피 주문&lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;</code></pre>
<p><strong>결과:</strong></p>
<pre><code>신입이 처리함</code></pre><p>✅ <code>stopPropagation()</code>으로 상위로 이벤트 전파 차단 → <strong>버블링 방지</strong></p>
<hr>
<h2 id="🧩-핵심-비교-요약">🧩 핵심 비교 요약</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>설명</th>
<th>흐름</th>
<th>처리 방식</th>
</tr>
</thead>
<tbody><tr>
<td>보고가 자연스러운 일</td>
<td>고객 불만, 시스템 장애 등</td>
<td>하위 → 상위로 전달</td>
<td>버블링 허용 (기본)</td>
</tr>
<tr>
<td>자율처리 가능한 일</td>
<td>커피 부족, 청소 등</td>
<td>하위에서 처리 종료</td>
<td><code>stopPropagation()</code>으로 차단</td>
</tr>
</tbody></table>
<hr>
<h2 id="🧠-정리">🧠 정리</h2>
<ul>
<li><strong>이벤트 버블링</strong>은 DOM 구조에서 발생하는 <strong>자연스러운 전파 현상</strong>입니다.</li>
<li>하지만 <strong>모든 이벤트가 전파되어야 하는 건 아니며</strong>, UX에 따라 <strong>제어할 필요가 있습니다</strong>.</li>
<li>그런 경우 사용하는 것이 바로 <code>stopPropagation()</code></li>
</ul>
<hr>
<h2 id="💬-마무리">💬 마무리</h2>
<p>모달, 드롭다운, 알림 UI처럼
<strong>클릭이 특정 범위에서만 유효해야 하는 상황</strong>이 많아질수록
이벤트의 흐름을 명확히 이해하고 제어하는 게 중요합니다.</p>
<p><code>stopPropagation()</code>은 단순한 클릭 차단 코드가 아니라,
<strong>UI의 흐름을 설계하는 중요한 도구</strong>입니다.
의도한 흐름을 만들어내기 위해선, <strong>이벤트가 어디까지 흘러야 하는지</strong> 스스로 결정할 수 있어야 합니다.</p>
<hr>
<p>이제 이벤트가 갑자기 이상하게 작동한다면,
“이건 위로 버블링된 건가?”부터 의심해보세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[트리 쉐이킹(Tree-Shaking)과 사이드 이펙트(Side Effect) 쉽게 정리하기 😊]]></title>
            <link>https://velog.io/@minjoo_huh/%ED%8A%B8%EB%A6%AC-%EC%89%90%EC%9D%B4%ED%82%B9Tree-Shaking%EA%B3%BC-%EC%82%AC%EC%9D%B4%EB%93%9C-%EC%9D%B4%ED%8E%99%ED%8A%B8Side-Effect-%EC%89%BD%EA%B2%8C-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-xreen1bi</link>
            <guid>https://velog.io/@minjoo_huh/%ED%8A%B8%EB%A6%AC-%EC%89%90%EC%9D%B4%ED%82%B9Tree-Shaking%EA%B3%BC-%EC%82%AC%EC%9D%B4%EB%93%9C-%EC%9D%B4%ED%8E%99%ED%8A%B8Side-Effect-%EC%89%BD%EA%B2%8C-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-xreen1bi</guid>
            <pubDate>Sun, 01 Jun 2025 04:15:09 GMT</pubDate>
            <description><![CDATA[<h2 id="1-트리-쉐이킹이란-🌳✨">1. 트리 쉐이킹이란? 🌳✨</h2>
<ul>
<li><strong>트리 쉐이킹</strong>은 사용하지 않는 코드를 제거해서 최종 파일을 가볍게 만드는 기술이에요.</li>
<li>“나무(tree)를 흔들면 낙엽(leaves)이 떨어지는” 모습처럼, 코드에서도 “안 쓰는 부분만 털어내는” 과정을 생각하면 돼요.</li>
<li>ES2015 모듈(import/export) 방식을 기반으로 동작하며, 대표적인 번들러들이 이 기능을 지원해요.<ul>
<li><a href="https://webpack.js.org/guides/tree-shaking/">Webpack 4+</a></li>
<li><a href="https://rollupjs.org/guide/en/#tree-shaking">Rollup</a></li>
<li><a href="https://vitejs.dev/guide/features.html#code-splitting">Vite (내부적으로 Rollup 사용)</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="2-사이드-이펙트side-effect란-🎭">2. 사이드 이펙트(Side Effect)란? 🎭</h2>
<ul>
<li><strong>사이드 이펙트</strong>는 모듈을 불러오기만 해도 외부 상태나 화면에 변화를 일으키는 코드입니다.<ul>
<li>예를 들어, 파일을 import 하는 순간 데이터베이스에 접근하거나 전역 변수를 바꾸는 경우가 해당돼요.</li>
</ul>
</li>
<li>순수한 로직(pure function)처럼 “입력값만 가지고 결과값을 내는” 코드와 달리, 사이드 이펙트가 있으면 번들러가 “이 모듈이 필요할지도 몰라”라고 판단해서 제거하지 못할 수 있어요.<ul>
<li><a href="https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free">관련 설명</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Glossary/Side_effect">MDN – 사이드 이펙트 개념</a></li>
</ul>
</li>
</ul>
<hr>
<h2 id="3-트리-쉐이킹-장점-😊👍">3. 트리 쉐이킹 장점 😊👍</h2>
<p><strong>1. 번들 크기 줄이기</strong></p>
<ul>
<li>안 쓰는 코드를 제거해 주니까 최종 파일이 훨씬 작아져요.</li>
<li>예시: 라이브러리 중 일부 함수만 쓰면, 나머지는 배포 파일에 포함되지 않아요.</li>
</ul>
<p><strong>2. 로딩 속도 개선</strong></p>
<ul>
<li>파일 용량이 작아지면 웹페이지 로딩이 빨라져요.</li>
<li>사용자들이 “사이트가 빨리 열린다”라고 느끼면 만족도가 높아집니다.</li>
</ul>
<p><strong>3. 코드 관리의 명확성</strong></p>
<ul>
<li>어떤 코드가 실제로 사용되는지 분명해지니까, 불필요한 코드가 쌓이지 않아요.</li>
<li>협업 중에도 “이 부분은 왜 남아 있지?” 하고 쉽게 확인할 수 있습니다.</li>
</ul>
<hr>
<h2 id="4-트리-쉐이킹-단점-😅👎">4. 트리 쉐이킹 단점 😅👎</h2>
<p><strong>1. ES 모듈 방식만 지원</strong></p>
<ul>
<li>반드시 <code>import</code>/<code>export</code>를 사용해야 해요.</li>
<li>예전 <code>require</code>/<code>module.exports</code> 방식으로 작성된 코드에서는 제대로 동작하지 않을 수 있어요.</li>
</ul>
<p><strong>2. 사이드 이펙트가 있는 코드 제외 안 될 수 있음</strong></p>
<ul>
<li>코드 안에 외부를 바꾸는 동작이 있으면, 번들러가 “언제 쓰일지 몰라”라고 생각해 제거를 하지 않아요.</li>
<li>이때는 모듈을 순수 로직(pure)으로 분리하거나, <code>package.json</code>에서 사이드 이펙트 설정을 적절히 해줘야 합니다.</li>
</ul>
<p><strong>3. 설정 복잡도 증가</strong></p>
<ul>
<li><code>package.json</code>에 <code>&quot;sideEffects&quot;: false</code> 등을 적어 주어야 해요.</li>
<li>이 설정을 안 하면 번들러가 “모든 파일은 사이드 이펙트가 있을 수 있다”라고 간주해 일부 코드를 남길 수 있어요.</li>
</ul>
<hr>
<h2 id="5-사이드-이펙트-장점--단점-😊👎">5. 사이드 이펙트 장점 &amp; 단점 😊👎</h2>
<ul>
<li><p><strong>장점</strong></p>
<ul>
<li><strong>1. 필요한 동작(사이드 이펙트)을 보장</strong><ul>
<li>예를 들어, 페이지가 로드될 때 특정 설정을 초기화해야 한다면 사이드 이펙트가 꼭 필요합니다.</li>
<li>화면에 “환영합니다”를 자동으로 표시하거나 전역 상태를 세팅하는 코드가 여기에 해당해요.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>단점</strong></p>
<ul>
<li><strong>1. 트리 쉐이킹 방해</strong><ul>
<li>사이드 이펙트가 있는 모듈은 번들러가 “혹시 사용될지도 몰라”라고 남겨 놓아서 최적화에서 빠질 수 있어요.</li>
</ul>
</li>
<li><strong>2. 예측이 어려움</strong><ul>
<li>코드가 로딩되는 순간 외부 상태를 바꾸면, 언제 어떤 순서로 동작할지 정확히 알기 어렵습니다.</li>
<li>디버깅이나 유지보수가 복잡해질 수 있어요.</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="6-왜-꼭-사용해야-할까-🎯">6. 왜 꼭 사용해야 할까? 🎯</h2>
<p><strong>1. 빠르고 가벼운 웹페이지</strong></p>
<ul>
<li>트리 쉐이킹 덕분에 배포 파일 크기가 작아지고, 페이지 로딩 속도가 빨라집니다.</li>
<li>사용자들이 기다림 없이 사이트를 사용할 수 있어요.</li>
</ul>
<p><strong>2. 서버 트래픽 비용 절감</strong></p>
<ul>
<li>작은 파일을 전송하면 서버에서 소비하는 네트워크 비용도 줄어듭니다.</li>
<li>결국 비용과 시간을 모두 아낄 수 있어요.</li>
</ul>
<p><strong>3. 불필요한 코드 관리</strong></p>
<ul>
<li>프로젝트가 커지면 안 쓰는 코드가 쌓이게 되는데, 트리 쉐이킹은 자동으로 정리해 줍니다.</li>
<li>협업할 때 “이 코드 어디 쓰이는 거야?”라는 고민이 줄어듭니다.</li>
</ul>
<hr>
<h2 id="7-실제-사용-방법-🌐">7. 실제 사용 방법 🌐</h2>
<h3 id="7-1-webpack">7-1. Webpack</h3>
<ul>
<li><p><strong>프로덕션 모드</strong>(<code>mode: &quot;production&quot;</code>)로 빌드하면 자동으로 트리 쉐이킹을 시도합니다.</p>
</li>
<li><p><code>package.json</code>에 아래의 코드를 추가하면, “이 프로젝트 안에는 사이드 이펙트가 없다”라고 Webpack에 알려줘서, 쓰이지 않는 파일을 더 적극적으로 제거할 수 있어요.</p>
<pre><code class="language-json">  {
    &quot;sideEffects&quot;: false
  }</code></pre>
</li>
<li><p>공식 문서:</p>
<ul>
<li><a href="https://webpack.js.org/guides/tree-shaking/">트리 쉐이킹</a></li>
<li><a href="https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free">사이드 이펙트 설정</a></li>
</ul>
</li>
</ul>
<h3 id="7-2-rollup">7-2. Rollup</h3>
<ul>
<li>ES 모듈 기반으로 처음부터 트리 쉐이킹을 염두에 두고 설계되었습니다.</li>
<li><code>rollup.config.js</code>에서 <code>treeshake</code> 옵션을 조정하여 세부 설정이 가능합니다.</li>
<li><a href="https://rollupjs.org/guide/en/#tree-shaking">공식 문서</a></li>
</ul>
<h3 id="7-3-vite">7-3. Vite</h3>
<ul>
<li>내부적으로 Rollup을 사용하므로, Vite로 빌드할 때도 트리 쉐이킹이 자동 적용됩니다.</li>
<li><code>vite.config.js</code>에서 <code>build.rollupOptions</code> 옵션을 통해 사이드 이펙트 제외 대상 등을 설정할 수 있어요.</li>
<li><a href="https://vitejs.dev/guide/features.html#code-splitting">공식 문서</a></li>
</ul>
<hr>
<h2 id="8-정리-✨">8. 정리 ✨</h2>
<ul>
<li><strong>트리 쉐이킹</strong><ul>
<li>나무 흔들듯 “쓰지 않는 코드만 털어내는” 최적화 기술</li>
<li>장점: 파일 크기 감소, 로딩 속도 개선, 코드 관리 명확화</li>
<li>단점: ES 모듈 필요, 사이드 이펙트 포함 모듈은 제외하지 못할 수 있음</li>
</ul>
</li>
<li><strong>사이드 이펙트</strong><ul>
<li>모듈 실행 시 화면이나 데이터에 영향을 주는 행동</li>
<li>장점: 꼭 필요한 동작(예: 초기화, 로그 남기기)에 필수</li>
<li>단점: 트리 쉐이킹 방해, 예측/디버깅 어려움</li>
</ul>
</li>
<li><strong>왜 써야 할까?</strong><ol>
<li>빠르고 가벼운 웹페이지</li>
<li>서버 트래픽 비용 절감</li>
<li>불필요한 코드 자동 정리</li>
</ol>
</li>
<li><strong>참고 설정</strong><ul>
<li><code>package.json</code>에 <code>&quot;sideEffects&quot;: false</code> 또는 특정 파일만 제외 지시</li>
<li>Webpack, Rollup, Vite 등 주요 번들러에서 자동 지원</li>
</ul>
</li>
</ul>
<hr>
<h2 id="9-출처-references-📚">9. 출처 (References) 📚</h2>
<p><strong>1. Webpack 공식 문서</strong></p>
<ul>
<li><a href="https://webpack.js.org/guides/tree-shaking/">Tree Shaking</a></li>
<li><a href="https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free">Mark the file as side effect free</a></li>
</ul>
<p><strong>2. Rollup 공식 문서</strong></p>
<ul>
<li><a href="https://rollupjs.org/guide/en/#tree-shaking">Tree Shaking</a></li>
</ul>
<p><strong>3. Vite 공식 문서</strong></p>
<ul>
<li><a href="https://vitejs.dev/guide/features.html#code-splitting">Code Splitting &amp; Dynamic Imports</a></li>
</ul>
<p><strong>4. MDN – 사이드 이펙트 설명</strong></p>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Glossary/Side_effect">https://developer.mozilla.org/en-US/docs/Glossary/Side_effect</a></li>
</ul>
<p><strong>5. 블로그 아티클</strong></p>
<ul>
<li>“Practical Tree Shaking” (검색어 예시)</li>
<li>“Tree Shaking with Side Effects” (검색어 예시)</li>
</ul>
<hr>
<p>바렐(Barrel)을 공부하다가 나온 모르는 단어들을 정리해보았습니다!
이 글이 프로젝트 최적화나 웹사이트 성능 개선에 도움이 되었기를 바랍니다! 😊</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[바렐(Barrel) 파일(index.ts) 사용하기 가이드 ✨😊]]></title>
            <link>https://velog.io/@minjoo_huh/%EB%B0%94%EB%A0%90Barrel-%ED%8C%8C%EC%9D%BCindex.ts-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-%EA%B0%80%EC%9D%B4%EB%93%9C</link>
            <guid>https://velog.io/@minjoo_huh/%EB%B0%94%EB%A0%90Barrel-%ED%8C%8C%EC%9D%BCindex.ts-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-%EA%B0%80%EC%9D%B4%EB%93%9C</guid>
            <pubDate>Sun, 01 Jun 2025 03:09:06 GMT</pubDate>
            <description><![CDATA[<h2 id="1-바렐barrel이란">1. 바렐(Barrel)이란?</h2>
<ul>
<li>폴더 내부에 여러 모듈(컴포넌트, 유틸, 타입 등)을 한곳에서 재내보내기(re-export)하는 방법</li>
<li><code>index.ts</code> 파일을 “통(barrel)”처럼 만들어두면, 상위 코드에서 폴더 경로만으로 필요한 모듈을 한 번에 가져올 수 있어요 😉</li>
<li>예시<ul>
<li>폴더 구조<pre><code class="language-css">components/
Button/
      Button.tsx
      IconButton.tsx
      index.ts  ← Barrels</code></pre>
</li>
<li><code>index.ts</code> 내부<ul>
<li><code>export { default as Button } from &quot;./Button&quot;;</code><ul>
<li><code>export { default as IconButton } from &quot;./IconButton&quot;;</code></li>
</ul>
</li>
</ul>
</li>
<li>이렇게 하면 다른 파일에서<pre><code class="language-css">import { Button, IconButton } from &quot;components/Button&quot;;</code></pre>
처럼 간단하게 사용 가능 👍</li>
</ul>
</li>
</ul>
<hr>
<h2 id="2-장점-pros-😊">2. 장점 (Pros) 😊</h2>
<p><strong>1. import 문이 간결해진다</strong></p>
<ul>
<li>여러 모듈을 개별 경로로 줄줄이 적을 필요 없이, 폴더명만 써서 한 번에 가져올 수 있어요.</li>
<li>코드 가독성이 눈에 띄게 좋아집니다!</li>
</ul>
<p><strong>2. 폴더 구조가 한눈에 보인다</strong></p>
<ul>
<li><code>index.ts</code>만 보면 “이 폴더 안에 어떤 모듈이 모여 있는지” 바로 파악할 수 있어요.</li>
<li>팀원끼리 협업할 때 “어떤 컴포넌트를 써야 할지” 더 빠르게 찾을 수 있어요.</li>
</ul>
<p><strong>3. 리팩터링이 편해진다</strong></p>
<ul>
<li>파일명을 바꾸거나 새로운 파일을 추가/삭제할 때, <code>index.ts</code>만 수정하면 돼요.</li>
<li>다른 파일에서 일일이 import 경로를 고칠 필요가 없어서 효율이 올라갑니다!</li>
</ul>
<p><strong>4. 의존성 트리(Dependency Tree)가 깔끔해진다</strong></p>
<ul>
<li>번들러(예: Webpack, Vite)가 바렐을 통과해 실제 구현 모듈을 매핑하므로, 의존성 그래프가 정돈돼요.</li>
<li><strong>Tree‐shaking</strong>을 통해 사용하지 않는 코드가 번들에 포함되지 않도록 할 수 있어요.</li>
</ul>
<hr>
<h2 id="3-단점-cons-😅">3. 단점 (Cons) 😅</h2>
<p><strong>1. 바렐 파일이 너무 커질 수 있다</strong></p>
<ul>
<li>폴더 안에 모듈이 너무 많으면 <code>index.ts</code>도 길어져 관리하기 번거로워질 수 있어요.</li>
<li>“바렐이 또 다른 바렐을 가져오는” 식의 중첩 구조(바렐 체인)가 생길 위험이 있습니다.</li>
</ul>
<p><strong>2. 트리 쉐이킹(Dead Code Elimination) 주의</strong></p>
<ul>
<li><code>export * from &quot;./A&quot;;</code> 같은 방식으로 모든 걸 일괄 re‐export하면, <strong>tree‐shaking</strong>이 제대로 동작하지 않을 수 있어요</li>
<li>필요한 모듈만 정확히 export해 주지 않으면, 사용하지 않는 모듈도 번들에 포함될 가능성이 있습니다.</li>
</ul>
<p><strong>3. 순환 참조(Circular Dependency) 위험</strong></p>
<ul>
<li>서로 다른 바렐끼리 재내보내기를 하게 되면 순환 의존성이 발생할 수 있어요.</li>
<li>예측하지 못한 에러가 나거나 빌드가 중단될 수 있으니 주의해야 합니다.</li>
</ul>
<p><strong>4. 바렐에만 의존 경로가 집중됨</strong></p>
<ul>
<li>모듈 간 의존 순서가 바렐 내부에 숨어 있으면, 디버깅이 어려워질 수 있어요.</li>
<li>특정 모듈이 <strong>사이드 이펙트(side effect)</strong> 를 실행해야 하는 상황에서는, 바렐을 타고 순서가 뒤바뀌면 문제가 생길 수 있습니다.</li>
</ul>
<hr>
<h2 id="4-주의할-점--베스트-프랙티스-cautions--best-practices-⚠️">4. 주의할 점 &amp; 베스트 프랙티스 (Cautions &amp; Best Practices) ⚠️</h2>
<p><strong>1. 바렐 크기 관리</strong></p>
<ul>
<li>폴더 안에 5~10개 정도의 관련 모듈이 있을 때 바렐을 만드는 것이 적당해요.</li>
<li>너무 많은 모듈을 한 번에 묶으면 가독성과 유지보수가 오히려 어려워집니다.</li>
</ul>
<p><strong>2. 명시적 재내보내기(explicit export)</strong></p>
<ul>
<li><p><code>export * from &quot;./SomeModule&quot;;</code> 대신</p>
<pre><code class="language-typescript">  export { default as SomeModule } from &quot;./SomeModule&quot;;  
  export type { SomeType } from &quot;./SomeModule&quot;;  </code></pre>
<p>와 같이 <strong>개별 export</strong>를 사용하면, <strong>tree‐shaking</strong>이 더 잘 동작해요.</p>
</li>
<li><p>사용하지 않는 코드는 번들에서 제외되도록, 불필요한 모듈을 최대한 배제합시다.</p>
</li>
</ul>
<p><strong>3. 순환 참조(Avoid Circular Dependency)</strong></p>
<ul>
<li>바렐끼리 서로 참조하지 않도록 신경 써야 합니다.</li>
<li>“이 폴더의 <code>index.ts</code>는 같은 폴더 내부의 모듈만 재내보낸다”는 원칙을 지키면 순환 의존성 문제를 피할 수 있어요.</li>
</ul>
<p><strong>4. 폴더/파일 네이밍 일관성</strong></p>
<ul>
<li>폴더마다 동일한 네이밍 컨벤션(단수형 vs 복수형 등)을 사용하여 헷갈리지 않도록 해요.</li>
<li>예: <pre><code class="language-css">  components/
    Button/
      Button.tsx
      IconButton.tsx
      index.ts</code></pre>
이런 식으로 네이밍하면 누구나 구조를 쉽게 이해할 수 있어요.</li>
</ul>
<p><strong>5. 번들러 설정 확인</strong></p>
<ul>
<li><code>package.json</code>에 <code>&quot;sideEffects&quot;: false</code> 옵션을 추가하거나, Webpack/Rollup/Vite 설정에서 <strong>tree‐shaking</strong> 관련 옵션을 확인해 주세요.</li>
<li>그렇지 않으면 의도하지 않은 코드가 번들에 포함될 수 있습니다.</li>
</ul>
<hr>
<h2 id="5-실무-적용-예시-examples-🌟">5. 실무 적용 예시 (Examples) 🌟</h2>
<h3 id="5-1-컴포넌트-바렐">5-1. 컴포넌트 바렐</h3>
<ul>
<li><p><strong>폴더 구조</strong></p>
<pre><code class="language-css">src/
components/
  Button/
    Button.tsx
    IconButton.tsx
    MenuButton.tsx
    index.ts
  Modal/
    BaseModal.tsx
    ConfirmModal.tsx
    index.ts</code></pre>
</li>
<li><p><code>components/Button/index.ts</code></p>
<pre><code class="language-typescript">  export { default as Button } from &quot;./Button&quot;;
  export type { ButtonProps } from &quot;./Button&quot;;

  export { default as IconButton } from &quot;./IconButton&quot;;
  export type { IconButtonProps } from &quot;./IconButton&quot;;

  export { default as MenuButton } from &quot;./MenuButton&quot;;
  export type { MenuButtonProps } from &quot;./MenuButton&quot;;</code></pre>
</li>
<li><p><strong>사용 예시</strong></p>
<pre><code class="language-typescript">  // Before
  import Button from &quot;components/Button/Button&quot;;
  import IconButton from &quot;components/Button/IconButton&quot;;

  // After
  import { Button, IconButton } from &quot;components/Button&quot;;</code></pre>
</li>
</ul>
<hr>
<h3 id="5-2-타입-바렐">5-2. 타입 바렐</h3>
<ul>
<li><strong>폴더 구조</strong><pre><code>  src/
    types/
      User.ts
       Post.ts
        Comment.ts
        index.ts</code></pre></li>
<li><code>types/index.ts</code><pre><code class="language-javascript">export * from &quot;./User&quot;;
export * from &quot;./Post&quot;;
export * from &quot;./Comment&quot;;</code></pre>
</li>
<li><strong>사용 예시</strong><pre><code class="language-javascript">import { User, Post, Comment } from &quot;types&quot;;</code></pre>
</li>
</ul>
<hr>
<h2 id="6-장점-vs-단점-한눈에-정리-👍👎">6. 장점 vs 단점 한눈에 정리 👍👎</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>가독성</td>
<td>- import 문이 간결해지며 코드가 깔끔해집니다.</td>
<td>- 바렐 파일 자체가 비대해지면 관리하기 어려워집니다.</td>
</tr>
<tr>
<td>유지보수</td>
<td>- 파일명 변경, 모듈 추가/삭제 시 <code>index.ts</code>만 수정하면 됩니다.</td>
<td>- 잘못 구성된 바렐은 순환 의존성(circular dependency)을 유발할 수 있습니다.</td>
</tr>
<tr>
<td>의존성 관리</td>
<td>- 번들러가 의존성 트리를 깔끔하게 정리해 줍니다.</td>
<td>- <code>export * from ...</code> 방식으로 모든 걸 re-export하면 tree-shakng이 제대로 안 될 수 있습니다.</td>
</tr>
<tr>
<td>리팩터링</td>
<td>- 필요한 모듈만 올바로 export해 두면 번들 크기가 줄어듭니다.</td>
<td>- 사이드 이팩트(side effect)가 있는 모듈을 바렐을 통해 잘못 로딩하면 예기치 않은 버그가 발생할 수 있습니다.</td>
</tr>
</tbody></table>
<hr>
<h2 id="7-주의할-점-다시-한번-⚠️">7. 주의할 점 다시 한번! ⚠️</h2>
<ul>
<li>바렐을 “만드는 목적”은 <strong>편리함과 가독성 향상</strong>이지, 무턱대고 모든 모듈을 한곳에 몰아넣으라는 뜻이 아닙니다.</li>
<li>“폴더마다 관련 모듈을 5~10개 내외로 묶어두는” 정도가 적당하며, 그 이상이라면 폴더를 더 잘게 쪼개거나 바렐 범위를 좁혀보세요.</li>
<li>번들러 설정(특히 t<strong>ree‐shaking, sideEffects</strong> 옵션)과 <strong>순환 참조</strong> 여부를 꼼꼼히 점검해야 합니다.</li>
</ul>
<hr>
<h2 id="8-참고-자료-references-📚">8. 참고 자료 (References) 📚</h2>
<p><strong>1. TypeScript 공식 문서</strong></p>
<ul>
<li><a href="https://www.typescriptlang.org/docs/handbook/module-resolution.html">Module Resolution</a></li>
<li><a href="https://www.typescriptlang.org/docs/handbook/declaration-merging.html#barrel-files">Declaration Merging &amp; Barrel Files</a></li>
</ul>
<p><strong>2. Webpack 공식 문서</strong></p>
<ul>
<li><a href="https://webpack.js.org/guides/tree-shaking/">Tree Shaking</a></li>
<li><a href="https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free">Side Effects</a></li>
</ul>
<p><strong>3. Vite 공식 문서</strong></p>
<ul>
<li><a href="https://vitejs.dev/guide/dep-pre-bundling.html">Dependency Pre-Bundling</a></li>
<li><a href="https://vitejs.dev/guide/features.html#code-splitting">Code Splitting &amp; Dynamic Imports</a></li>
</ul>
<p><strong>4. 블로그/아티클</strong></p>
<ul>
<li>“Barrel Files in TypeScript” by Basarat Ali Syed</li>
<li>“Organizing Modules with Barrels” from Practical TypeScript Tutorial</li>
</ul>
<hr>
<p>✨ 정리 끝! ✨
바렐 패턴을 적절히 활용하면 import 문이 깔끔해지고, 유지보수·리팩터링이 한결 수월해집니다.
하지만 과도한 바렐 사용이나 순환 의존성, tree‐shaking 누락 등에 주의하면서 상황에 맞게 적용하세요! 😎🛠</p>
<p>Happy Coding! 🚀</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[💡 CSS 100vh vs 100% 제대로 이해하고 쓰기]]></title>
            <link>https://velog.io/@minjoo_huh/CSS-100vh-vs-100-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B3%A0-%EC%93%B0%EA%B8%B0</link>
            <guid>https://velog.io/@minjoo_huh/CSS-100vh-vs-100-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B3%A0-%EC%93%B0%EA%B8%B0</guid>
            <pubDate>Fri, 30 May 2025 14:24:30 GMT</pubDate>
            <description><![CDATA[<p>CSS에서 높이를 설정할 때 가장 자주 쓰는 단위인 <code>100vh</code>와 <code>100%</code>.
비슷해 보이지만 둘은 동작 방식이 완전히 다릅니다.</p>
<p>이번 글에서는 <strong><code>100vh</code>와 <code>100%</code>의 차이</strong>,
<strong>예제 코드</strong>, <strong>실제 동작 방식</strong>,
그리고 <strong>자주 하는 실수와 해결법</strong>까지 모두 정리해볼게요!</p>
<hr>
<h2 id="✅-1-100vh란">✅ 1. <code>100vh</code>란?</h2>
<p><code>vh</code>는 <strong>Viewport Height</strong>의 약자로, 브라우저 화면 높이 기준입니다.</p>
<ul>
<li><code>100vh</code> = <strong>브라우저 화면 전체 높이</strong></li>
<li><code>50vh</code> = <strong>브라우저 화면의 절반 높이</strong></li>
</ul>
<pre><code class="language-css">.section {
  height: 100vh;
}</code></pre>
<p>📌 위 코드는 <code>.section</code> 요소를 <strong>브라우저 화면 전체 높이</strong>만큼 채웁니다.</p>
<hr>
<h2 id="✅-2-100란">✅ 2. <code>100%</code>란?</h2>
<p><code>100%</code>는 <strong>부모 요소의 높이</strong>를 기준으로 동작합니다.</p>
<pre><code class="language-css">.parent {
  height: 500px;
}

.child {
  height: 100%;
}</code></pre>
<p>📌 이 경우 <code>.child</code>는 정확히 <code>500px</code> 높이가 됩니다.</p>
<blockquote>
<p>❗ 주의: 부모 요소에 <code>height</code>가 없으면, <code>100%</code>는 아무 효과가 없습니다.</p>
</blockquote>
<hr>
<h2 id="🔍-비교-요약">🔍 비교 요약</h2>
<table>
<thead>
<tr>
<th>속성</th>
<th>기준</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td><code>100vh</code></td>
<td>브라우저 창</td>
<td>항상 정확하게 적용됨</td>
</tr>
<tr>
<td><code>100%</code></td>
<td>부모 요소</td>
<td>부모가 <code>height</code>를 가져야 적용 가능</td>
</tr>
</tbody></table>
<hr>
<h2 id="🧪-실전-예제-비교">🧪 실전 예제 비교</h2>
<h3 id="예제-html">예제 HTML</h3>
<pre><code class="language-html">&lt;div class=&quot;wrapper&quot;&gt;
  &lt;div class=&quot;box&quot;&gt;&lt;/div&gt;
&lt;/div&gt;</code></pre>
<h3 id="①-height-100vh">① <code>height: 100vh</code></h3>
<pre><code class="language-css">.box {
  height: 100vh;
  background: skyblue;
}</code></pre>
<p>🟢 결과: <code>.box</code>는 브라우저 높이만큼 정확하게 채워짐</p>
<hr>
<h3 id="②-height-100-부모-높이-없음">② <code>height: 100%</code> (부모 높이 없음)</h3>
<pre><code class="language-css">.wrapper {
  background: lightgray;
}

.box {
  height: 100%;
  background: red;
}</code></pre>
<p>🔴 결과: <code>.wrapper</code>가 <code>height</code>가 없기 때문에, <code>.box</code>는 <strong>높이가 0</strong> → 보이지 않음</p>
<hr>
<h3 id="③-height-100-부모-높이-있음">③ <code>height: 100%</code> (부모 높이 있음)</h3>
<pre><code class="language-css">.wrapper {
  height: 400px;
}

.box {
  height: 100%;
  background: red;
}</code></pre>
<p>🟢 결과: <code>.box</code>는 <code>400px</code> 높이로 정확히 적용됨</p>
<hr>
<h2 id="💡-추가-팁-위치와-높이는-다르다">💡 추가 팁: 위치와 높이는 다르다!</h2>
<pre><code class="language-css">.box {
  height: 100vh;
  margin-top: 40px;
}</code></pre>
<p>📌 이 코드는 <strong>높이 100vh</strong>인 박스를 <strong>위에서 40px 아래에 위치</strong>시킵니다.</p>
<p>즉, 실제 위치는 <strong>40px ~ 840px</strong>이 되죠.
<code>vh</code>는 <strong>크기</strong>일 뿐, <strong>시작 위치를 의미하지는 않습니다</strong>.</p>
<hr>
<h2 id="❌-자주-하는-실수">❌ 자주 하는 실수</h2>
<pre><code class="language-css">/* ❌ 잘못된 예시 */
height: 100vh - 1rem;</code></pre>
<ul>
<li>이렇게는 CSS가 인식하지 못해 <strong>무시</strong>됩니다.</li>
</ul>
<h4 id="✅-올바른-방법은-calc-사용">✅ 올바른 방법은 calc() 사용!</h4>
<pre><code class="language-css">/* ✅ 제대로 된 예시 */
height: calc(100vh - 1rem);</code></pre>
<hr>
<h2 id="🎯-언제-뭘-써야-할까">🎯 언제 뭘 써야 할까?</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>추천 속성</th>
</tr>
</thead>
<tbody><tr>
<td>화면 전체를 채우고 싶을 때</td>
<td><code>100vh</code></td>
</tr>
<tr>
<td>부모 요소와 같은 높이로 맞추고 싶을 때</td>
<td><code>100%</code> (단, 부모가 <code>height</code>를 가질 때만)</td>
</tr>
<tr>
<td>뷰포트에서 특정 영역만 제외하고 싶을 때</td>
<td><code>calc(100vh - xxx)</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="✅-마무리-요약">✅ 마무리 요약</h2>
<table>
<thead>
<tr>
<th>속성</th>
<th>기준</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td><code>100vh</code></td>
<td>브라우저 화면 전체</td>
<td>항상 일정한 높이 보장</td>
</tr>
<tr>
<td><code>100%</code></td>
<td>부모 요소의 높이</td>
<td>부모가 <code>height</code>를 설정해야 의미 있음</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[📚 HTML5 시맨틱 태그 완전 정복]]></title>
            <link>https://velog.io/@minjoo_huh/HTML5-%EC%8B%9C%EB%A7%A8%ED%8B%B1-%ED%83%9C%EA%B7%B8-%EC%99%84%EC%A0%84-%EC%A0%95%EB%B3%B5</link>
            <guid>https://velog.io/@minjoo_huh/HTML5-%EC%8B%9C%EB%A7%A8%ED%8B%B1-%ED%83%9C%EA%B7%B8-%EC%99%84%EC%A0%84-%EC%A0%95%EB%B3%B5</guid>
            <pubDate>Fri, 30 May 2025 13:03:25 GMT</pubDate>
            <description><![CDATA[<h2 id="🧠-시맨틱-태그란">🧠 시맨틱 태그란?</h2>
<p><strong>시맨틱(Semantic)</strong>이란 &quot;의미론적인&quot;이라는 뜻이에요.
즉, <strong>시맨틱 태그(Semantic Tag)</strong>는 <strong>&quot;이 태그가 어떤 역할을 하는지 그 이름만 보고도 알 수 있도록 만든 HTML 태그&quot;</strong>를 의미해요.</p>
<p>과거에는 <code>&lt;div&gt;</code>, <code>&lt;span&gt;</code> 같은 <strong>의미 없는 태그</strong>만 써서 모든 구조를 만들었지만,
HTML5부터는 구조를 <strong>더 명확하게 설명</strong>하기 위해 <code>&lt;header&gt;</code>, <code>&lt;main&gt;</code>, <code>&lt;section&gt;</code>, <code>&lt;article&gt;</code>, <code>&lt;nav&gt;</code>, <code>&lt;aside&gt;</code> 같은 시맨틱 태그가 도입되었어요.</p>
<hr>
<h2 id="🔍-왜-시맨틱-태그를-사용할까">🔍 왜 시맨틱 태그를 사용할까?</h2>
<table>
<thead>
<tr>
<th>이유</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>✅ 의미 전달</td>
<td>코드만 봐도 어떤 역할을 하는지 알 수 있어요</td>
</tr>
<tr>
<td>✅ SEO 향상</td>
<td>검색 엔진이 구조를 더 잘 이해할 수 있어요</td>
</tr>
<tr>
<td>✅ 접근성 향상</td>
<td>스크린 리더 등의 보조 기기가 의미를 파악할 수 있어요</td>
</tr>
<tr>
<td>✅ 유지보수 편리</td>
<td>개발자나 협업자들이 코드를 이해하기 쉬워요</td>
</tr>
</tbody></table>
<hr>
<p>이제 본격적으로 자주 사용하는 시맨틱 태그들을 하나씩 살펴볼게요!</p>
<hr>
<h2 id="✅-1-main">✅ 1. <code>&lt;main&gt;</code></h2>
<h3 id="✔-정의">✔ 정의</h3>
<p>웹페이지의 <strong>주요 콘텐츠 영역</strong>을 나타내요.
페이지마다 <strong>하나만 존재해야 하며</strong>, 사이트 전체에서 공통으로 반복되는 헤더, 네비게이션, 푸터 등은 포함하지 않아요.</p>
<h3 id="✔-사용-예시">✔ 사용 예시</h3>
<pre><code>&lt;main&gt;
  &lt;h1&gt;HTML 시맨틱 태그란?&lt;/h1&gt;
  &lt;p&gt;시맨틱 태그는 의미를 갖는 태그입니다...&lt;/p&gt;
&lt;/main&gt;</code></pre><h3 id="✔-어디에-사용될까">✔ 어디에 사용될까?</h3>
<ul>
<li>블로그 본문</li>
<li>기사 내용</li>
<li>제품 상세 정보</li>
<li>서비스 소개 페이지의 핵심 설명</li>
</ul>
<hr>
<h2 id="✅-2-section">✅ 2. <code>&lt;section&gt;</code></h2>
<h3 id="✔-정의-1">✔ 정의</h3>
<p><strong>하나의 주제(topic)</strong> 또는 <strong>기능 단위</strong>를 묶는 구획이에요.
보통 제목(<code>&lt;h1&gt;</code>~<code>&lt;h6&gt;</code>)을 포함하며, 논리적으로 관련된 콘텐츠 덩어리에 사용해요.</p>
<h3 id="✔-사용-예시-1">✔ 사용 예시</h3>
<pre><code>&lt;section&gt;
  &lt;h2&gt;시맨틱 태그의 장점&lt;/h2&gt;
  &lt;p&gt;접근성과 SEO에 유리합니다...&lt;/p&gt;
&lt;/section&gt;</code></pre><h3 id="✔-어디에-사용될까-1">✔ 어디에 사용될까?</h3>
<ul>
<li>블로그에서 &quot;관련 글&quot;, &quot;댓글&quot;, &quot;작성자 소개&quot; 구역</li>
<li>포트폴리오에서 &quot;프로젝트 목록&quot;, &quot;기술 스택&quot; 구역</li>
<li>메인 페이지에서 각각의 배너나 섹션 단위</li>
</ul>
<hr>
<h2 id="✅-3-article">✅ 3. <code>&lt;article&gt;</code></h2>
<h3 id="✔-정의-2">✔ 정의</h3>
<p><strong>독립적으로 구분 가능한 콘텐츠 단위</strong>에 사용돼요.
그 자체로 의미를 갖고, 외부에 <strong>단독 발행</strong>이 가능한 콘텐츠에 적합해요.</p>
<h3 id="✔-사용-예시-2">✔ 사용 예시</h3>
<pre><code>&lt;article&gt;
  &lt;h2&gt;HTML5란?&lt;/h2&gt;
  &lt;p&gt;HTML5는 최신 웹 표준입니다...&lt;/p&gt;
&lt;/article&gt;</code></pre><h3 id="✔-어디에-사용될까-2">✔ 어디에 사용될까?</h3>
<ul>
<li>블로그 글 하나</li>
<li>뉴스 기사</li>
<li>게시판 글</li>
<li>제품 리뷰, 유저 후기</li>
</ul>
<hr>
<h2 id="✅-4-nav">✅ 4. <code>&lt;nav&gt;</code></h2>
<h3 id="✔-정의-3">✔ 정의</h3>
<p><strong>내비게이션 링크 집합</strong>을 나타내요.
웹사이트의 메뉴, 목차, 페이지 이동 등 <strong>사용자 이동을 위한 링크 그룹</strong>에 사용해요.</p>
<h3 id="✔-사용-예시-3">✔ 사용 예시</h3>
<pre><code>&lt;nav&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;/&quot;&gt;홈&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;/blog&quot;&gt;블로그&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;/contact&quot;&gt;문의&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;</code></pre><h3 id="✔-어디에-사용될까-3">✔ 어디에 사용될까?</h3>
<ul>
<li>사이트 상단 메뉴 바</li>
<li>사이드 메뉴바</li>
<li>문서의 목차 영역</li>
</ul>
<hr>
<h2 id="✅-5-aside">✅ 5. <code>&lt;aside&gt;</code></h2>
<h3 id="✔-정의-4">✔ 정의</h3>
<p><strong>보조적인 콘텐츠 영역</strong>이에요.
메인 콘텐츠와 직접적인 연결은 없지만, 관련 있거나 부가적인 정보를 제공하는 데 사용돼요.</p>
<h3 id="✔-사용-예시-4">✔ 사용 예시</h3>
<pre><code>&lt;aside&gt;
  &lt;h3&gt;관련 글&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;HTML5 기본 구조&lt;/li&gt;
    &lt;li&gt;CSS 모듈이란?&lt;/li&gt;
  &lt;/ul&gt;
&lt;/aside&gt;</code></pre><h3 id="✔-어디에-사용될까-4">✔ 어디에 사용될까?</h3>
<ul>
<li>블로그의 관련 글, 광고, 인기 글 목록</li>
<li>뉴스 사이트의 작가 소개</li>
<li>기술문서에서 태그 목록, 참고 링크</li>
</ul>
<hr>
<h2 id="🎯-시맨틱-태그-요약-비교표">🎯 시맨틱 태그 요약 비교표</h2>
<table>
<thead>
<tr>
<th>태그</th>
<th>용도</th>
<th>특징</th>
<th>대표 사용 위치</th>
</tr>
</thead>
<tbody><tr>
<td><code>&lt;main&gt;</code></td>
<td>주요 콘텐츠</td>
<td>페이지당 1개만</td>
<td>본문, 핵심 콘텐츠</td>
</tr>
<tr>
<td><code>&lt;section&gt;</code></td>
<td>주제별 구획</td>
<td>제목 포함됨</td>
<td>페이지 단위 구간</td>
</tr>
<tr>
<td><code>&lt;article&gt;</code></td>
<td>독립적인 콘텐츠</td>
<td>단독 발행 가능</td>
<td>블로그 글, 게시물</td>
</tr>
<tr>
<td><code>&lt;nav&gt;</code></td>
<td>내비게이션 링크</td>
<td>링크 집합</td>
<td>메뉴바, 목차</td>
</tr>
<tr>
<td><code>&lt;aside&gt;</code></td>
<td>보조 콘텐츠</td>
<td>참고/광고/연관 내용</td>
<td>사이드바, 관련 글</td>
</tr>
</tbody></table>
<hr>
<h2 id="✍️-마무리-한-마디">✍️ 마무리 한 마디</h2>
<p>시맨틱 태그는 <strong>단지 태그의 이름만 바꾸는 게 아니라,</strong>
<strong>의미를 명확히 하여 검색엔진 최적화(SEO)</strong>와 <strong>접근성 향상</strong>에도 큰 도움을 줍니다.</p>
<p>정확한 의미를 이해하고 적절한 위치에 사용하면,
<strong>구조적으로 탄탄하고 유지보수하기 쉬운 웹페이지</strong>를 만들 수 있어요! 💪</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🎯 React Router에서 Router는 왜 index.tsx에 있어야 할까?]]></title>
            <link>https://velog.io/@minjoo_huh/React-Router%EC%97%90%EC%84%9C-Router%EB%8A%94-%EC%99%9C-index.tsx%EC%97%90-%EC%9E%88%EC%96%B4%EC%95%BC-%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@minjoo_huh/React-Router%EC%97%90%EC%84%9C-Router%EB%8A%94-%EC%99%9C-index.tsx%EC%97%90-%EC%9E%88%EC%96%B4%EC%95%BC-%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Thu, 29 May 2025 05:17:36 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>useLocation 훅을 사용하려는데 자꾸 에러가 난다면, Router 위치를 의심해보세요!</p>
</blockquote>
<hr>
<h2 id="🧩-문제-상황">🧩 문제 상황</h2>
<p>React 프로젝트에서 다음처럼 <code>AppRouter</code> 내부에서 <code>useLocation()</code>을 사용하면서 <code>Router</code>까지 함께 선언하는 경우:</p>
<pre><code>import { Router, useLocation } from &quot;react-router-dom&quot;;

const AppRouter = () =&gt; {
  const location = useLocation(); // ❌ 여기서 에러 발생!

  return (
    &lt;Router&gt;
      {/* Routes 구성 */}
    &lt;/Router&gt;
  );
};
</code></pre><p>이럴 때 다음과 같은 오류가 발생합니다:</p>
<blockquote>
<p>❗<code>useLocation()</code> must be used within a <code>&lt;Router&gt;</code> component</p>
</blockquote>
<hr>
<h2 id="✅-이유-uselocation은-router의-자식-컴포넌트여야-동작">✅ 이유: useLocation은 Router의 자식 컴포넌트여야 동작</h2>
<p>React Router의 모든 훅들 (<code>useLocation</code>, <code>useNavigate</code>, <code>useParams</code> 등)은 내부적으로 <code>Router Context</code>를 참조합니다.
즉, 이 훅들이 정상 작동하려면 반드시 <strong>Router 컴포넌트 아래(자식)</strong>에서 호출돼야 해요.</p>
<hr>
<h2 id="✅-해결-방법">✅ 해결 방법</h2>
<h3 id="🔧-router는-indextsx에-approuter는-경로-구성만">🔧 Router는 index.tsx에, AppRouter는 경로 구성만</h3>
<h3 id="📁-indextsx-또는-maintsx">📁 index.tsx (또는 main.tsx)</h3>
<pre><code>import React from &quot;react&quot;;
import ReactDOM from &quot;react-dom/client&quot;;
import { BrowserRouter } from &quot;react-router-dom&quot;;
import AppRouter from &quot;./AppRouter&quot;;

const root = ReactDOM.createRoot(document.getElementById(&quot;root&quot;)!);
root.render(
  &lt;React.StrictMode&gt;
    &lt;BrowserRouter&gt;
      &lt;AppRouter /&gt;
    &lt;/BrowserRouter&gt;
  &lt;/React.StrictMode&gt;
);
</code></pre><h3 id="📁-approutertsx">📁 AppRouter.tsx</h3>
<pre><code>import { Routes, Route, useLocation } from &quot;react-router-dom&quot;;
import Header from &quot;./components/common/Header&quot;;
import StudyRoomHeader from &quot;./components/studyRoom/StudyRoomHeader&quot;;
import HomePage from &quot;./pages/HomePage&quot;;
import StudyRoomPage from &quot;./pages/StudyRoomPage&quot;;

const AppRouter = () =&gt; {
  const location = useLocation();
  const isStudyRoom = location.pathname.startsWith(&quot;/study-room&quot;);

  return (
    &lt;&gt;
      {isStudyRoom ? &lt;StudyRoomHeader /&gt; : &lt;Header /&gt;}
      &lt;Routes&gt;
        &lt;Route path=&quot;/&quot; element={&lt;HomePage /&gt;} /&gt;
        &lt;Route path=&quot;/study-room&quot; element={&lt;StudyRoomPage /&gt;} /&gt;
      &lt;/Routes&gt;
    &lt;/&gt;
  );
};

export default AppRouter;
</code></pre><hr>
<h2 id="❓-그럼-uselocation을-안-쓰면-router를-어디에-둬도-되는-걸까">❓ 그럼 useLocation을 안 쓰면 Router를 어디에 둬도 되는 걸까?</h2>
<blockquote>
<p>✔️ 맞습니다.</p>
</blockquote>
<p>만약 <code>AppRouter</code> 내부에서 <code>useLocation()</code>이나 <code>useNavigate()</code>, <code>useParams()</code> 같은 훅을 전혀 사용하지 않는다면,
<code>Router</code>를 <code>AppRouter</code> 안에 두더라도 <strong>기술적으로는 에러가 나지 않습니다.</strong></p>
<p>하지만 이건 <strong>우연히 작동하는 것처럼 보일 뿐</strong>, 다음과 같은 단점이 있습니다:</p>
<hr>
<h2 id="🚫-내부에서-router를-선언하면-생기는-문제점">🚫 내부에서 Router를 선언하면 생기는 문제점</h2>
<table>
<thead>
<tr>
<th>문제</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>❌ 위치 부적절</td>
<td>라우팅 환경과 구조를 한 컴포넌트에 섞게 됨</td>
</tr>
<tr>
<td>❌ 유지보수 어려움</td>
<td>추후 <code>useLocation</code> 사용 시 다시 구조 변경해야 함</td>
</tr>
<tr>
<td>❌ 컨텍스트 중첩 오류</td>
<td>중첩된 Router나 미묘한 버그 유발 가능</td>
</tr>
</tbody></table>
<hr>
<h2 id="✅-구조를-나누는-게-좋은-이유">✅ 구조를 나누는 게 좋은 이유</h2>
<table>
<thead>
<tr>
<th>장점</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>✅ 안정성</td>
<td>모든 라우터 훅들이 안전하게 작동</td>
</tr>
<tr>
<td>✅ 역할 분리</td>
<td><code>index.tsx</code> → 환경 제공, <code>AppRouter.tsx</code> → 경로 구성</td>
</tr>
<tr>
<td>✅ 확장성</td>
<td>이후 <code>Layout</code>, <code>AuthRoute</code> 추가하기 쉬움</td>
</tr>
<tr>
<td>✅ 예측 가능</td>
<td>동작 위치가 명확하므로 디버깅이 쉬움</td>
</tr>
</tbody></table>
<hr>
<h2 id="🧠-정리">🧠 정리</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>Router 위치</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>useLocation()</code> 사용함</td>
<td><code>index.tsx</code> (최상단)</td>
<td>반드시 필요</td>
</tr>
<tr>
<td>아무 훅도 사용 안 함</td>
<td>내부에 둬도 에러 없음</td>
<td>그러나 비추천</td>
</tr>
</tbody></table>
<hr>
<h2 id="✨-결론">✨ 결론</h2>
<blockquote>
<p><strong>“Hook을 쓰려면, 그 Hook을 인식할 수 있는 환경 안에 있어야 한다.”</strong></p>
</blockquote>
<p><code>React Router</code>의 훅을 쓰고 싶다면 반드시 <code>Router</code>는 컴포넌트 외부, 보통은 <code>index.tsx</code>에 위치해야 합니다.
그렇지 않으면 훅은 작동하지 않거나 에러가 발생합니다.
안 쓰더라도 미래를 생각해 구조를 나눠두는 것이 더 좋은 선택입니다. 🌱</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[📘 React.FC란 무엇인가? – TypeScript에서의 사용과 장단점 정리]]></title>
            <link>https://velog.io/@minjoo_huh/React.FC%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-TypeScript%EC%97%90%EC%84%9C%EC%9D%98-%EC%82%AC%EC%9A%A9%EA%B3%BC-%EC%9E%A5%EB%8B%A8%EC%A0%90-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@minjoo_huh/React.FC%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-TypeScript%EC%97%90%EC%84%9C%EC%9D%98-%EC%82%AC%EC%9A%A9%EA%B3%BC-%EC%9E%A5%EB%8B%A8%EC%A0%90-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 23 May 2025 15:59:55 GMT</pubDate>
            <description><![CDATA[<p>React와 TypeScript를 함께 사용할 때, 흔히 보게 되는 타입이 하나 있다. 바로 <code>React.FC</code> 또는 <code>React.FunctionComponent</code>이다.
이 글에서는 <code>React.FC</code>가 무엇인지, 어떤 역할을 하는지, 실제 현업에서는 어떤 방식을 선호하는지, 그리고 구체적인 예시를 통해 정리해보자.</p>
<hr>
<h2 id="✅-1-reactfc란">✅ 1. React.FC란?</h2>
<p><code>React.FC</code>는 <strong>Function Component의 타입 정의</strong>를 도와주는 제네릭(Generic) 타입이다.
즉, 컴포넌트가 어떤 props를 받을지 명시할 수 있도록 도와주는 <strong>타입 도우미</strong>라고 이해하면 된다.</p>
<pre><code>type Props = {
  name: string;
};

const Hello: React.FC&lt;Props&gt; = ({ name }) =&gt; {
  return &lt;div&gt;Hello, {name}&lt;/div&gt;;
};
</code></pre><p>위 코드에서 <code>Hello</code> 컴포넌트는 <code>name</code>이라는 문자열 props를 받으며, <code>React.FC&lt;Props&gt;</code>를 통해 이 타입을 명시하고 있다.</p>
<hr>
<h2 id="🧠-2-typescript에서-reactfc가-하는-일">🧠 2. TypeScript에서 React.FC가 하는 일</h2>
<ul>
<li>Function Component로 정의<ul>
<li>컴포넌트가 함수형이라는 것을 타입으로 명확하게 알려줌</li>
</ul>
</li>
<li>children을 자동 포함<ul>
<li>props.children이 자동으로 타입에 포함되어 따로 명시하지 않아도 사용 가능</li>
</ul>
</li>
<li>반환값을 ReactElement로 고정<ul>
<li>컴포넌트가 JSX 또는 ReactNode를 반환하는 것을 타입으로 보장함</li>
</ul>
</li>
</ul>
<hr>
<h2 id="⚖️-3-reactfc의-장단점">⚖️ 3. React.FC의 장단점</h2>
<h3 id="✅-장점">✅ 장점</h3>
<table>
<thead>
<tr>
<th>장점</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>🔹 <code>children</code> 자동 포함</td>
<td>컴포넌트 내부에서 <code>props.children</code>을 바로 사용할 수 있음</td>
</tr>
<tr>
<td>🔹 명시적인 반환 타입</td>
<td><code>ReactElement</code>를 반환하는 걸 보장해줌</td>
</tr>
<tr>
<td>🔹 초기 학습자에게 직관적</td>
<td>한눈에 &quot;이건 함수형 컴포넌트야&quot;라는 걸 알 수 있음</td>
</tr>
</tbody></table>
<h3 id="❌-단점">❌ 단점</h3>
<table>
<thead>
<tr>
<th>단점</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>🔸 <code>children</code> 자동 포함으로 인한 오류</td>
<td>사용하지 않는 컴포넌트에도 <code>children</code>이 허용됨 (실수 가능)</td>
</tr>
<tr>
<td>🔸 제너릭 사용 제약</td>
<td><code>&lt;T&gt;</code> 등의 제너릭을 적용하기가 번거로움</td>
</tr>
<tr>
<td>🔸 함수의 반환값 타입을 중복 명시</td>
<td>TypeScript가 추론 가능한 값을 굳이 명시할 필요 없음</td>
</tr>
</tbody></table>
<hr>
<h2 id="🆚-4-reactfc-vs-명시적-props-타입">🆚 4. React.FC vs 명시적 Props 타입</h2>
<h3 id="✅-reactfc-방식">✅ React.FC 방식</h3>
<pre><code>type Props = {
  name: string;
};

const MyComponent: React.FC&lt;Props&gt; = (props) =&gt; {
  return &lt;div&gt;{props.name}&lt;/div&gt;;
};
</code></pre><h3 id="✅-명시적-타입-방식-권장되는-추세">✅ 명시적 타입 방식 (권장되는 추세)</h3>
<pre><code>type Props = {
  name: string;
};

const MyComponent = ({ name }: Props) =&gt; {
  return &lt;div&gt;{name}&lt;/div&gt;;
};
</code></pre><hr>
<h2 id="🔍-5-어느-방식이-더-좋은가">🔍 5. 어느 방식이 더 좋은가?</h2>
<table>
<thead>
<tr>
<th>기준</th>
<th>React.FC</th>
<th>직접 타입 명시</th>
</tr>
</thead>
<tbody><tr>
<td><code>children</code> 자동 포함</td>
<td>✅ O</td>
<td>❌ 명시 필요</td>
</tr>
<tr>
<td>타입 추론 유연성</td>
<td>❌ 제한 있음</td>
<td>✅ 자유로움</td>
</tr>
<tr>
<td>코드 길이</td>
<td>❌ 길어짐</td>
<td>✅ 간결함</td>
</tr>
<tr>
<td>최신 추세</td>
<td>❌ 지양</td>
<td>✅ 선호됨</td>
</tr>
</tbody></table>
<blockquote>
<p>💡 <strong>대부분의 기업, 라이브러리, 공식 문서에서는 React.FC 사용을 지양하는 추세</strong>다.
특히 <code>children</code> 자동 포함으로 발생할 수 있는 <strong>불필요한 오류 방지와 타입 추론 유연성 확보</strong>가 큰 이유다.</p>
</blockquote>
<hr>
<h2 id="⏰-언제-reactfc를-써도-괜찮을까">⏰ 언제 React.FC를 써도 괜찮을까?</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>React.FC 사용 여부</th>
</tr>
</thead>
<tbody><tr>
<td>간단한 프로토타입 개발</td>
<td>✅ 괜찮음</td>
</tr>
<tr>
<td><code>children</code> 포함한 컴포넌트 작성 시</td>
<td>✅ 명시 없이 사용 가능</td>
</tr>
<tr>
<td>제너릭 사용이 필요한 상황</td>
<td>❌ 지양</td>
</tr>
<tr>
<td>규모 있는 팀 프로젝트</td>
<td>❌ 가급적 명시적 방식 사용 권장</td>
</tr>
</tbody></table>
<hr>
<h2 id="✅-결론">✅ 결론</h2>
<ul>
<li><p><code>React.FC</code>는 타입스크립트에서 함수형 컴포넌트를 쉽게 선언할 수 있도록 도와주는 제네릭 타입이다.</p>
</li>
<li><p>하지만 <code>children</code> 자동 포함과 제네릭 제약 때문에 <strong>요즘은 직접 Props를 명시하는 방식</strong>을 선호한다.</p>
</li>
<li><p>상황에 따라 적절히 선택하되, <strong>팀 내 코드 스타일 가이드에 맞춰 통일</strong>하는 것이 중요하다.</p>
</li>
</ul>
<hr>
<h3 id="📝-한-줄-요약">📝 한 줄 요약</h3>
<blockquote>
<p><code>React.FC</code>는 편리하지만, 더 명시적이고 유연한 직접 Props 타입 선언 방식이 현재 TypeScript + React 개발에서 더 많이 사용된다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[🧠 실시간 통신의 두 가지 방식: Polling vs WebSocket 정리]]></title>
            <link>https://velog.io/@minjoo_huh/%EC%8B%A4%EC%8B%9C%EA%B0%84-%ED%86%B5%EC%8B%A0%EC%9D%98-%EB%91%90-%EA%B0%80%EC%A7%80-%EB%B0%A9%EC%8B%9D-Polling-vs-WebSocket-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@minjoo_huh/%EC%8B%A4%EC%8B%9C%EA%B0%84-%ED%86%B5%EC%8B%A0%EC%9D%98-%EB%91%90-%EA%B0%80%EC%A7%80-%EB%B0%A9%EC%8B%9D-Polling-vs-WebSocket-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 23 May 2025 09:15:52 GMT</pubDate>
            <description><![CDATA[<p>실시간 기능이 필요한 채팅, 알림, 라이브 데이터 등에선
데이터를 실시간으로 주고받는 방식이 매우 중요합니다.
대표적으로 사용되는 방식은 두 가지입니다:</p>
<ul>
<li><strong>🕓 Polling (폴링)</strong></li>
<li><strong>🔌 WebSocket (웹소켓)</strong></li>
</ul>
<p>이번 글에선 이 두 가지 방식을 비교하고,
어떤 상황에서 어떤 방식을 사용하는 게 좋은지 살펴보겠습니다.</p>
<hr>
<h2 id="✅-1-폴링polling이란">✅ 1. 폴링(Polling)이란?</h2>
<blockquote>
<p>일정한 시간 간격으로 서버에 “새 소식 있어요?”라고 계속 물어보는 방식입니다.</p>
</blockquote>
<p>폴링은 클라이언트가 정해진 시간마다 서버에 요청을 보내,
<strong>새로운 데이터가 생겼는지 확인하는 방식</strong>입니다.</p>
<pre><code>[클라이언트] → 3초마다 → [서버] &quot;새 메시지 있어?&quot;
[서버] → &quot;있어!&quot; 또는 &quot;없어~&quot;</code></pre><h3 id="🔹-특징">🔹 특징</h3>
<ul>
<li><p>실시간처럼 보이지만, 실제로는 주기적으로 확인</p>
</li>
<li><p>구현이 매우 간단함 (setInterval만 사용해도 가능)</p>
</li>
<li><p>새로운 데이터가 없어도 계속 요청하게 되어 서버에 부담이 될 수 있음</p>
</li>
</ul>
<hr>
<h2 id="✅-2-웹소켓websocket이란">✅ 2. 웹소켓(WebSocket)이란?</h2>
<blockquote>
<p>한 번 연결하면 서버와 클라이언트가 실시간으로 메시지를 주고받는 방식입니다.</p>
</blockquote>
<p>웹소켓은 서버와 클라이언트가 한 번 연결한 뒤,
<strong>지속적인 연결을 유지하면서 양방향 통신이 가능한 방식</strong>입니다.</p>
<pre><code>[클라이언트] 🔗 [서버] ←→ 실시간 대화</code></pre><h3 id="🔹-특징-1">🔹 특징</h3>
<ul>
<li><p>실시간성이 매우 뛰어남 (채팅, 알림 등 즉시 반영이 필요한 기능에 적합)</p>
</li>
<li><p>연결을 유지하기 때문에 불필요한 반복 요청이 없음</p>
</li>
<li><p>설정이 다소 복잡하지만, 효율적이고 빠름</p>
</li>
</ul>
<hr>
<h2 id="🔁-polling-vs-websocket--간단-비교표">🔁 Polling vs WebSocket – 간단 비교표</h2>
<table>
<thead>
<tr>
<th>항복</th>
<th>Polling</th>
<th>WebSocket</th>
</tr>
</thead>
<tbody><tr>
<td>작동 방식</td>
<td>일정 가격마다 요청</td>
<td>한 번 연결 후 계속 통신</td>
</tr>
<tr>
<td>실시간성</td>
<td>느림 (3~5초 간격)</td>
<td>매우 빠름 (즉시 전송)</td>
</tr>
<tr>
<td>서버 부담</td>
<td>요청 많으면 과부하</td>
<td>적음 (지속 연결 유지)</td>
</tr>
<tr>
<td>구현 난이도</td>
<td>쉽다 (단순한 요청 반복)</td>
<td>중간 이상 (서버/클라이언트 설정 필요)</td>
</tr>
<tr>
<td>브라우저 호환성</td>
<td>매우 좋음</td>
<td>최신 브라우저 대부분 OK</td>
</tr>
<tr>
<td>사용 예</td>
<td>뉴스 피드, 테스트 채팅</td>
<td>실시간 채팅, 알림, 주식, 게임</td>
</tr>
</tbody></table>
<hr>
<h2 id="💬-meetty-프로젝트에서의-활용">💬 MEETTY 프로젝트에서의 활용</h2>
<p>우리 프로젝트인 <strong>MEETTY</strong>에서는 다음과 같은 방식으로 활용할 수 있습니다:</p>
<table>
<thead>
<tr>
<th>기능</th>
<th>추천 방식</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>채팅방 테스트</td>
<td>Polling</td>
<td>빠르고 간단하게 구현 가능</td>
</tr>
<tr>
<td>실제 채팅/화상채팅</td>
<td>WebSocket</td>
<td>실시간 반응이 중요함</td>
</tr>
<tr>
<td>읽지 않은 메시지 수 확인</td>
<td>Polling</td>
<td>주기적으로 확인하면 충분</td>
</tr>
<tr>
<td>참여자 수 실시간 표시</td>
<td>WebSocket</td>
<td>변화가 생기면 즉시 반영 필요</td>
</tr>
</tbody></table>
<hr>
<h2 id="🧪-react에서-polling-구현-예시">🧪 React에서 Polling 구현 예시</h2>
<pre><code>import { useEffect, useState } from &quot;react&quot;;
import axios from &quot;axios&quot;;

const ChatPolling = () =&gt; {
  const [messages, setMessages] = useState([]);

  useEffect(() =&gt; {
    const interval = setInterval(() =&gt; {
      axios.get(&quot;/api/messages&quot;).then((res) =&gt; {
        setMessages(res.data);
      });
    }, 3000); // 3초마다 서버에 새 메시지 요청
    return () =&gt; clearInterval(interval);
  }, []);

  return (
    &lt;div&gt;
      &lt;h2&gt;채팅창&lt;/h2&gt;
      {messages.map((msg, idx) =&gt; (
        &lt;div key={idx}&gt;{msg.content}&lt;/div&gt;
      ))}
    &lt;/div&gt;
  );
};

export default ChatPolling;
</code></pre><hr>
<h2 id="🐾-마무리-한-마디">🐾 마무리 한 마디</h2>
<blockquote>
<p>정리해보니 폴링은 구현이 간단해서 초반 테스트에 좋고,
웹소켓은 실시간 반응이 필요한 기능에 더 잘 어울린다는 걸 알게 됐다.
MEETTY 프로젝트에서도 상황에 맞게 둘 중 적절한 방식을 선택하면 좋을 것 같다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[🌈 CSS 파일 vs CSS Module 완벽 정리]]></title>
            <link>https://velog.io/@minjoo_huh/CSS-%ED%8C%8C%EC%9D%BC-vs-CSS-Module-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@minjoo_huh/CSS-%ED%8C%8C%EC%9D%BC-vs-CSS-Module-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 21 May 2025 16:18:04 GMT</pubDate>
            <description><![CDATA[<p>프론트엔드 개발을 하다 보면 스타일을 적용할 때 <code>style.css</code>처럼 일반 CSS 파일을 사용하는 경우도 있고,<br><code>.module.css</code>라는 조금은 생소한 확장자를 마주치는 경우도 있습니다.</p>
<blockquote>
<p>이 둘은 어떻게 다르고, 언제 무엇을 써야 할까요?</p>
</blockquote>
<hr>
<h2 id="🔍-css란-무엇인가">🔍 CSS란 무엇인가?</h2>
<p>CSS(Cascading Style Sheets)는 HTML 문서의 시각적 표현을 담당하는 스타일링 언어입니다.</p>
<pre><code class="language-css">/* style.css */
.button {
  background-color: #4caf50;
  color: white;
}</code></pre>
<pre><code>&lt;button className=&quot;button&quot;&gt;클릭&lt;/button&gt;</code></pre><ul>
<li>이 스타일은 <strong>모든 컴포넌트, 모든 파일</strong>에서 사용할 수 있습니다.</li>
<li>즉, <strong>전역(Global)</strong> 으로 작동합니다.</li>
</ul>
<hr>
<h2 id="🧩-css-module이란">🧩 CSS Module이란?</h2>
<p>CSS Module은 <strong>컴포넌트 단위로 스타일을 캡슐화</strong>하는 방식입니다.
파일 이름이 Something.module.css처럼 되어 있고, JS/TS 파일에서 객체처럼 불러와서 사용합니다.</p>
<pre><code>/* Button.module.css */
.button {
  background-color: #4caf50;
  color: white;
}</code></pre><pre><code>// Button.tsx
import styles from &#39;./Button.module.css&#39;;

&lt;button className={styles.button}&gt;클릭&lt;/button&gt;</code></pre><p>이렇게 하면 이 button 클래스는 오직 이 컴포넌트에서만 적용됩니다.</p>
<hr>
<h2 id="⚖️-css-vs-css-module--비교-정리">⚖️ CSS vs CSS Module — 비교 정리</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>일반 CSS (<code>.css</code>)</th>
<th>CSS Module (<code>.module.css</code>)</th>
</tr>
</thead>
<tbody><tr>
<td>적용 범위</td>
<td>전역</td>
<td>로컬 (컴포넌트 단위)</td>
</tr>
<tr>
<td>클래스 충돌</td>
<td>발생 가능 (주의 필요)</td>
<td>충돌 없음 (자동 해시 처리)</td>
</tr>
<tr>
<td>스타일 사용 방식</td>
<td><code>className=&quot;...&quot;</code></td>
<td><code>className={styles.class}</code></td>
</tr>
<tr>
<td>코드 유지보스</td>
<td>규모가 커지면 어렵다</td>
<td>컴포넌트별로 관리 쉬움</td>
</tr>
<tr>
<td>선언 위치</td>
<td>어디서든 가능</td>
<td>import한 컴포넌트 내에서만 사용</td>
</tr>
<tr>
<td>권장 상황</td>
<td>전체적인 레이아웃, 폰트, 공통 스타일</td>
<td>컴포넌트 스타일, 재사용 컴포넌트</td>
</tr>
</tbody></table>
<hr>
<h2 id="✅-실제-사용-예시">✅ 실제 사용 예시</h2>
<h3 id="📁-디렉토리-구조">📁 디렉토리 구조</h3>
<pre><code>src/
├── components/
│   ├── Button.tsx
│   └── Button.module.css
├── App.tsx
└── global.css
</code></pre><h3 id="📄-buttonmodulecss">📄 Button.module.css</h3>
<pre><code>.button {
  background-color: royalblue;
  color: white;
  padding: 0.5rem 1rem;
  border-radius: 4px;
  border: none;
  font-weight: bold;
}
</code></pre><h3 id="📄-buttontsx">📄 Button.tsx</h3>
<pre><code>import React from &#39;react&#39;;
import styles from &#39;./Button.module.css&#39;;

const Button: React.FC = () =&gt; {
  return &lt;button className={styles.button}&gt;눌러주세요&lt;/button&gt;;
};

export default Button;
</code></pre><h3 id="📄-apptsx">📄 App.tsx</h3>
<pre><code>import React from &#39;react&#39;;
import &#39;./global.css&#39;; // 전역 CSS
import Button from &#39;./components/Button&#39;;

function App() {
  return (
    &lt;div className=&quot;app&quot;&gt;
      &lt;h1&gt;CSS vs CSS Module&lt;/h1&gt;
      &lt;Button /&gt;
    &lt;/div&gt;
  );
}

export default App;
</code></pre><hr>
<h2 id="💡-어떤-걸-선택해야-할까">💡 어떤 걸 선택해야 할까?</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>추천 방식</th>
</tr>
</thead>
<tbody><tr>
<td>리셋, 폰트, 전역 테마 설정</td>
<td>일반 CSS</td>
</tr>
<tr>
<td>버튼, 카드, 섹션 등 개별 UI 컴포넌트</td>
<td>CSS Module</td>
</tr>
<tr>
<td>대규모 팀 프로젝트</td>
<td>CSS Module (충돌 방지)</td>
</tr>
</tbody></table>
<hr>
<h2 id="✅-한-줄-요약">✅ 한 줄 요약</h2>
<blockquote>
<p><strong>전역 스타일은 <code>.css</code>, 컴포넌트 스타일은 <code>.module.css</code>로!</strong></p>
</blockquote>
<hr>
<h2 id="📚-마무리">📚 마무리</h2>
<p>React에서 CSS를 다룰 때는 단순히 보이는 것만 생각하지 말고,
<strong>구조적으로 스타일이 어디까지 영향을 미치는가</strong>를 고려하는 것이 중요합니다.</p>
<p>CSS Module을 잘 활용하면 유지보수도 쉬워지고, 팀원 간 충돌도 줄일 수 있어요.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🚀 Vite + React 프로젝트를 GCP에 배포하기]]></title>
            <link>https://velog.io/@minjoo_huh/Vite-React-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A5%BC-GCP%EC%97%90-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@minjoo_huh/Vite-React-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A5%BC-GCP%EC%97%90-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 15 May 2025 15:47:29 GMT</pubDate>
            <description><![CDATA[<p>Vite는 빠른 개발 환경을 제공하는 프론트엔드 빌드 도구입니다. 이번 글에서는 Vite + React로 제작한 프로젝트를 GCP 환경에 배포하는 과정을 단계별로 정리해보겠습니다. ✅</p>
<h3 id="✅-1-패키지-설치-및-빌드">✅ 1. 패키지 설치 및 빌드</h3>
<p>먼저, Vite 프로젝트의 패키지를 설치하고 빌드합니다.</p>
<pre><code>    cd 프로젝트명
    npm install
    npm run build</code></pre><p>위 명령어를 통해 dist 폴더가 생성됩니다. dist 폴더에는 배포할 정적 파일들이 포함됩니다.</p>
<h3 id="✅-2-gcloud-cli-환경-설정-및-ssh-키-생성">✅ 2. gcloud CLI 환경 설정 및 SSH 키 생성</h3>
<p><strong>gcloud CLI란?</strong></p>
<p>gcloud CLI는 GCP 인스턴스에 접근하고 관리하는 명령줄 도구입니다. SSH 키 생성, VM 인스턴스 접속, 파일 전송 등을 지원합니다.</p>
<ol>
<li>gcloud CLI 다운로드 및 설치:</li>
</ol>
<pre><code>    gcloud auth login
    gcloud config set project &lt;PROJECT_ID&gt;</code></pre><ol start="2">
<li>SSH 키 생성 및 접속:</li>
</ol>
<ul>
<li>SSH 키 자동 생성</li>
</ul>
<pre><code>    gcloud compute ssh &lt;INSTANCE_NAME&gt; --zone=&lt;ZONE&gt;</code></pre><p>~/.ssh/google_compute_engine 경로에 SSH 키가 생성되고 서버에 자동 등록됩니다.</p>
<ul>
<li><p>기존 SSH 키 삭제 및 재생성:</p>
<pre><code>  rm -f ~/.ssh/google_compute_engine*
  gcloud compute ssh &lt;INSTANCE_NAME&gt; --zone=&lt;ZONE&gt;</code></pre></li>
<li><p>수동 SSH 키 생성:</p>
<pre><code>  ssh-keygen -t rsa -f ~/.ssh/my-gcp-key</code></pre></li>
</ul>
<p>생성된 공개 키를 GCP Console &gt; Metadata &gt; SSH Keys에 추가합니다.</p>
<h3 id="✅-3-파일-전송-gcloud-cli-vs-scp">✅ 3. 파일 전송 (gcloud CLI vs SCP)</h3>
<p>Vite + React 프로젝트의 dist 폴더를 GCP 서버에 전송하는 방법은 gcloud CLI와 SCP 두 가지 방식이 있습니다. 아래는 두 방법의 차이점과 각각의 명령어를 정리한 표입니다:</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>gcloud CLI</th>
<th>SCP</th>
</tr>
</thead>
<tbody><tr>
<td>사용 명령어</td>
<td><code>gcloud compute scp</code></td>
<td><code>scp</code></td>
</tr>
<tr>
<td>SSH 키 관리</td>
<td>자동 관리 (<code>~/.ssh/google_compute_engine</code>)</td>
<td>수동 관리 (<code>-i 옵션 사용</code>)</td>
</tr>
<tr>
<td>파일 경로</td>
<td><code>/home/&lt;USERNAME&gt;/frontend/</code></td>
<td><code>/home/&lt;USERNAME&gt;/frontend/</code></td>
</tr>
<tr>
<td>전송 방식</td>
<td>GCP CLI 내부 명령어로 전송</td>
<td>Linux, macOS 기본 명령어로 전송</td>
</tr>
<tr>
<td>명령어 예시</td>
<td><code>gcloud compute scp --recurse ./dist/ &lt;INSTANCE_NAME&gt;:/home/&lt;USERNAME&gt;/frontend --zone=&lt;ZONE&gt;</code></td>
<td><code>scp -i ~/.ssh/google_compute_engine -r ./dist/* &lt;USERNAME&gt;@&lt;SERVER_IP&gt;:/home/&lt;USERNAME&gt;/frontend/</code></td>
</tr>
</tbody></table>
<p>✅ 권장 방법:</p>
<p>GCP 환경에 익숙하거나 프로젝트가 GCP CLI로 구성된 경우 gcloud CLI를 사용하는 것이 편리합니다.
SSH를 통해 수동으로 관리하거나, GCP CLI 환경이 없는 경우 SCP를 사용하는 것이 좋습니다.</p>
<ul>
<li>gcloud CLI로 파일 전송:</li>
</ul>
<pre><code>    gcloud compute scp --recurse ./dist/ &lt;INSTANCE_NAME&gt;:/home/&lt;USERNAME&gt;/frontend --zone=&lt;ZONE&gt;</code></pre><ul>
<li>SCP로 파일 전송:</li>
</ul>
<pre><code>    scp -i ~/.ssh/google_compute_engine -r ./dist/* &lt;USERNAME&gt;@&lt;SERVER_IP&gt;:/home/&lt;USERNAME&gt;/frontend/</code></pre><h3 id="✅-4-서버에서-dist-폴더-이동-및-nginx-설정">✅ 4. 서버에서 dist 폴더 이동 및 Nginx 설정</h3>
<ul>
<li>서버로 접속:</li>
</ul>
<pre><code>    gcloud compute ssh &lt;INSTANCE_NAME&gt; --zone=&lt;ZONE&gt;</code></pre><ul>
<li>dist 폴더 이동:</li>
</ul>
<pre><code>    sudo mv /home/&lt;USERNAME&gt;/frontend/* /var/www/html/</code></pre><ul>
<li>Nginx 설정 파일 열기:</li>
</ul>
<pre><code>    sudo nano /etc/nginx/sites-available/default</code></pre><ul>
<li>Nginx 설정 추가:</li>
</ul>
<pre><code>    server {
        listen 80;
        server_name &lt;DOMAIN_OR_IP&gt;;

        root /var/www/html;
        index index.html;

        location / {
            try_files $uri $uri/ /index.html;
        }
    }
</code></pre><ul>
<li>설정 저장 후 Nginx 재시작:</li>
</ul>
<pre><code>    sudo nginx -t
    sudo systemctl restart nginx</code></pre><h3 id="✅-5-배포-확인-및-로그-확인">✅ 5. 배포 확인 및 로그 확인</h3>
<ul>
<li><p>웹 브라우저에서 접속:</p>
<p>http://서버IP로 접속하여 배포된 Vite + React 앱이 정상적으로 표시되는지 확인합니다.</p>
</li>
<li><p>Nginx 로그 확인:</p>
</li>
</ul>
<pre><code>    sudo tail -f /var/log/nginx/access.log
    sudo tail -f /var/log/nginx/error.log</code></pre><p>이제 Vite + React에서 빌드한 dist 파일이 GCP 서버에 배포되었습니다!</p>
<p>이 과정에서 발생할 수 있는 에러나 추가적인 최적화 방법에 대해선 다음 글에서 다루도록 하겠습니다. 👍😊</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript로 전환 후 Vite + React에서 발생한 모듈 경로 오류, 해결책은 단순히 VSCode 재시작?]]></title>
            <link>https://velog.io/@minjoo_huh/TypeScript%EB%A1%9C-%EC%A0%84%ED%99%98-%ED%9B%84-Vite-React%EC%97%90%EC%84%9C-%EB%B0%9C%EC%83%9D%ED%95%9C-%EB%AA%A8%EB%93%88-%EA%B2%BD%EB%A1%9C-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%EC%B1%85%EC%9D%80-%EB%8B%A8%EC%88%9C%ED%9E%88-VSCode-%EC%9E%AC%EC%8B%9C%EC%9E%91</link>
            <guid>https://velog.io/@minjoo_huh/TypeScript%EB%A1%9C-%EC%A0%84%ED%99%98-%ED%9B%84-Vite-React%EC%97%90%EC%84%9C-%EB%B0%9C%EC%83%9D%ED%95%9C-%EB%AA%A8%EB%93%88-%EA%B2%BD%EB%A1%9C-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%EC%B1%85%EC%9D%80-%EB%8B%A8%EC%88%9C%ED%9E%88-VSCode-%EC%9E%AC%EC%8B%9C%EC%9E%91</guid>
            <pubDate>Thu, 15 May 2025 13:07:50 GMT</pubDate>
            <description><![CDATA[<p>Vite + React 환경에서 .jsx 파일을 .tsx로 변경한 후, 모듈에 대한 선언 파일을 찾을 수 없습니다라는 TypeScript 오류를 마주한 적이 있는가? 나도 동일한 문제를 겪었다. tsconfig.json을 열심히 뒤져보고, Vite 설정까지 점검했지만, 해결책은 의외로 간단했다.</p>
<h3 id="✅-문제-상황">✅ 문제 상황</h3>
<p>Vite 프로젝트에서 .tsx 파일을 import할 때, 아래와 같은 에러가 발생했다:</p>
<p>모듈 &#39;./Login&#39;에 대한 선언 파일을 찾을 수 없습니다. &#39;c:/Users/프로젝트경로/src/Login.tsx&#39;에는 암시적으로 &#39;any&#39; 형식이 포함됩니다.ts(7016)</p>
<p>이 오류는 TypeScript가 .tsx 파일을 인식하지 못하거나 경로를 제대로 읽지 못할 때 발생한다. tsconfig.json의 경로 설정이 잘못되었거나, VSCode가 변경 사항을 인식하지 못한 경우다.</p>
<h3 id="✅-문제-원인-분석">✅ 문제 원인 분석</h3>
<p>이 오류의 원인은 다름 아닌 VSCode의 캐시 문제였다.</p>
<p>VSCode는 프로젝트를 열 때 tsconfig.json의 설정을 메모리에 캐싱해둔다. 그런데 .jsx에서 .tsx로 확장자를 변경하거나 파일 경로를 수정하면, TypeScript 서버가 이를 즉시 반영하지 못할 수 있다.</p>
<p>이 경우, TypeScript 서버는 기존 캐시를 사용해 여전히 .tsx 파일을 찾지 못한다고 인식하게 된다.</p>
<h3 id="✅-해결-방법">✅ 해결 방법</h3>
<p>해결 방법은 아주 간단하다. 아래 두 가지 방법 중 하나만 수행하면 된다:</p>
<p>VSCode 재시작:</p>
<p>파일 경로나 설정이 변경되었을 때, VSCode가 이를 즉시 반영하지 못하는 경우가 있다.</p>
<p>따라서 VSCode를 완전히 종료하고 다시 실행하면 설정이 새로 반영된다.</p>
<p>TypeScript 서버 재시작:</p>
<p>Ctrl + Shift + P 또는 Cmd + Shift + P를 눌러 명령어 팔레트를 열고 TypeScript: Restart TS Server를 입력하고 실행한다.</p>
<p>이 과정에서 TypeScript 서버의 캐시가 초기화되고, 새로운 경로 설정이 반영된다.</p>
<h3 id="✅-왜-vscode-재시작이-효과적일까">✅ 왜 VSCode 재시작이 효과적일까?</h3>
<p>VSCode는 프로젝트를 열 때 tsconfig.json과 vite.config.ts의 설정을 메모리에 저장한다.</p>
<p>.jsx에서 .tsx로 파일 확장자를 변경하거나, tsconfig.json의 include 경로를 수정해도, TypeScript 서버가 이를 즉시 반영하지 못할 때가 있다.</p>
<p>이럴 경우, VSCode를 재시작하거나 TypeScript 서버를 재시작하면, 캐시가 초기화되면서 새로운 설정이 반영된다.</p>
<h3 id="✅-결론">✅ 결론</h3>
<p>TypeScript 설정 파일을 아무리 수정해도 에러가 해결되지 않는다면, 가장 먼저 시도해볼 해결책은 VSCode 재시작이다.</p>
<p>TypeScript 서버가 새로운 설정을 인식하지 못할 때, 가장 빠른 해결책은 <strong>재시작</strong>이다.</p>
<p>작은 오류도 해결 과정에서 큰 배움이 될 수 있다. 이번 경험을 통해 VSCode의 캐시 시스템이 어떻게 동작하는지, 그리고 재시작이 왜 강력한 해결책인지 확실히 알게 되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Objects are not valid as a React child (found: [object Date]).]]></title>
            <link>https://velog.io/@minjoo_huh/Objects-are-not-valid-as-a-React-child-found-object-Date</link>
            <guid>https://velog.io/@minjoo_huh/Objects-are-not-valid-as-a-React-child-found-object-Date</guid>
            <pubDate>Wed, 22 Jan 2025 16:26:56 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-JavaScript">Objects are not valid as a React child (found: [object Date]). If you meant to render a collection of children, use an array instead.
    at throwOnInvalidObjectType (http://localhost:3000/static/js/bundle.js:15364:11)
    at reconcileChildFibersImpl (http://localhost:3000/static/js/bundle.js:15679:9)
    at http://localhost:3000/static/js/bundle.js:15691:31
    at reconcileChildren (http://localhost:3000/static/js/bundle.js:17064:115)
    at beginWork (http://localhost:3000/static/js/bundle.js:17835:1565)
    at runWithFiberInDEV (http://localhost:3000/static/js/bundle.js:13128:14)
    at performUnitOfWork (http://localhost:3000/static/js/bundle.js:20372:93)
    at workLoopSync (http://localhost:3000/static/js/bundle.js:20266:38)
    at renderRootSync (http://localhost:3000/static/js/bundle.js:20250:7)
    at performWorkOnRoot (http://localhost:3000/static/js/bundle.js:20011:42)</code></pre>
<p>일정을 짜는 기능을 만드는 도중에, 에러가 떴다....
정확하게는 react-calendar를 사용하여, 한국 시간대에 맞춘 마크와 타임테이블을 만들려고 하는 도중에 꼬여서 에러가 발생했다.</p>
<p>이 오류가 발생한 이유는 React가 렌더링 과정에서 <code>Date</code> 객체를 화면에 출력하려고 했기 때문이다. React는 문자열, 숫자, React 엘리먼트는 렌더링할 수 있지만, <strong><code>Date</code> 객체는 직접 렌더링할 수 없다.</strong></p>
<pre><code class="language-JavaScript">const MyComponent = () =&gt; {
    const now = new Date();        // Date 객체 생성
      return &lt;div&gt;{now}&lt;/div&gt;;    // Date 객체를 렌더링하려고 함 -&gt; 오류 발생
};</code></pre>
<p>위의 코드에서 <code>now</code>는 <code>Date</code> 객체이고, React는 이를 문자열로 변환하지 않으면 DOM에 출력할 방법을 모르기 때문에 오류가 발생한다.</p>
<p>React는 <strong>DOM의 텍스트 노드</strong>에 데이터를 삽입할 때 <strong>내부적으로 문자열만 처리</strong>한다. 하지만 <code>Date</code> 객체는 JavaScript에서 복잡한 데이터 구조를 가지며, 이를 단순한 문자열로 출력하려면 명시적으로 변환해야 한다.</p>
<p>React에서 <code>Date</code> 객체를 화면에 표시하려면 문자열로 변환해야 한다. JavaScript에서는 <code>Date</code> 객체를 문자열로 변환하는 여러 가지 방법을 제공한다.</p>
<blockquote>
<h4 id="1-tostring-메서드">1. <code>toString()</code> 메서드</h4>
</blockquote>
<ul>
<li>기본적으로 사람이 읽을 수 있는 형식으로 변환<pre><code class="language-JavaScript">const now = new Date();
console.log(now.toString());    // &quot;Wed Jan 22 2025 15:30:00 GMT+0900 (Korean Standard Time)&quot;</code></pre>
<blockquote>
</blockquote>
<h4 id="2-tolocaldatestring-메서드">2. <code>toLocalDateString()</code> 메서드</h4>
</li>
<li>날짜를 특정 Local(ex: 한국 등) 형식으로 변환<pre><code class="language-JavaScript">const now = new Date();
console.log(now.toLocalDateString(&quot;ko-KR&quot;));    // ex: &quot;2025. 1. 22.&quot;</code></pre>
<blockquote>
</blockquote>
<h4 id="3-toisostring-메서드">3. <code>toISOString()</code> 메서드</h4>
</li>
<li><code>Date</code> 객체를 표준 <code>YYYY-MM-DDHH:mm:ss.sssZ</code> 형식의 문자열로 변환<pre><code class="language-JavaScript">const now = new Date();
console.log(now.toISOString());    // ex: &quot;2025-01-22T06:30:00.000Z&quot;</code></pre>
</li>
</ul>
<p>⭐ 결론은 React에서는 <code>Date</code> 객체를 컴포넌트로 바로 올릴 수 없기 때문에 문자열로 변환하여 사용해야 한다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Uncaught runtime Error!]]></title>
            <link>https://velog.io/@minjoo_huh/Uncaught-runtime-Error</link>
            <guid>https://velog.io/@minjoo_huh/Uncaught-runtime-Error</guid>
            <pubDate>Fri, 20 Dec 2024 18:51:10 GMT</pubDate>
            <description><![CDATA[<pre><code>Objects are not valid as a React child (found: object with keys {props}). If you meant to render a collection of children, use an array instead.
    at throwOnInvalidObjectType (http://localhost:3000/static/js/bundle.js:13130:11)
    at reconcileChildFibersImpl (http://localhost:3000/static/js/bundle.js:13445:9)
    at http://localhost:3000/static/js/bundle.js:13457:31
    at reconcileChildren (http://localhost:3000/static/js/bundle.js:14830:47)
    at beginWork (http://localhost:3000/static/js/bundle.js:15601:1565)
    at runWithFiberInDEV (http://localhost:3000/static/js/bundle.js:10894:14)
    at performUnitOfWork (http://localhost:3000/static/js/bundle.js:18138:93)
    at workLoopSync (http://localhost:3000/static/js/bundle.js:18032:38)
    at renderRootSync (http://localhost:3000/static/js/bundle.js:18016:7)
    at performWorkOnRoot (http://localhost:3000/static/js/bundle.js:17777:42)</code></pre><p>props를 자식 컴포넌트에 넘겨주었을 때, { props } 형태로 자식 컴포넌트에서 사용해야 한다. 이것을 사용하지 않아 에러가 떴다...</p>
<p><strong>참고 자료</strong>
BLOG : <a href="https://velog.io/@leemember/Objects-are-not-valid-as-a-React-child-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0">https://velog.io/@leemember/Objects-are-not-valid-as-a-React-child-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</a>
tiypeScript : <a href="https://ko.react.dev/learn/typescript">https://ko.react.dev/learn/typescript</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Too many re-renders Error!]]></title>
            <link>https://velog.io/@minjoo_huh/Too-many-re-renders-Error</link>
            <guid>https://velog.io/@minjoo_huh/Too-many-re-renders-Error</guid>
            <pubDate>Fri, 20 Dec 2024 16:23:29 GMT</pubDate>
            <description><![CDATA[<pre><code>Too many re-renders. React limits the number of renders to prevent an infinite loop.
    at renderWithHooksAgain (http://localhost:3000/static/js/bundle.js:13699:55)
    at renderWithHooks (http://localhost:3000/static/js/bundle.js:13659:63)
    at updateFunctionComponent (http://localhost:3000/static/js/bundle.js:14926:17)
    at beginWork (http://localhost:3000/static/js/bundle.js:15544:16)
    at runWithFiberInDEV (http://localhost:3000/static/js/bundle.js:10885:14)
    at performUnitOfWork (http://localhost:3000/static/js/bundle.js:18129:93)
    at workLoopSync (http://localhost:3000/static/js/bundle.js:18023:38)
    at renderRootSync (http://localhost:3000/static/js/bundle.js:18007:7)
    at performWorkOnRoot (http://localhost:3000/static/js/bundle.js:17768:42)
    at performSyncWorkOnRoot (http://localhost:3000/static/js/bundle.js:18578:5)</code></pre><p>Radio onChange로 value (0, 1) 값을 받아서, 배열(2차배열)의 첫번째 인자를 구분하고, 그 배열을 body에서 map으로 button을 생성하는 도중에 위의 에러가 뜨게 되었다.</p>
<p>아래의 링크를 읽어본 결과, state의 변화가 무한반복되어서 나타나는 에러로, button에서 <code>onClick={handleButtonClick(index)}</code> 부분이 문제였다. <code>handleButtonClick(index)</code>로 주면 바로 함수가 실행이 되기 때문에, 함수 안에 있던 <code>setPayButtonMethod(index);</code>라는 state를 값을 변경하는 로직이 계속 실행이 되어 무한 반복에 걸리게 된다.</p>
<p>해결은 <code>onClick={() =&gt; handleButtonClick(index)}</code>로 일급 함수 형태로 가지고 오면 된다. 함수를 실행이 아닌 인자로 넘겨주는 것이기 때문에, 무한 반복에 걸리지 않는다.</p>
<h4 id="참고-링크">참고 링크</h4>
<p><a href="https://wnsdufdl.tistory.com/245">https://wnsdufdl.tistory.com/245</a>
<a href="https://anerim.tistory.com/161">https://anerim.tistory.com/161</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Uncaught Error]]></title>
            <link>https://velog.io/@minjoo_huh/React-Uncaught-Error</link>
            <guid>https://velog.io/@minjoo_huh/React-Uncaught-Error</guid>
            <pubDate>Tue, 17 Dec 2024 18:14:41 GMT</pubDate>
            <description><![CDATA[<pre><code>Uncaught Error: input is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`</code></pre><h2 id="발단">발단</h2>
<p>input tag로 radio를 만들고 있는 중이다.</p>
<h2 id="해결">해결</h2>
<ul>
<li>오류가 난 코드...<pre><code>&lt;input type=&quot;radio&quot; ... &gt; item1 &lt;/input&gt;</code></pre></li>
<li>오류 해결<pre><code>&lt;input type=&quot;radio&quot; ... /&gt;
&lt;label&gt; item1 &lt;/label&gt;</code></pre></li>
</ul>
<p>input은 하위 콘텐츠를 가질 수 없는 빈 요소이다. 그러므로 <code>&lt;/input&gt;</code>이 필요가 없다는 뜻!
그래서 예러가 뜬 것이다.
<a href="https://codingeverybody.kr/html-input-%ED%83%9C%EA%B7%B8-%EC%98%AC%EB%B0%94%EB%A5%B8-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95/">참조_codingEverybody{}</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Install ENONET Error!]]></title>
            <link>https://velog.io/@minjoo_huh/React-Install-ENONET-Error</link>
            <guid>https://velog.io/@minjoo_huh/React-Install-ENONET-Error</guid>
            <pubDate>Tue, 17 Dec 2024 17:45:46 GMT</pubDate>
            <description><![CDATA[<pre><code>npm error code ENOENT
npm error syscall open
npm error path E:\PracticeBookShop\FE\node_modules\.bin\parser.ps1
npm error errno -4058
npm error enoent ENOENT: no such file or directory, open &#39;E:\PracticeBookShop\FE\node_modules\.bin\parser.ps1&#39;
npm error enoent This is related to npm not being able to find a file.
npm error enoent
npm error A complete log of this run can be found in: C:\Users\rmfla\AppData\Local\npm-cache\_logs\2024-12-17T17_00_53_052Z-debug-0.log</code></pre><h2 id="발단">발단</h2>
<p>clone 해서 가져온  react 파일을 <code>npm start</code> 할려고 했다가 안되어서, <code>npm install</code>을 시도하다가 또 에러가 떠서 찾아보는 중이다...</p>
<h2 id="결론">결론</h2>
<p>저장 공간이 없어서 에러가 뜬 것이다...
git 로컬 위치 바꿀려면 그냥 .git 파일 있는 곳 내용 전부 다른 곳으로 옮기면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[(2024.09.06(금)) 슈퍼코딩 부트캠프 4주차 Day4-5 후기]]></title>
            <link>https://velog.io/@minjoo_huh/2024.09.06%EA%B8%88-%EC%8A%88%ED%8D%BC%EC%BD%94%EB%94%A9-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-4%EC%A3%BC%EC%B0%A8-Day4-5-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@minjoo_huh/2024.09.06%EA%B8%88-%EC%8A%88%ED%8D%BC%EC%BD%94%EB%94%A9-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-4%EC%A3%BC%EC%B0%A8-Day4-5-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Fri, 06 Sep 2024 03:42:14 GMT</pubDate>
            <description><![CDATA[<h2 id="to-do-list">To-do List</h2>
<ul>
<li>38강. 스타일링 - 4 - tailwindcss ~ 44강. 데이터 정렬</li>
</ul>
<hr>
<h2 id="📜-38강-스타일링---4---tailwindcss">📜 38강. 스타일링 - 4 - tailwindcss</h2>
<h3 id="⭐-css-framework">⭐ CSS Framework</h3>
<ul>
<li><p>프레임워크를 통해서 정해진대로 하다보면, 생산성을 높일 수 있음.</p>
</li>
<li><p>다양한 CSS 프레임워크 도구들이 있다.</p>
</li>
<li><p>이 외에도 Material UI, Ant Design, Chakra UI 같은 라이브러리도 많이 이용.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/minjoo_huh/post/efc1fe17-b295-4652-b6d3-4dd7c6208180/image.png" alt=""></p>
<ul>
<li>bootstrap : 과거에는 제일 많이 쓰였고, 현재도 일반적으로 많이 쓰던 css framework. 개발을 잘 모르는 사람도 쉽게 이용할 수 있다.</li>
</ul>
<h3 id="⭐-tailwindcss">⭐ <a href="https://tailwindcss.com/">TailwindCSS</a></h3>
<ul>
<li>Utility first CSS Framework</li>
</ul>
<blockquote>
<p>사람들이 적게 사용하는 거라도, 프로그램에 맞는 것이라면 선택하는 것이 좋다. 
오히려 적게 사용하면 이점이 생기는 것!</p>
</blockquote>
<ul>
<li>HTML과 CSS 파일을 별도로 관리할 필요가 없다.</li>
<li>클래스 명을 고민할 필요가 없다.</li>
<li>디자인이 일관되어있다.</li>
<li>자유롭게 커스텀이 가능하다. 등등</li>
</ul>
<h4 id="cli">CLI</h4>
<ul>
<li>Commend Line Interface</li>
<li>CUI (Character User Interface) 라고도 불림 (vs. GUI )</li>
<li>글자를 입력하여 컴퓨터에 명령을 내리는 방식</li>
</ul>
<blockquote>
<p>ex)
p-0 : <code>padding: 0;</code>
mt-0.5 : <code>margin-top: 0.125rem: // 2px</code></p>
</blockquote>
<p>tailwindCSS에서의 1은 4px이다.</p>
<blockquote>
</blockquote>
<p>rounded : <code>border-radius: 0.25rem; // 4px</code></p>
<blockquote>
</blockquote>
<p>4px이 기본값이므로, 그냥 rounded로 표현</p>
<h4 id="tailwindui"><a href="https://tailwindui.com/">tailwindUI</a></h4>
<ul>
<li>framework가 다양하게 존재. (거의 완성된)</li>
</ul>
<hr>
<h2 id="📜-39강-디버깅-part-1">📜 39강. 디버깅 Part 1</h2>
<h3 id="⭐-디버깅-debugging">⭐ 디버깅 (Debugging)</h3>
<ul>
<li>소프트웨어의 소스의 오류 혹은 버그를 고치는 하나의 과정</li>
<li>예전에 1940년에 컴퓨터는 굉장히 컸음. 벌레 한 마리가 컴퓨터에 들어가서 컴퓨터가 멈췄다. 이 벌레를 빼니깐 컴퓨터가 다시 실행되었다. 이래서 버그를 잡는다고 함...</li>
</ul>
<h4 id="컴파일-에러---전적으로-개발자-잘못임">컴파일 에러 - 전적으로 개발자 잘못임</h4>
<p>: 컴파일을 할 때 발생하는 에러</p>
<ul>
<li>Syntax Error // 구문 에러 : 오타 났음! 되게 친절하게 알려줌.</li>
<li>Type Error    // </li>
<li>Reference Error</li>
</ul>
<h4 id="런타임-에러">런타임 에러</h4>
<p>: 컴파일 과정을 마친 후에 사용자에 의해 실행시 에러</p>
<ul>
<li><p>0 나누기 오류</p>
</li>
<li><p>Null 참조 오류</p>
</li>
<li><p>메모리 부족 오류</p>
</li>
<li><p>런타임 에러 해결 방식</p>
<pre><code>// 예외 처리
try {
  logic...
} catch {
  error handling
}</code></pre></li>
</ul>
<h3 id="중단점">중단점</h3>
<ul>
<li><p>break point</p>
</li>
<li><p>디버깅을 한 줄씩 확인하기 위해서, 멈췄으면 하는 곳에서 중단점을 찍어 멈추고 한줄씩 확인하기</p>
</li>
<li><p>멈췄으면 하는 곳에 <code>dibbugger;</code> 넣기</p>
</li>
</ul>
<h4 id="브라우저-환경에서-디버깅">브라우저 환경에서 디버깅</h4>
<ul>
<li>소스 &gt; 자바스크립트 파일 &gt; 옆에 코드 줄 번호를 클릭하면 파란색 태그가 걸림(중단점) -&gt; 디버깅 시작</li>
</ul>
<hr>
<h2 id="📜-40강-디버깅-part-2">📜 40강. 디버깅 Part 2</h2>
<h3 id="⭐프로-파일-도구들">⭐프로 파일 도구들</h3>
<ul>
<li>코드를 최적화하기 위해 함수 호출 주기와 빈도, 시각과 메모리 소요 등을 측정하는 것</li>
</ul>
<h3 id="⭐-react-devtool---chrome-extension">⭐ React Devtool - Chrome Extension</h3>
<ul>
<li>Components
: 컴포넌트를 <strong>트리 구조</strong>로 보여줌. 상태 정보를 확인할 수 있음.</li>
</ul>
<p>사진</p>
<ul>
<li>Profiler
: <strong>랜더링</strong>된 컴포넌트를 <strong>소요 시간</strong>과 함께 보여줌</li>
</ul>
<p><img src="https://velog.velcdn.com/images/minjoo_huh/post/13f3819f-1882-49a5-904b-eef5acb910f7/image.png" alt=""></p>
<h3 id="⭐-google-lighthouse">⭐ <a href="https://developer.chrome.com/docs/lighthouse/overview?hl=ko">Google Lighthouse</a></h3>
<ul>
<li>google에서 프로파일만을 하기 위해서 전문적으로 만든 것</li>
<li>웹 페이지의 품질을 개선할 수 있는 오픈 소스 형태의 자동화 도구.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/minjoo_huh/post/fe5132de-d549-467f-b812-d51b5e1304da/image.png" alt=""></p>
<hr>
<h2 id="📜-42강-이벤트-버블링과-캡처링">📜 42강. 이벤트 버블링과 캡처링</h2>
<h3 id="⭐-브라우저의-이벤트">⭐ 브라우저의 이벤트</h3>
<p align="center"><img src="https://velog.velcdn.com/images/minjoo_huh/post/38a578c8-ab1b-4bab-ad9f-b4e32935fe67/image.png" width="30%" > </p>


<ul>
<li>이벤트 캡처링 : 이벤트를 지정한 것을 찾기 위해 DOM 요소를 부모 요소(body)부터 차근차근 찾아감</li>
<li>이벤트 타겟팅 : 타겟을 찾았다면 잡는다!</li>
<li>이벤트 버블링 : 타겟팅된 돔 요소를 다시 올라오면서 이벤트를 찾는다!</li>
</ul>
<pre><code>&lt;body&gt;
    &lt;div&gt;
        &lt;button&gt;Hello&lt;/button&gt;
    &lt;/div&gt;
&lt;/body&gt;</code></pre><p style="color: white; background: lightpink; width:20rem;">body -> div -> button -> div -> body </p>

<h4 id="1-이벤트-캡처링">1) 이벤트 캡처링</h4>
<ul>
<li>body : Click 이벤트 핸들러를 가지고 있나요? 있다면, 호출한다.</li>
<li>div : 위와 동일</li>
</ul>
<h4 id="2-이벤트-타겟팅">2) 이벤트 타겟팅</h4>
<ul>
<li>button : 클릭한 요소로 가서 이벤트 핸들러를 확인 -&gt; 실행</li>
</ul>
<h4 id="3-이벤트-버블링---반대로-다시-위로-올라가면서-이벤트-확인">3) 이벤트 버블링 - 반대로 다시 위로 올라가면서 이벤트 확인</h4>
<ul>
<li>div : Click 이벤트 핸들러를 가지고 있나요? 있다면, 호출해준다.</li>
<li>body : 위와 동일</li>
</ul>
<h3 id="⭐-이벤트-버블링과-캡처링">⭐ 이벤트 버블링과 캡처링</h3>
<p><img src="https://velog.velcdn.com/images/minjoo_huh/post/d966b1e6-c082-4684-8689-c6c7892cd2cf/image.png" alt=""></p>
<ul>
<li><p>위에서 아래로 target 요소를 찾아가는 것이 -&gt; capturing</p>
</li>
<li><p>아래에서 위로 target 요소를 찾아가는 것이 -&gt; bubbling</p>
</li>
<li><p>handler의 default 값이 bubbling 시 이벤트 헨들러가 일어남.</p>
</li>
<li><p>Event Bubbling</p>
<pre><code>import React from &quot;react&quot;;
</code></pre></li>
</ul>
<p>function App() {
    return (
        &lt;section onClick={() =&gt; console.log(&quot;section dlick&quot;)}&gt;
            &lt;div onClick={() =&gt; console.log(&quot;div click&quot;)}&gt;
                &lt;button onClick={() =&gt; console.log(&quot;button click&quot;)}&gt;
                    클릭
                </button>
            </div>
        </section>
    );
}</p>
<p>export default App;</p>
<pre><code>결과</code></pre><p>button click
div  click
section click</p>
<pre><code>
- Event Capturing</code></pre><p>import React from &quot;react&quot;;</p>
<p>function App() {
    // DOM 요소가 없을시에 처리 방법
    if(document.getElementById(&quot;eventCapture&quot;)) return null;</p>
<pre><code>// eventcapture의 DOM요소에 capture에서 돌아가게 함!
document.getElementById(&quot;eventCapture&quot;).addEventListener(&#39;click&#39;, () =&gt; console.log(&#39;div event capture&#39;), true);

return (
    &lt;section onClick={() =&gt; console.log(&quot;section dlick&quot;)}&gt;
        &lt;div id=&quot;eventCapture&quot; onClick={() =&gt; console.log(&quot;div click&quot;)}&gt;
            &lt;button onClick={() =&gt; console.log(&quot;button click&quot;)}&gt;
                클릭
            &lt;/button&gt;
        &lt;/div&gt;
    &lt;/section&gt;
);</code></pre><p>}</p>
<p>export default App;</p>
<pre><code>결과</code></pre><p>div event capture
button click
div  click
section click</p>
<pre><code>
### ⭐ 이벤트 버블링을 막고 싶다면?

ex) 모달 : 네모난 박스 형태의 작은 창.

![](https://velog.velcdn.com/images/minjoo_huh/post/4b39b43e-2a1e-4daa-9df1-ad8101a67bf6/image.png)


기본적으로 모달 외의 영역을 클릭하게 된다면 모달창이 닫히지만, 해당 모달의 영역을 클릭하면 닫히지 않는다.

모달의 부모 영역에서 버블링을 통해 클릭 이벤트가 일어나 모달의 창이 닫히게 된다. 하지만 자식 요소이기 때문에 부모 영역 안에 속한다. 그렇다면 부모 요소에서 닫힘 이벤트가 떠있다면, 자식 요소도 닫히는 게 인지상정!

=&gt; 이것을 막기 위해서 모달의 이벤트 버블링을 막아볼려고 한다.
해당 요소 위로는 버블링을 하는 것!

#### event.stopPropagation()
- Propagation : 전파
</code></pre><body>
    <div>
        <button>Hello</button>
    </div>
</body>
```
body -> div -> button -> div --> 여기 Click 이벤트 핸들러가 실행이 안되게 하고 싶어요.


<pre><code>import React from &quot;react&quot;;

function App() {
    return (
        &lt;section onClick={() =&gt; console.log(&quot;section dlick&quot;)}&gt;
            &lt;div onClick={(event) =&gt; {
                event.stopPropagation();
                console.log(&quot;div click&quot;);
                }}
            &gt;
                &lt;button onClick={() =&gt; console.log(&quot;button click&quot;)}&gt;
                    클릭
                &lt;/button&gt;
            &lt;/div&gt;
        &lt;/section&gt;
    );
}

export default App;</code></pre><p>결과</p>
<pre><code>button click
div click</code></pre><hr>
<h2 id="📜-43강-복잡한-이벤트와-상태-디자인하기">📜 43강. 복잡한 이벤트와 상태 디자인하기</h2>
<p><img src="https://velog.velcdn.com/images/minjoo_huh/post/3d4423a5-044b-4c31-ae92-623936101642/image.gif" alt=""></p>
<h3 id="⭐-드롭다운-컴포넌트를-구현해보자">⭐ 드롭다운 컴포넌트를 구현해보자.</h3>
<ol>
<li>동작 설명해보기</li>
<li>state와 event handler로 나누기</li>
<li>비슷한 것 묶기</li>
</ol>
<h3 id="✨-1-동작-설명해보기">✨ 1. 동작 설명해보기</h3>
<p>1) 드롭다운 클릭
2) 옵션이 나타남
3) 하나의 옵션을 클릭함
4) 옵션들이 사라짐
5) 클릭한 옵션이 박스에 표시됨</p>
<h3 id="✨-2-state와-event-handler로-나누기">✨ 2. State와 event handler로 나누기</h3>
<p align="center"><img src="https://velog.velcdn.com/images/minjoo_huh/post/15680966-c746-4187-a333-e063def67ce3/image.png" width="70%" > </p>


<p>1) 드롭다운 클릭 &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;<span style="color:#628f50;">Event handler</span>
2) 옵션이 나타남 &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;<span style="color:#5072bf;">State</span>
3) 하나의 옵션을 클릭함 &emsp;&emsp;&emsp;&nbsp;&nbsp;<span style="color:#628f50;">Event handler</span>
4) 옵션들이 사라짐 &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;<span style="color:#5072bf;">State</span>
5) 클릭한 옵션이 박스에 표시됨 &nbsp;<span style="color:#5072bf;">State</span></p>
<h3 id="✨-3-비슷한-것-묶기">✨ 3. 비슷한 것 묶기</h3>
<p><img src="https://velog.velcdn.com/images/minjoo_huh/post/f65d0fbc-ca21-4be3-b27e-e297020f3ca2/image.png" alt=""></p>
<p>토대로 구현하기ㅎㅎ</p>
<br>

<h3 id="❓css-event가-일어날-때-변경하기">❓CSS event가 일어날 때 변경하기.</h3>
<h4 id="1-조건">1) 조건</h4>
<p>: dropdown을 클릭하면 테두리가 생기게 한다.</p>
<pre><code>.dropdown {
    ...
    border: none;
    ...
}

.switched-dropdown {
    border: 1px solid black;
}</code></pre><h4 id="2-state-생성하기-boolean">2) state 생성하기 (boolean)</h4>
<pre><code>const [switchCss, setSwitchCss] = useState(false);</code></pre><h4 id="3-click-handler-함수에서-state-값-변경">3) click handler 함수에서 state 값 변경</h4>
<pre><code>const handlerClick = () =&gt; {
    ...
    setSwitchCss(!switchCss);
};</code></pre><h4 id="4-div에-classname-삼항연산자로-변경하기">4) div에 className 삼항연산자로 변경하기</h4>
<pre><code>&lt;div className={`dropdown ${switchCss ? &quot;switched-dropdown&quot; : &quot;&quot;}`}&gt;
    ...
&lt;/div&gt;</code></pre><h4 id="5-끝">5) 끝!</h4>
<br>

<h3 id="❓-부모-요소-뒤에-자식-요소">❓ 부모 요소 뒤에 자식 요소</h3>
<ul>
<li>부모 요소 뒤에 자식 요소를 숨기고 싶다면?
<code>overflow: hidden;</code> 을 부모 요소(CSS)에 넣어주자!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/minjoo_huh/post/1cae35be-5f6a-4ca0-8411-d2e34690ca78/image.gif" alt=""></p>
<hr>
<h2 id="📜-44강-데이터-정렬">📜 44강. 데이터 정렬</h2>
<h3 id="⭐-number-정렬">⭐ Number 정렬</h3>
<h4 id="sort-메서드">.sort() 메서드</h4>
<pre><code>const data = [1, 5, 6, 3];

data.sort();</code></pre><pre><code>&gt; (4) [1, 3, 5, 6]</code></pre><h4 id="📌sort-메서드-문제점---comparator">📌.sort() 메서드 문제점 - comparator</h4>
<pre><code>const data2 = [1, 10, 2, 3];

data2.sort();</code></pre><pre><code>&gt; (4) [1, 10, 2, 3]</code></pre><p>JS 내부에서는 sort()라는 함수를 구현할 때, 다른 타입도 모두 사용가능하게 구현하였다.
그리고 string이 default 값이기 때문에, 배열을 정렬하면 위처럼 나오게 된다.</p>
<p>이는 <strong>comparator 메서드</strong>로 설정하여 해결한다.</p>
<pre><code>data2.sort((a, b) =&gt; a-b);</code></pre><pre><code>&gt; (4) [1, 2, 3, 10]</code></pre><p>두 수를 비교하여 순서를 맞추어 나간다.
( a-b &lt; 0 이면, b가 큰 것이고, a-b &gt; 0 이면, a가 큰 것이다. )</p>
<h3 id="⭐-string-정렬">⭐ string 정렬</h3>
<h4 id="localecompare-메서드">localeCompare() 메서드</h4>
<ul>
<li>사전 정렬 방식과 비슷함.</li>
</ul>
<pre><code>const data3 = [&#39;a&#39;, &#39;b&#39;, &#39;A&#39;, &#39;B&#39;, &#39;t&#39;];

data3.sort()</code></pre><pre><code>&gt; (5) [&#39;A&#39;, &#39;B&#39;, &#39;a&#39;, &#39;b&#39;, &#39;t&#39;]</code></pre><p>ASCII 코드로 인해서 대문자 -&gt; 소문자 순으로 정렬이 된다.</p>
<h4 id="알파벳-순서대로-대소문자-섞어서---comparator">알파벳 순서대로 (대소문자 섞어서) - comparator</h4>
<pre><code>data3.sort((a, b) =&gt; a.localeCompare(b));</code></pre><pre><code>&gt; (5) [&#39;a&#39;, &#39;A&#39;, &#39;b&#39;, &#39;B&#39;, &#39;t&#39;]</code></pre><h4 id="거꾸로-정렬하기">거꾸로 정렬하기</h4>
<pre><code>data3.sort((a, b) =&gt; b.localeCompare(a));</code></pre><pre><code>&gt; (5) [&#39;t&#39;, &#39;B&#39;, &#39;b&#39;, &#39;A&#39;, &#39;a&#39;]</code></pre><h3 id="⭐-object-정렬">⭐ object 정렬</h3>
<ul>
<li>여러 가지 속성이 있는 객체들을 정렬할려면 어떻게 해야 하는 가?</li>
</ul>
<h4 id="테이블-만들기"><a href="https://developer.mozilla.org/ko/docs/Learn/HTML/Tables/Basics">테이블 만들기</a></h4>
<h4 id="react-icons"><a href="https://react-icons.github.io/react-icons/">react-icons</a></h4>
<p>: react에서 지원해주는 아이콘.
방법은 링크에서 친절하게 가르쳐 줌.</p>
<h4 id="arrayprototypefind"><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/find">array.prototype.find()</a></h4>
<p>Array 인스턴스의  find() 메서드는 제공된 테스트 함수를 만족하는 첫 번째 요소를 반환한다. 테스트 함수를 만족하는 값이 없으면 undefined가 반환된다.</p>
<h4 id="오름차순asc-내림차순desc">오름차순(asc), 내림차순(desc)</h4>
<ul>
<li><strong>comparator 메서드</strong>에서, a - b &gt; 0 이면 a가 더 크고, a - b &lt; 0 이면 b가 더 크다는 것을 이용하여, 값이 <strong>작은 순서대로</strong> 놓여지게 된다.
그렇다면 <strong>(a-b)에 -1</strong>을 곱해주면 순서는 값이 <strong>큰 순서대로</strong> 놓여지게 된다.</li>
</ul>
<pre><code>sortedData = [...data].sort((a, b) =&gt; {
      // comparator 함수
      const valueA = sortValue(a);
      const valueB = sortValue(b);

      // compare할 때, order 확인 : asc or desc
      // null일 때는 애초부터 이 함수가 돌지 않음
      // asc: 1, desc: -1
      const reverseOrder = sortOrder === &quot;asc&quot; ? 1 : -1;

      // 객체 타입별 비교
      if (typeof valueA === &quot;string&quot;) {
        return valueA.localeCompare(valueB) * reverseOrder; // order 순서
      } else {
        // Number일 경우
        return (valueA - valueB) * reverseOrder;
      }
    });</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[아키텍처, 칸반]]></title>
            <link>https://velog.io/@minjoo_huh/%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%B9%B8%EB%B0%98</link>
            <guid>https://velog.io/@minjoo_huh/%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%B9%B8%EB%B0%98</guid>
            <pubDate>Fri, 30 Aug 2024 03:14:02 GMT</pubDate>
            <description><![CDATA[<h2 id="📜-소프트웨어-아키텍처">📜 소프트웨어 아키텍처</h2>
<h3 id="⭐-정의">⭐ 정의</h3>
<p>: 소프트웨어의 골격이 되는 기본 구조이자, 소프트웨어를 구성하는 요소들 간의 관계를 표현하는 시스템의 구조 또는 구조체이다.</p>
<p><a href="https://velog.io/@gwichanlee/%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98Architecture">아키텍처 그림 참조</a></p>
<p><a href="https://m.blog.naver.com/thl0818/221486726887">자세한 설명</a></p>
<h3 id="⭐-특징">⭐ 특징</h3>
<ol>
<li><p>소프트웨어 개발 시 적용되는 원칙과 지침이며, 이해 관계자들의 의사소통 도구로 활용된다.</p>
</li>
<li><p>소프트웨어 아키텍처의 설계는 기본적으로 좋은 품질을 유지하면서 사용자의 비기능적 요구사항으로 나타난 제약을 반영하고, 기능적 요구사항을 구현하는 방법을 찾는 해결 과정이다.</p>
</li>
<li><p>애플리케이션의 분할 방법과 분할된 모듈에 할당된 기능, 모듈 간의 인터페이스 등을 결정한다.</p>
</li>
<li><p>소프트웨어 아키텍처 설게의 기본 원리로는 모듈화, 추상화, 단계적 분해, 정보은닉이 있다.</p>
</li>
</ol>
<h3 id="⭐-원리">⭐ 원리</h3>
<ul>
<li><p><strong>모듈화(Modularity)</strong> : 소프트웨어의 성능을 향상시키거나 시스템의 수정 및 재사용, 유지 관리 등이 용이하도록 시스템의 기능들을 모듈 단위로 나누는 것을 의미한다.</p>
</li>
<li><p><strong>추상화(Abstraction)</strong> : 추상화는 문제의 전체적이고 포괄적인 개념을 설계한 후 차례로 세분화하여 구체화시켜 나가는 것이다.</p>
</li>
<li><p><strong>단계적 분해(Stepwise Refinement)</strong> : 단계적 분해는 Niklaus Wirth에 의해 제안된 하향식 설계 전략으로, 문제를 상위의 중요 개념으로부터 하위의 개념으로 구체화시키는 분할 기법이다.</p>
</li>
<li><p><strong>정보 은닉(information Hiding)</strong> : 정보 은닉은 한 모듈 내부에 포함된 절차와 자료들의 정보가 감추어져 다른 모듈이 접근하거나 변경하지 못하도록 하는 기법이다.</p>
</li>
</ul>
<p><a href="https://blog.naver.com/molba06/223166451845">접근제한자</a> </p>
<h3 id="⭐-설계-과정">⭐ 설계 과정</h3>
<h4 id="1-설계-목표-설정">1) 설계 목표 설정</h4>
<p>: 시스템의 개발 방향을 명확히 하기 위해 설계에 영향을 주는 비즈니스 목표, 우선순위 등의 요구사항을 분석하여 전체 시스템의 설계 목표를 설정한다.</p>
<h4 id="2-시스템-타입-결정">2) 시스템 타입 결정</h4>
<p>: 시스템과 서브시스템의 타입을 결정하고, 설계 목표와 함께 고려하여 아키텍처 패턴을 선택한다.</p>
<h4 id="3-아케텍처-패턴-적용">3) 아케텍처 패턴 적용</h4>
<p>: 아키텍처 패턴을 참조하여 표준 아키텍처를 설계 한다.</p>
<h4 id="4-서브시스템-구체화">4) 서브시스템 구체화</h4>
<p>: 서브시스템의 기능 및 서브시스템 간의 상호작용을 위한 동작과 인터페이스를 정의한다.</p>
<h4 id="5-검토">5) 검토</h4>
<p>: 아키텍처가 설계 목표에 부합하는지, 요구사항이 잘 반영되었는지, 설계의 기본 원리를 만족하는지 등을 검토한다.</p>
<h3 id="⭐-사용해야하는-이유">⭐ 사용해야하는 이유</h3>
<p><a href="https://velog.io/@yeongori/%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98%EB%9E%80">https://velog.io/@yeongori/%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98%EB%9E%80</a></p>
<p>유지 보수에 최적화!</p>
<hr>
<h2 id="📜-칸반-kanban">📜 칸반 (Kanban)</h2>
<h3 id="⭐-칸반의-기원">⭐ 칸반의 기원</h3>
<ul>
<li>kanban은 간판 또는 광고판을 의미하는 일본어 용어이다.</li>
<li>&#39;오노 타이이치&#39;라는 산업 엔지니어가 도요타 자동차 회사에서 칸반을 개발하여 제조 효율성을 개선하였다.</li>
</ul>
<h3 id="⭐-칸반의-의미">⭐ 칸반의 의미</h3>
<ul>
<li>칸반(Kanban)은 반복적인 프로세스의 단게를 명확히 나누는 프로젝트 관리 방식이다.</li>
<li>애자일 방법론을 실현하는 도구의 종류.</li>
<li>칸반 보드에 팀별로 해야할 일(to do)과 진행중인 일을 잡아놓는다. </li>
<li>매일 짧은 회의를 거쳐 우선순위에 따라 업무 처리한다.</li>
</ul>
<blockquote>
<p>프레임워크를 통해 주요 작업을 관리하기 쉬운 작은 조각으로 세분화하고 칸반 보드에 배치하면 각 업무의 진행 상태를 시각적으로 확인할 수 있으며, 문제가 발견되면 즉시 해결할 수 있다.</p>
</blockquote>
<h3 id="⭐-애자일이란">⭐ 애자일이란?</h3>
<ul>
<li><p>&#39;민첩한&#39;, &#39;기민한&#39;이라는 의미이다.</p>
</li>
<li><p>고객의 <strong>요구사항 변화</strong>에 유연하게 대응할 수 있도록 <strong>일정한 주기를 반복</strong>하면서 개발과정을 진행한다.</p>
</li>
<li><p>스크럼도 여기에 포함됨.</p>
</li>
</ul>
<p><a href="https://business.adobe.com/kr/blog/basics/what-is-kanban">칸반으로 프로젝트를 관리하는 방법</a></p>
<p>극강의 효율을 위해 사용...</p>
<p><br><br></p>
<hr>
<h3 id="참조">참조</h3>
<p>정보처리기사 필기 2024 기본서 - 시나공
<a href="https://learn.microsoft.com/ko-kr/devops/plan/what-is-kanban">https://learn.microsoft.com/ko-kr/devops/plan/what-is-kanban</a>
<a href="https://open-pro.dict.naver.com/_ivp/#/pfentry/c0be8b4bdf92430c8b8fea537ae8468a/db75ef713bbd46de9d7f42a3046818ad">https://open-pro.dict.naver.com/_ivp/#/pfentry/c0be8b4bdf92430c8b8fea537ae8468a/db75ef713bbd46de9d7f42a3046818ad</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[(2024.08.29(목)) 슈퍼코딩 부트캠프 4주차 Day3 후기]]></title>
            <link>https://velog.io/@minjoo_huh/2024.08.29%EB%AA%A9-%EC%8A%88%ED%8D%BC%EC%BD%94%EB%94%A9-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-4%EC%A3%BC%EC%B0%A8-Day3-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@minjoo_huh/2024.08.29%EB%AA%A9-%EC%8A%88%ED%8D%BC%EC%BD%94%EB%94%A9-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-4%EC%A3%BC%EC%B0%A8-Day3-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Thu, 29 Aug 2024 13:46:42 GMT</pubDate>
            <description><![CDATA[<h2 id="to-do-list">To-do List</h2>
<ul>
<li>34강. 리스트 렌더링 - 3 - 리스트 필터링 ~ 37강. 스타일링 - 2 - CSS Modules</li>
</ul>
<hr>
<h2 id="📜34강-리스트-렌더링---3---리스트-필터링">📜34강. 리스트 렌더링 - 3 - 리스트 필터링</h2>
<h3 id="⭐리스트에-필터를-걸어주기">⭐리스트에 필터를 걸어주기</h3>
<ul>
<li>리스트에 상품들을 특정 조건에 따라 필터링 해서 보여주기</li>
<li>필터링을 할 때마다 업데이트가 되어야 한다.</li>
<li>값이 없으면, 없다는 문구를 나타낸다.</li>
</ul>
<h4 id="filter-state">filter state</h4>
<pre><code>const [filteredYear, setFilteredYear] = useState(&quot;2023&quot;);</code></pre><h4 id="filter-handler">filter handler</h4>
<pre><code>  const filterChangeHandler = (selectedYear) =&gt; {
    setFilteredYear(selectedYear);
  };</code></pre><h4 id="filter-items----array-list">filter items -- array list</h4>
<pre><code>  const filteredExpenses = props.items.filter((expense) =&gt; {
    return expense.date.getFullYear().toString() === filteredYear;
  });</code></pre><h4 id="html-input-data">html input data</h4>
<pre><code>&lt;ExpensesFilter
        selected={filteredYear}
        onChangeFilter={filterChangeHandler}
      /&gt;</code></pre><h4 id="html-input-data---filter-html--state-expensesfilterjs">html input data - filter html + state (ExpensesFilter.js)</h4>
<pre><code>const dropdownChangeHandler = (event) =&gt; {
    props.onChangeFilter(event.target.value);
  };

  return (
    &lt;div className=&#39;expenses-filter&#39;&gt;
      &lt;div className=&#39;expenses-filter__control&#39;&gt;
        &lt;label&gt;Filter by year&lt;/label&gt;
        &lt;select value={props.selected} onChange={dropdownChangeHandler}&gt;
          &lt;option value=&#39;2023&#39;&gt;2023&lt;/option&gt;
          &lt;option value=&#39;2022&#39;&gt;2022&lt;/option&gt;
          &lt;option value=&#39;2021&#39;&gt;2021&lt;/option&gt;
          &lt;option value=&#39;2020&#39;&gt;2020&lt;/option&gt;
        &lt;/select&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );</code></pre><h4 id="html-filtered-items">html filtered items</h4>
<pre><code>{/* 3항 연산자 */}
      {filteredExpenses.length &gt; 0 ? (
        filteredExpenses.map((item) =&gt; (
          &lt;ExpenseItem
            title={item.title}
            amount={item.amount}
            date={item.date}
          /&gt;
        ))
      ) : (
        &lt;p&gt;값이 없습니다.&lt;/p&gt;
      )}
      {/* {filteredExpenses.length === 0 &amp;&amp; &lt;p&gt;값이 없습니다.&lt;/p&gt;} */}
      {/* {expensesContent} */}</code></pre><hr>
<h2 id="📜35강-스타일링---1---동적인-스타일링">📜35강. 스타일링 - 1 - 동적인 스타일링</h2>
<h3 id="⭐인라인-스타일링">⭐인라인 스타일링</h3>
<ul>
<li>직접 요소에 스타일링을 넣어서 만듦</li>
</ul>
<h4 id="일반-인라인-스타일링">일반 인라인 스타일링</h4>
<pre><code>&lt;FormCotrolInput
    type=&quot;text&quot;
    ...
    style={{ backgroundColor: &quot;salmon&quot;, borderColor: &quot;red&quot;}}
/&gt;</code></pre><h4 id="3항-연산자-인라인-스타일링">3항 연산자 인라인 스타일링</h4>
<pre><code>isValid - true or false / state 변수

&lt;FormCotrolInput
    type=&quot;text&quot;
    ...
    style={{
        backgroundColor: isValid ? &quot;transparent&quot; : &quot;salmon&quot;,
        borderColor: isValid ? &quot;#ccc&quot; : &quot;red&quot;,
    }}
/&gt;</code></pre><h3 id="⭐css-클래스를-동적으로-조작하기">⭐CSS 클래스를 동적으로 조작하기</h3>
<h4 id="css-file---class">css file - class</h4>
<pre><code>.form-control.invalid input {
  background-color: salmon;
  border-color: red;
}</code></pre><h4 id="class-불러오기-name-옆에-class-명-붙이기">class 불러오기, name 옆에 class 명 붙이기</h4>
<pre><code>&lt;form onSubmit={...Handler}&gt;
    &lt;div className=&quot;form-control invalid&quot;&gt;
        &lt;label&gt;목표&lt;/label&gt;
        &lt;input
            type=&quot;text&quot;
            ...
        /&gt;
    &lt;/div&gt;
&lt;/form&gt;</code></pre><h4 id="동적으로-불러오고-싶어여">동적으로 불러오고 싶어여!</h4>
<pre><code>isValid - true or false / state 변수

&lt;form onSubmit={...Handler}&gt;
    &lt;div className=`form-control ${!isValid ? &#39;invalid&#39; : &#39;&#39;}`&gt;
        &lt;label&gt;목표&lt;/label&gt;
        &lt;input
            type=&quot;text&quot;
            ...
        /&gt;
    &lt;/div&gt;
&lt;/form&gt;</code></pre><hr>
<h2 id="📜36강-스타일링---2---styled-components">📜36강. 스타일링 - 2 - styled-components</h2>
<h3 id="⭐css-in-js">⭐CSS-in-JS</h3>
<ul>
<li>자바스크립트 코드를 CSS 에서 작성하는 방식</li>
</ul>
<h3 id="⭐styled-component">⭐styled component</h3>
<ul>
<li>CSS-in-JS 방식은 자바스크립트에서 CSS를 작성하는 방식이다.</li>
<li>CSS-in-JS 방식은 CSS를 컴포넌트 레벨로 추상화 해서 관리할 수 있다.</li>
<li>styled-components는 리액트 컴포넌트 스타일링을 위해  CSS를 JS로 쓸 수 있게 만든 가장 많이 쓰이는 도구 중 하나이다.</li>
</ul>
<h4 id="styled-components-download">styled-components download</h4>
<ul>
<li>버전 이슈 때문에 가장 최신 버전 다운로드<pre><code>&gt; npm install styled-components@latest</code></pre></li>
</ul>
<h4 id="styled-components-import-하기">styled-components import 하기</h4>
<pre><code>import { styled } from &quot;styled-components&quot;;</code></pre><h4 id="styled-component-표현하기">styled component 표현하기</h4>
<pre><code>const DivControl = styled.div`
  margin: 0.5rem 0;
`;

const DivControlLabel = styled.label`
  font-weight: bold;
  display: block;
  margin-bottom: 0.5rem;
`;

const DivControlInput = styled.input`
  display: block;
  width: 100%;
  border: 1px solid #ccc;
  font: inherit;
  line-height: 1.5rem;
  padding: 0 0.25rem;
  ${(props) =&gt;
    !props.isValid &amp;&amp; // isValid = false, 조건 성립
    `background-color: salmon;
    border-color: red;
    `}
`;
</code></pre><h4 id="styled-components-값-불러오기">styled-components 값 불러오기</h4>
<pre><code>const test = () =&gt; {

  return &lt;DivControl&gt;
    &lt;DivControlLabel&gt;행운의 네잎클로버!&lt;/DivControlLabel&gt;
    &lt;DivControlInput
        type=&quot;text&quot;
        onChange={...handler}
        isValid={isValid}
    /&gt;
  &lt;/DivControl&gt;;
};

export default test;</code></pre><hr>
<h2 id="📜37강-스타일링---2---css-modules">📜37강. 스타일링 - 2 - CSS Modules</h2>
<h3 id="⭐css-modules"><a href="https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/">⭐CSS Modules</a></h3>
<ul>
<li>CSS 사용 시, Class 이름을 고유한 값으로 자동 생성한다.</li>
<li>React에서 CSS Modules을 사용한다면, Component에 적용하는 style 클래스의 이름이 중첩되는 현상을 방지할 수 있다.</li>
</ul>
<h4 id="css-파일을-파일명modulecss로-작성">CSS 파일을 <code>파일명.module.css</code>로 작성</h4>
<p>사진 첨부</p>
<pre><code>.testControl label{
}

.testControl input{
     font: inherit;
      padding: 0.5rem;
      border-radius: 6px;
      border: 1px solid #ccc;
      width: 20rem;
      max-width: 100%;
}

.testActions{
  text-align: right;
}

.isTrue{
    border: 1px solid red;
}</code></pre><h4 id="css-파일-imoprt-하기-모듈처럼">CSS 파일 imoprt 하기 (모듈처럼)</h4>
<pre><code>import styles from &quot;./PaymentForm.module.css&quot;;</code></pre><h4 id="사용해보기">사용해보기</h4>
<pre><code>isValid - true or false / state 변수

&lt;div className={styles.test}&gt;
    &lt;form... &gt;
        &lt;div className={styles.testControl}&gt;
            &lt;div
                className={`${styles.testControl} ${!isValid &amp;&amp; styles.isTrue}`}
            &gt;
                &lt;label&gt;안녕!&lt;/label&gt;
            ...
            &lt;/div&gt;
            &lt;div className={styles.testControl}&gt;
                &lt;label&gt;반가워!&lt;/label&gt;
                ...
            &lt;/div&gt;
            ...
        &lt;/div&gt;
        &lt;div className={styles.testActions}&gt;
            &lt;button type=&quot;submit&quot;&gt;제출&lt;/button&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;</code></pre><hr>
<h4 id="부족한-점">부족한 점</h4>
<ul>
<li>매번 github에서 다운로드 받아서 console에 <code>&gt; npm install -save react-scripts</code>를 적기가 귀찮다...</li>
</ul>
<h4 id="스스로-시도해-본-것들">스스로 시도해 본 것들</h4>
<ul>
<li>googling</li>
</ul>
<h4 id="해결-내용">해결 내용</h4>
<ul>
<li>위의 부족한 점을 해결할 때 썼던 <a href="https://goddaehee.tistory.com/298">사이트</a>에서 있는 코드들을 cmd에서 뿌리기 (workspace에서만)</li>
</ul>
<h4 id="알게된-점">알게된 점</h4>
<h4 id="헷갈리거나-실수한-점">헷갈리거나 실수한 점</h4>
<ul>
<li>과제할 때(filter price), state로 받은 데이터를 filter로 배열로 받아 html에 뿌릴려고 할때, 배열의 length 값이 0보다 클때 html을 뿌리면 되는데... 반대로 줘버렸다...;; (0보다 작을때... 이러니깐 안나오지!)</li>
</ul>
<h4 id="회고">회고</h4>
<ul>
<li>결국 진짜... 아파서 어제 쉬게 되었음...! 진짜ㅠㅠ 왜ㅠㅠ 아직도 목이랑 머리가 아프긴 하지만... 버틸만 한가..? 버틸만 하니깐 이것저것 했겠지! 지금은 잠이 와서 오락가락하는 것 같긴함!</li>
<li>그래도 할 건 하고 자야한다! 춥다!!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[(2024.08.27(화)) 슈퍼코딩 부트캠프 4주차 Day2 후기]]></title>
            <link>https://velog.io/@minjoo_huh/2024.08.27%ED%99%94-%EC%8A%88%ED%8D%BC%EC%BD%94%EB%94%A9-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-4%EC%A3%BC%EC%B0%A8-Day2-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@minjoo_huh/2024.08.27%ED%99%94-%EC%8A%88%ED%8D%BC%EC%BD%94%EB%94%A9-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-4%EC%A3%BC%EC%B0%A8-Day2-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Tue, 27 Aug 2024 14:56:19 GMT</pubDate>
            <description><![CDATA[<h2 id="to-do-list">To-do List</h2>
<ul>
<li>29강, 리액트 상태 - 5 - Form 제출 ~ 33강 리스트 렌더링 - 2 - KEY</li>
</ul>
<hr>
<h2 id="📜29강-리액트-상태---5---form-제출">📜29강. 리액트 상태 - 5 - Form 제출</h2>
<h3 id="⭐form-제출하기">⭐Form 제출하기</h3>
<ul>
<li><form> 에는 onSubmit 이벤트 리스너가 있어서 form의 제출 이벤트를 핸들링</li>
<li>이 이벤트를 발생하기 위해서는 <code>&lt;button type=&quot;submit&quot;&gt;</code>이 필요</li>
</ul>
<h4 id="eventpreventdefault">event.preventDefault()</h4>
<ul>
<li>해당 event에서 기본적으로 실행되는 로직을 실행되지 않게 하고 싶은 경우
1) a 태그 클릭 시 href 링크로 이동
2) form의 submit을 누르면 새로 실행이 됨</li>
</ul>
<pre><code>// button에서 submit 신호를 받으면 수행되는 함수
const buttonSubmitHandler = (event) =&gt; {
    event.preventDefault();

    console.log(&quot;submit&quot;);
}

return (
    ...
    // form 안에서 submit 신호를 받으면 함수 불러오기
    &lt;form onSumbmit={buttonSubmitHandler}&gt;
        로직
        ...

        &lt;button type=&quot;submit&quot;&gt;버튼&lt;/button&gt;
        ...
    &lt;/form&gt;
    ...
);</code></pre><h3 id="⭐two-way-binding">⭐Two-way binding</h3>
<ul>
<li>form을 제출하고 값을 모두 초기화 해주고 싶을 때</li>
</ul>
<h4 id="1-input에-상태를-value-속성으로-넣어준-후">1) Input에 상태를 value 속성으로 넣어준 후</h4>
<ul>
<li>Value에 useState 속성값 넣기 (objectState.name)<pre><code>&lt;input
  type=&quot;text&quot;
  onChange={inputTextHandler}
  value={objectState.name}
/&gt;
  ...
  ...</code></pre></li>
</ul>
<h4 id="2-제출을-한-후에-상태를-초기화-해주면">2) 제출을 한 후에 상태를 초기화 해주면</h4>
<ul>
<li>submit handler 함수에 상태 초기화 넣기.<pre><code>setObjectState({
  name: &quot;&quot;,
  price: 0,
  today: null,
});</code></pre></li>
</ul>
<h4 id="3-value에-초기화된-상태가-반영되어-ui에-업데이트">3) Value에 초기화된 상태가 반영되어 UI에 업데이트</h4>
<ul>
<li>저장!</li>
</ul>
<h4 id="❌날짜-초기화가-안됨ㅜㅜ">❌날짜 초기화가 안됨ㅜㅜ</h4>
<ul>
<li>날짜를 null 대신 초기화 대신 Date() 메소드로 초기화하기<pre><code>today: null, =&gt; today: new Date(),</code></pre></li>
</ul>
<hr>
<h2 id="📜30강-리액트-상태---6---자식과-부모간-상태-이동">📜30강. 리액트 상태 - 6 - 자식과 부모간 상태 이동</h2>
<h3 id="⭐자식-컴포넌트에서-부모-컴포넌트로-상태-올리기">⭐자식 컴포넌트에서 부모 컴포넌트로 상태 올리기</h3>
<ul>
<li>자식 컴포넌트에서 작성한 form state를 부모 컴포넌트로 올리기</li>
</ul>
<h4 id="1-props로-부모-컴포넌트의-data를-받는-함수를-자식에게로-보냄">1) props로 부모 컴포넌트의 data를 받는 함수를 자식에게로 보냄.</h4>
<p>-&gt; 바로 state를 보내는 방법이 없기 때문에 함수를 보내서 데이터를 받는다.</p>
<p>▪️부모 컴포넌트</p>
<pre><code>// 1. parent에서 자식의 form 정보를 받는 함수
  const getPaymentFormDate = (data) =&gt; {
    console.log(data);

    setExpenses([
      {
        id: Math.random().toString(),
        title: data.name,
        amount: data.price,
        date: data.today,
      },
    ]);
  };

return (
    &lt;&gt;
      {/* 2. props로 함수 보내기 */}
      &lt;PaymentForm getPaymentFormDate={getPaymentFormDate} /&gt;
    &lt;/&gt;
);</code></pre><h4 id="2-부모-컴포넌트에서-props로-받은">2) 부모 컴포넌트에서 props로 받은</h4>
<p>▫️자식 컴포넌트</p>
<pre><code>const PaymentForm = ({getPaymentFormDate}) =&gt; {
...

    const buttonSubmitHandler = (event) =&gt; {
        event.preventDefault();

        // 4. button submit이 돌면 함수가 실행
            // objectState 정보 (함수가 가리키고 있는 부모 컨포넌트의 함수로) 보내기
            getPaymentFormData(objectState);
    }

    ...

    return ...
}</code></pre><h3 id="⭐부모-컴포넌트의-상태를-자식-컴포넌트에-전달">⭐부모 컴포넌트의 상태를 자식 컴포넌트에 전달</h3>
<ul>
<li>자식 컴포넌트에서 부모 컴포넌트로 올려진 state를 또 다른 컴포넌트로 전달해보기</li>
</ul>
<p>1) HTML 창에서 값 입력(input) 받기
2) submit button click, 부모 컴포넌트에  data 전달. (props 로 받은 함수에 의해서)
3) 부모 컴포넌트는 함수에서 데이터 저장 및 할당</p>
<h4 id="4-또-다른-자식-컴포넌트에-다른-데이터-보내기-props">4) 또 다른 자식 컴포넌트에 다른 데이터 보내기 (props)</h4>
<h4 id="5-자식-컴포넌트는-props로-받은-데이터를-html-창에-올릴-수-있다">5) 자식 컴포넌트는 props로 받은 데이터를 HTML 창에 올릴 수 있다.</h4>
<h4 id="😫typeerror--propsdategetfullyear-is-not-a-function">😫TypeError : props.date.getFullYear is not a function</h4>
<p>  <img src="https://velog.velcdn.com/images/minjoo_huh/post/b3688233-6487-4bdf-a40b-1b83882370be/image.png" alt=""></p>
<ul>
<li>date 관련 타입 에러</li>
<li>자식 컴포넌트에서 props로 데이터를 받고 처리할 때 string으로 뜬다.</li>
<li>그래서 state를 업데이트 할 때, event.target.value를 그냥 받아오는 것을 new Date(event.target.value)로 받아옴.<pre><code>const inputTodayHandler = (event) =&gt; {
  setObjectState((prevState) =&gt; ({
    ...prevState,
    today: new Date(event.target.value),
  }));
};</code></pre></li>
<li>해결!</li>
</ul>
<hr>
<h2 id="📜31강-리액트-상태---7---이미지-처리">📜31강. 리액트 상태 - 7 - 이미지 처리</h2>
<h3 id="⭐이미지-가져오기">⭐이미지 가져오기</h3>
<ul>
<li>이미지 파일을 불러오는 방법</li>
<li>image 파일명 같은 경우는 대문자부터 시작하는 경우가 많다.</li>
<li>이미지는 .png 같은 확장자가 반드시 붙여져야 한다. (js는 안붙었음!!)<pre><code>import TestImage from &quot;./images/alexa.png&quot;;
...
&lt;img src={TestImage} alt=&quot;test&quot;&gt;</code></pre><h3 id="⭐이미지-파일의-종류">⭐이미지 파일의 종류</h3>
<h4 id="▪️jpg-jpeg">▪️jpg, jpeg</h4>
</li>
<li>pixel 단위</li>
<li>높은 압축률 =&gt; 파일 크기가 작다.</li>
<li>이미지 퀄리티가 손상될 수 있음 (Lossy) → 압축되면서 손상 가능성 있음</li>
<li>수천 가지 팔레트 색 - 하나의 픽셀당</li>
<li>사진☑️ 로고, 라인❌- 잘못하다보면 깨질 수 있으니깐.... 깔끔하지 않지...</li>
<li>캡처 전달, 고용량 이미지 전송, 썸네일 전송 </li>
</ul>
<h4 id="▫️png">▫️png</h4>
<ul>
<li>손실 없이 이미지를 압축(Lossless) = 압축이 잘되지만, 파일 크기가 큼. (&lt;-&gt; Lossy)</li>
<li>W3C 권장 표준 - web 공식문서</li>
<li>간단한 배너 이미지☑️</li>
<li>배경을 지우고 해당 로고만 볼 수 있는 기능도 있음.</li>
<li>배너 이미지, 선명한 이미지, 백그라운드 없는 로고 이미지에서 많이 사용</li>
</ul>
<h4 id="▪️svg">▪️svg</h4>
<ul>
<li>2차원 벡터 그래픽 - 1000배를 늘려도 깨지지 않음.</li>
<li>해상도 상관 없이 이미지 품질 좋음</li>
<li>로고, 라인☑️</li>
<li>복잡한 이미지❌ - 굉장히 파일이 복잡하고 커지고 무거워지고...</li>
<li>아이콘, 선, 간단한 도형 등등 처리할 때. 이것들을 우리가 자유자재로 핸들링하고 싶을 때... </li>
</ul>
<p>bmp, etc...</p>
<h3 id="⭐이미지-용량에-따른-브라우저에서의-처리">⭐이미지 용량에 따른 브라우저에서의 처리</h3>
<p><img src="https://velog.velcdn.com/images/minjoo_huh/post/e691b132-7afe-4bfb-beb5-5b7622af91ae/image.png" alt=""></p>
<h4 id="alexapng-4kb">alexa.png (4KB)</h4>
<ul>
<li>9.7KB보다 작으므로(&lt; 9.7KB), inlined(encoding하여 string 형태로 저장) 된다.</li>
<li>❓Base64 : 이진 데이터를 기수-64 표현으로 변환하여 ASCII 문자열 방식으로 나타내는 유사한 이진 데이터를 텍스트로 인코딩 방식의 그룹.</li>
<li>큰 파일X, 주로 작은 파일에서 주로 사용. 커지면 그만큼 주소가 굉장히 길어짐;;</li>
</ul>
<h4 id="siripng-57kb">siri.png (57KB)</h4>
<ul>
<li>9.7KB보다 크므로(&gt; 9.7KB), seperate files(파일 압축)해서 그대로 개발 서버에 저장된다.</li>
</ul>
<h3 id="⭐이미지-크기를-조절하기">⭐이미지 크기를 조절하기</h3>
<p>이미지 크기를 조절하기</p>
<h4 id="1-img-태그의-속성인-width-height를-작성해-주기">1) <code>&lt;img&gt;</code> 태그의 속성인 width, height를 작성해 주기</h4>
<pre><code>&lt;img src={TestImage} alt=&quot;test&quot; width={500} height={500} /&gt;</code></pre><h4 id="2-style-속성으로-width-height-값-작성해주기">2) Style 속성으로 width, height 값 작성해주기</h4>
<pre><code>&lt;img src={TestImage} alt=&quot;test&quot; style={{ width: 500, height: 500 }} /&gt;</code></pre><hr>
<h2 id="📜32강-리스트-렌더링---1---리스트-렌더링">📜32강. 리스트 렌더링 - 1 - 리스트 렌더링</h2>
<h3 id="❓list">❓List?</h3>
<ul>
<li><a href="https://velog.io/@tbh05158/Array-List">JS 배열 = 동적 배열 (Array List)</a></li>
<li>자료구조 List
<a href="https://taco99.tistory.com/7">종류</a> 
<a href="https://cdragon.tistory.com/entry/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8List-ArrayList">좀 더 자세한 </a></li>
</ul>
<h3 id="⭐리스트를-state-값과-연동하기---추가">⭐리스트를 state 값과 연동하기 - 추가</h3>
<ul>
<li>결제 추가를 하면 아래 리스트에 값이 추가되게 만들어 보기.</li>
<li>setExpenses에 ...expenses 스프레드 연산자로 연결하기!
▪️App.js<pre><code>setExpenses([
    {
      id: Math.random().toString(),
      title: data.name,
      amount: data.price,
      date: new Date(data.today),
    },
    ...expenses, // 배열의 값이 몇개가 들어올지 모르니깐.. 스프레드 연산자로 확장.
  ]);</code></pre></li>
</ul>
<h3 id="⭐리스트를-state-값과-연동하기---삭제">⭐리스트를 state 값과 연동하기 - 삭제</h3>
<p>1) 삭제 버튼 만들기
2) 삭제 로직은 js 파일 어디든 넣을 수 있지만, state를 생성한 곳에서 하는 게 가장 효율적임!
3) 삭제 방법 2가지!</p>
<h4 id="3-1-filter">3-1) filter</h4>
<p>: 주어진 함수의 테스트를 통과하는 모든 요소들을 모아 새로운 배열로 반환합니다.</p>
<ul>
<li>filter(word =&gt; word.length &gt; 6)  : word.length라는 조건문이 true인 요소들을 모아 새로운 배열을 만들어냄</li>
<li>id, 즉 primary key를 가져올 수 있을 때 사용하는 것이 유리하다.<pre><code>const newFilteredArray = expense.filter((item) =&gt; item.id !== id);
setExpense(newFilteredArray);</code></pre></li>
</ul>
<h4 id="3-2-slice">3-2) slice</h4>
<p>: 어떤 배열의 begin부터 end까지 (end 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환합니다. 원본 배열은 바뀌지 않습니다.</p>
<ul>
<li>배열의 index 값을 받을 수 있는 환경일 때 사용하는 것이 유리하다.</li>
<li>시작부터 끝까지 자르는 것을 의미.</li>
<li>index 값이 필요한 것이기 때문에 delete 작업을 다르게 해야함...</li>
</ul>
<p>▪️App.js</p>
<pre><code>const deleteExpenseItem = (index) =&gt; {
    // 2. slice
    // [0, 1, 2, 3, .. , index, index+1, .. , n-1]
    // index 요소를 삭제하고 싶다.
    // [0, 1, 2, 3, .. , index-1, index+1, .., n-1]
    // [0, 1, 2, ... , index-1] [index+1, .., n-1] 두가지의 배열로 만듦
    const beforeArray = expenses.slice(0, index);
    const afterArray = expenses.slice(index + 1); // end는 생략 가능
    setExpenses([...beforeArray, ...afterArray]);
  };

return (
    &lt;&gt;
        ...
        &lt;Expenses items={expenses} deleteExpenseItem={deleteExpenseItem} /&gt;
    &lt;/&gt;
);</code></pre><p>▫️Expenses.js - 다시 자식 컴포넌트로 함수 보내기 (props)</p>
<pre><code>{props.items.map((item, index) =&gt; (
        &lt;ExpenseItem
          id={item.id}
          index={index}
          title={item.title}
          amount={item.amount}
          date={item.date}
          deleteExpenseItem={props.deleteExpenseItem}
        /&gt;
      ))}</code></pre><p>▪️ExpenseItem.js - 삭제 버튼 + onClick 이벤트</p>
<pre><code>&lt;button onClick={() =&gt; props.deleteExpenseItem(props.index)}&gt;
          삭제하기
&lt;/button&gt;</code></pre><hr>
<h2 id="📜33강-리스트-렌더링---2---key">📜33강. 리스트 렌더링 - 2 - KEY</h2>
<p><img src="https://velog.velcdn.com/images/minjoo_huh/post/e7d07682-d581-4601-a527-8a1a9308dc2a/image.png" alt=""></p>
<ul>
<li>div 요소 혹은 컴포넌트들이 서로 구분이 안돼, 식별이 안되어 식별자를 두라는 의미.</li>
<li>식별자를 두지 않으면 비슷한 것들 중에 하나의 state가 변경될 때, 전부 리랜더링이 된다.</li>
</ul>
<h3 id="⭐리스트의-key">⭐리스트의 key</h3>
<ul>
<li>리액트에서 리스트 형태로 만드는 모든 컴포넌트 (HTML tag,  커스텀 컴포넌트 등)에 대해서 key값을 고유하게 부여해 주어야 에러가 발생하지 않는다.</li>
<li>컴포넌트를 생성할 때 key 값을 부여해줘서 에러를 방지한다.</li>
<li>key는 꼭 unique한 값이어야 한다.<pre><code>{props.items.map((item, index) =&gt; (
      &lt;ExpenseItem
        key={item.id}
        id={item.id}
        index={index}
        title={item.title}
        amount={item.amount}
        date={item.date}
        deleteExpenseItem={props.deleteExpenseItem}
      /&gt;
    ))}</code></pre></li>
</ul>
<hr>
<h3 id="부족한-점">부족한 점</h3>
<ul>
<li>list의 의미</li>
</ul>
<h3 id="스스로-시도해-본-것들">스스로 시도해 본 것들</h3>
<ul>
<li>구글링</li>
</ul>
<h3 id="해결-내용">해결 내용</h3>
<ul>
<li>array list (그냥 js에서의 배열을 의미)</li>
</ul>
<h3 id="알게된-점">알게된 점</h3>
<h3 id="헷갈리거나-실수한-점">헷갈리거나 실수한 점</h3>
<h3 id="회고">회고</h3>
<ul>
<li>오랜만의 땅바닥 신세... 몸살 날 것 같은뎅... 큰일이다!</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>