<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hye_rin.log</title>
        <link>https://velog.io/</link>
        <description>FE Developer</description>
        <lastBuildDate>Sun, 21 May 2023 07:50:10 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hye_rin.log</title>
            <url>https://velog.velcdn.com/images/hye_rin/profile/6694c4c6-7244-4fe0-aa9b-217d377ffc90/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hye_rin.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hye_rin" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[ReactNavigation] 나만 몰라 navigate랑 push 차이점 🫠]]></title>
            <link>https://velog.io/@hye_rin/ReactNavigation-%EB%82%98%EB%A7%8C-%EB%AA%B0%EB%9D%BC-navigate%EB%9E%91-push-%EC%B0%A8%EC%9D%B4%EC%A0%90</link>
            <guid>https://velog.io/@hye_rin/ReactNavigation-%EB%82%98%EB%A7%8C-%EB%AA%B0%EB%9D%BC-navigate%EB%9E%91-push-%EC%B0%A8%EC%9D%B4%EC%A0%90</guid>
            <pubDate>Sun, 21 May 2023 07:50:10 GMT</pubDate>
            <description><![CDATA[<h2 id="1-🤔-하는-역할을-같지-않나">1. 🤔 하는 역할을 같지 않나?</h2>
<p>React Navigation의 <code>navigate()</code>와 <code>push()</code>로 화면을 이동할 수 있다. 
그래서 이 둘은 <strong><span style="color:royalblue">화면을 이동시켜준다는 점은 동일</span></strong>하다는 것!</p>
<p>둘 다 화면을 이동시켜준다고 생각해 나는 이 둘을 별다른 구분 없이 사용하곤 했었다.
(<del>뭔가 다름을 느꼈음에도 흐린눈했던 나 반성하자</del>)</p>
<p><code>navigate()</code>와 <code>push()</code>모두 새로운 화면으로 넘어갈 때는 크게 다를 점이 없었기에 혼동해 사용해왔던 것인데.. 
이 둘은 <strong><span style="color:royalblue">같은 화면을 이동할 때 그 차이</span></strong>를 느낄 수 있다!</p>
<pre><code class="language-javascript">navigation.navigate(&#39;RouteName&#39;); 
navigation.push(&#39;RouteName&#39;);</code></pre>
<p><br><br></p>
<h2 id="2-🙅🏻♀️-달라달라">2. 🙅🏻‍♀️ 달라달라</h2>
<h3 id="1-push">(1) <code>push()</code></h3>
<p>아래의 이미지는 React Navigation 공식문서에서 설명한 <code>push()</code>를 사용했을 때의 경우이다.
여기서 확인할 수 있는 점은 다음과 같았다.</p>
<blockquote>
<ol>
<li><strong>Home ➡️ Details ➡️ Details ➡️ Details</strong> 와 같이 스크린이 이동되고 있다.</li>
<li><strong><span style="color:royalblue">같은</span></strong> Details 화면에서 Details 화면으로 이동하는 것임에도 <strong><span style="color:royalblue">화면전환 효과</span></strong>가 보인다.</li>
<li>뒤로 가기를 눌렀을 때, <strong><span style="color:royalblue">이전의 Details 화면들을 모두 지나야</span></strong> Home 화면을 볼 수 있다.</li>
</ol>
</blockquote>
<p><img src="https://reactnavigation.org/assets/navigators/stack/stack-push.mov" alt=""></p>
<p>이를 통해 <code>push()</code>는 어느 화면으로 이동하느냐에 상관없이
stack 구조에 차곡차곡 화면이 쌓인다는 것인다는 것을 알 수 있다.</p>
<p><strong>Details ➡️ Details</strong>와 같이 같은 화면으로 이동할 때조차 각각의 Details화면이
stack에 순서대로 쌓이게 되고, 뒤로가기(<code>pop()</code>)했을 때는 stack의 가장 위에서부터 하나씩 제거해나간다.
<img src="https://velog.velcdn.com/images/hye_rin/post/b54c6909-b3d1-4eb5-9590-95d970e721d4/image.png" alt=""></p>
<p>공식문서에서는 <code>push()</code>를 다음과 같이 요약하고 있다.
우리는 push를 우리가 원하는 만큼 호출할 수 있고, push는 계속해서 stack에 화면을 쌓아줄 것이라고!</p>
<blockquote>
<p>📜 <strong><a href="https://reactnavigation.org/docs/navigating/">React Navigation</a></strong>
<em>We can call <code>navigation.push(&#39;RouteName&#39;)</code> as many times as we like and it will continue pushing routes.</em></p>
</blockquote>
<br>

<h3 id="2-navigate">(2) <code>navigate()</code></h3>
<p><code>navigate()</code>는 <strong><span style="color:royalblue">새로운 화면으로 이동</span></strong>할 경우엔 
<code>push()</code>와 동일하게 stack에 새로운 화면이 차곡차곡 쌓인다.</p>
<p>하지만 <strong><span style="color:royalblue">같은 화면으로 이동</span></strong>할 경우,
위의 <code>push()</code>와 같이 stack에 같은 화면이 쌓이지도, 화면 전환 효과가 보이지도 않는다.
<code>navigate()</code>의 두번째 인자로 전달해주는 <strong>💥parameter값만 바꾸어 보여줄 뿐💥</strong>이다.</p>
<pre><code class="language-jsx">navigation.navigate(&#39;RouteName&#39;, { id : route.params.id })</code></pre>
<br>

<p><strong>Home ➡️ Details (id:1) ➡️ Details (id:2) ➡️ Details (id:3)</strong> 와 같이 이동한다고 했을때
stack에는 Home 화면 <strong><span style="color:royalblue">1개</span></strong>와 Details 화면 <strong><span style="color:royalblue">1개</span></strong>만 쌓이게 된다.</p>
<p>Details 화면은 paramerter값만 1, 2, 3으로 바뀌는 것이다. ❌<strong><span style="color:red">Details 화면이 또다시 쌓이는 것이 아니라</span></strong>❌
따라서, 가장 마지막 Details 화면(id:3)에서 뒤로 가기를 누르면 Home화면이 나오는 것을 볼 수 있다.</p>
<p><br><br></p>
<h2 id="3-📝-정리-및-느낀점">3. 📝 정리 및 느낀점</h2>
<blockquote>
<ol>
<li>새로운 화면 이동<ul>
<li><code>navigate()</code>와 <code>push()</code>모두 stack에 새로운 화면을 차곡차곡 쌓는다.<br></li>
</ul>
</li>
<li>같은 화면 이동 (<strong>A ➡️ A ➡️ B</strong>)<ul>
<li><code>push()</code>는 stack에 <strong>A, A, B</strong>화면이 순차적으로 쌓고, <code>navigate()</code>는 stack에 <strong>A, B</strong>화면을 쌓는다.</li>
<li><code>navigate()</code>는 같은 화면을 이동할 경우 stack에 같은 화면을 또다시 쌓지 않고, parameter값만 변경해준다.</li>
</ul>
</li>
</ol>
</blockquote>
<p>화면 이동이 필요한 경우, <code>push()</code>를 사용하면 어떤 화면이라도(같은 화면이라도)
항상 순차적으로 stack에 화면을 쌓아주기 때문에 
뒤로 가기를 했을 때 내가 원하는 화면을 보여줄 가능성이 크다.
탭이동과 같은 화면 이동이 아닌 경우에는 <code>push()</code>를 사용해야겠다.</p>
<p>어영부영 잘 작동한다고 넘어가지 말고,
왜 화면 이동에<code>push()</code>가 아닌 <code>navigate()</code>를 사용했는지 설명할 수 있는
근거있는 개발자가 되자‼️</p>
<p><br><br></p>
<h2 id="4-📜-참고">4. 📜 참고</h2>
<ul>
<li><a href="https://reactnavigation.org/docs/navigating/">React Navigation Docs</a></li>
<li><a href="https://code-masterjung.tistory.com/126">[React Navigation] 내비게이션 및 Hooks 익히기</a></li>
<li><a href="https://sites.google.com/site/ionic2withangular2/home/understanding-ionic-2-navigation-with-navcontroller">Understanding Ionic 2: Navigation with NavController</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[도널드노먼의 UX 디자인 특강] 복잡한 세상의 디자인]]></title>
            <link>https://velog.io/@hye_rin/%EB%8F%84%EB%84%90%EB%93%9C%EB%85%B8%EB%A8%BC%EC%9D%98-UX-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8A%B9%EA%B0%95-1.-%EB%B3%B5%EC%9E%A1%ED%95%9C-%EC%84%B8%EC%83%81%EC%9D%98-%EB%94%94%EC%9E%90%EC%9D%B8</link>
            <guid>https://velog.io/@hye_rin/%EB%8F%84%EB%84%90%EB%93%9C%EB%85%B8%EB%A8%BC%EC%9D%98-UX-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8A%B9%EA%B0%95-1.-%EB%B3%B5%EC%9E%A1%ED%95%9C-%EC%84%B8%EC%83%81%EC%9D%98-%EB%94%94%EC%9E%90%EC%9D%B8</guid>
            <pubDate>Tue, 21 Feb 2023 12:10:27 GMT</pubDate>
            <description><![CDATA[<h2 id="읽게-된-이유">읽게 된 이유</h2>
<hr>
<p>디자인 전공이라 그런지 프론트엔드 개발 공부를 하며 UI/UX 디자인에도 관심이 많았다.
하지만 제대로 알고 있지는 못했고, 어디서부터 알아가면 좋을지도 고민이었다.
그렇게 생각해낸 것은 바로 <strong><span style="color:royalblue">책</span></strong>! </p>
<p>&#39;도널드노먼의 UX 디자인 특강&#39;의 저자인 도널드 노먼은 UX의 창시자라고 한다. 
그래서 이 책은  <strong><span style="color:royalblue">UX 디자인의 바이블</span></strong>과도 같다고...!
그래서 다른 최신책들보다도 이 책을 먼저 읽어보고 싶었다.</p>
<p>책만 읽고 모든 것을 알아가리란 안일한 생각은 하지 않는다.
그저 이 책을 통해 👀<strong><span style="color:royalblue">나의 시야를 확장</span></strong>👀시켜 더 넓은 시야로 세상을 바라보고 싶다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/5f61c12b-5ded-4a06-98f4-f0afb6f98e62/image.png" alt=""></p>
<p><br><br></p>
<h2 id="메모">메모</h2>
<hr>
<h3 id="-복잡함과-혼란스러움은-다르다"># 복잡함과 혼란스러움은 다르다</h3>
<ul>
<li><strong><span style="color:royalblue">복잡함</span></strong>(complexity)은 실재의 상태, <strong><span style="color:royalblue">혼란스러움</span></strong>(complicated)은 마음의 상태이다.</li>
<li>복잡함의 사전적 의미는 많은 부분이 뒤얽히고 서로 연결된 상태를 말한다.</li>
<li>복잡함은 이 세상의 일부이다. 하지만 그것이 우리를 헷갈리게 해서는 안된다.</li>
<li>우리는 덜 복잡한 것만 쫓기보다, <strong><span style="color:royalblue">복잡함을 다스리는 쪽</span></strong>을 선택해야 한다.</li>
<li>결국 복잡함을 터득하는 핵심은 <strong><span style="color:royalblue">이해</span></strong>다. </li>
</ul>
<br>

<h3 id="-인공적이고-인공적인-모든-것이-곧-기술이다"># 인공적이고 인공적인 모든 것이 곧 기술이다</h3>
<ul>
<li>네트워크 및 기술이 발전할수록 우리는 지속적으로 복잡한 상호작용과 마주하게 될 것이다.</li>
</ul>
<br>

<blockquote>
<h4 id="🤔-span-stylecolorred내-생각-끄적이기span-🤔">🤔 <span style="color:red">내 생각 끄적이기</span> 🤔</h4>
<p>기술이 발전할수록 복잡함이란 것은 뗄레야 뗄 수 없다는 것을 새삼 깨달았다.
초등학생 때 썼던 폴더폰과 지금 사용하고 있는 스마트폰을 비교해봐도 그렇다.
전화, 문자 메세지, 사진 찍기 정도만 가능했던 이전의 폴더폰과 달리, 지금의 스마트폰을 보면 
사진 편집 기능, 인터넷, 다양한 서비스 등 정말 다양한 기능을 사용할 수 있게 됐다. <br />
복잡할 수 밖에 없다. 다양한 기능이 계속해서 추가되고 있기 때문에.
하지만, 혼란스러워져서는 안된다. 혼란스러움은 헷갈리게 하는 복잡함이다.
그럼 복잡한데 헷갈리지 않기 위해선 어떻게 해야할까? 
구조가 있어야 하고, 그 구조에 대한 이해가 뒷받침되어야 한다. <br />
똑같아 보이기만 했던 복잡함과 혼란스러움의 차이를 이해할 수 있게 됐다.</p>
</blockquote>
<br>

<h3 id="-복잡함이-단순함과-다른점"># 복잡함이 단순함과 다른점</h3>
<ul>
<li>좋은 디자인은 사용자가 제품에 호감을 느끼고 사용하면 사용할수록 <strong><span style="color:royalblue">즐거운 감정</span></strong>을 이끌어낸다.</li>
<li>단순함과 복잡함 사이의 차이에는 <strong><span style="color:royalblue">구조</span></strong>가 있다.</li>
</ul>
<br>

<h3 id="-복잡한-것들도-유쾌할-수-있다"># 복잡한 것들도 유쾌할 수 있다</h3>
<ul>
<li>야구규칙의 복잡함은 우리를 괴롭히지만 게임의 <strong><span style="color:royalblue">즐거움을 증가</span></strong>시키기도 한다.</li>
</ul>
<br>

<h3 id="-습득보다는-터득이-중요하다--습득과-터득의-차이"># 습득보다는 터득이 중요하다 : 습득과 터득의 차이</h3>
<ul>
<li>우리는 <strong><span style="color:royalblue">무언가를 배우는 일이 적절한 행동이라고 생각했을 때 복잡함에 대해서는 신경 쓰지 않는다.</span></strong></li>
<li>단지 애매하고 변덕스러운 무언가를 작동하는 방법을 배우느라 시간을 소모하는 게 싫은 것이다.</li>
</ul>
<br>

<blockquote>
<h4 id="🤔-span-stylecolorred내-생각-끄적이기span-🤔-1">🤔 <span style="color:red">내 생각 끄적이기</span> 🤔</h4>
<p>지금까지 나는 디자인은 물론이고 사용자 경험에 있어서도 <strong>단순함 &gt;&gt;&gt;&gt;&gt; 복잡함</strong>이라고만 생각했다.
누구나 복잡한 것보다 단순한 것을 원하지 않을까..라고 생각했다.
하지만 생각해보니 나조차도 복잡함을 추구하는 순간이 있었다.<br />
최근 했던 다도 체험, 향수 만들기 체험 등만 놓고 봐도 그렇다.
그냥 다 만들어진 차를 사서 마셔도 되고, 완벽하게 세팅된 향수를 사서 뿌리면 된다.
근데 굳이 직접 만드는 복잡한 과정을 거치며 즐거움을 느꼈었다.<br />
이 책에서 이야기하는 바도 이것과 같다. 복잡함의 과정 속에서 즐거움을 느낀다는 것이다.
무조건적으로 단순한 것만이 좋다고 말할 수 없겠다.<br />
복잡함. 그 속에서의 구조를 잘 만들어내 사용자들이 혼란스러움을 느끼지 못하도록 하자!</p>
</blockquote>
<p><br><br></p>
<h2 id="출처">출처</h2>
<hr>
<p><a href="https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=141060330">도널드 노먼의 UX 디자인 특강</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NextJS] 기초 다지기]]></title>
            <link>https://velog.io/@hye_rin/NextJS</link>
            <guid>https://velog.io/@hye_rin/NextJS</guid>
            <pubDate>Tue, 31 Jan 2023 13:02:51 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가며">들어가며</h2>
<hr>
<blockquote>
<p>🌱 NextJS의 기초를 다지고자 노마드코더의 <a href="https://nomadcoders.co/nextjs-fundamentals/lobby">NextJS입문 강의</a>를 완강했다. 강의를 따라가며 공부한 내용을 기록해두고자 한다!</p>
</blockquote>
<p><br><br></p>
<h2 id="0-creating-a-project">0. Creating a Project</h2>
<hr>
<p>TypeScript로 프로젝트를 시작하고자 한다면, <code>--typescript</code>를 추가해주면 된다.</p>
<pre><code class="language-powershell">npx create-next-app@latest
npx create-next-app@latest --typescript</code></pre>
<p><br><br></p>
<h2 id="1-library-vs-framework">1. Library vs Framework</h2>
<hr>
<h3 id="1-library">(1) Library</h3>
<blockquote>
<p>👩🏻‍💻 Library는 개발자로서 <span style="color:royalblue"><strong>내가 사용하는 것</strong></span></p>
</blockquote>
<ul>
<li>내가 원하는대로 코드를 작성할 수도 있고, library를 사용하고 싶을 때 사용할 수도 있다.</li>
<li>대표적인 예는 <span style="color:royalblue"><strong>React</strong></span>이다. React는 router를 만들든 component를 만들든 내가 코드를 작성하기 나름이고, 폴더명을 짓는 것에 있어서도 자유롭다. <span style="color:royalblue"><strong>자유도가 높다</strong></span>는 것을 알 수 있다!</li>
</ul>
<br>

<h3 id="2-framework">(2) Framework</h3>
<blockquote>
<p>👩🏻‍💻 Framework는 <span style="color:royalblue"><strong>나의 코드를 불러오는 것</strong></span></p>
</blockquote>
<ul>
<li>코드를 적절한 위치에 잘 적기만 하면 Framework가 내 코드를 불러와서 모든 것을 동작하게 한다.</li>
<li>대표적인 예는 <span style="color:royalblue"><strong>NextJS</strong></span>이다. Router 설정을 따로 하지 않아도 NextJS의 index.js에서 작성한 코드가 홈에 뜨는 것을 쉽게 확인할 수 있다.</li>
</ul>
<p><br><br></p>
<h2 id="2-pages">2. Pages</h2>
<hr>
<blockquote>
<p>💁🏻‍♀️ NextJS에서 페이지를 생성하려면? <span style="color:royalblue"><strong>pages 폴더</strong></span>만 보면 된다!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/412c5e06-8633-473a-9445-c500fa2f5df3/image.png" alt=""></p>
<ul>
<li>NextJS는 pages에 생성된 파일의 이름을 가져다가 URL의 이름으로 사용한다. (따라서 컴포넌트명은 중요하지 않다!)</li>
<li><code>export default 컴포넌트이름</code> 과 같이 default로 export를 꼭 해주어야한다는 것만 잘 지키자!</li>
<li>앱의 홈은 기본적으로 pages 폴더에 위치한 <code>index.js</code>가 나오게 되어 있다.</li>
</ul>
<p><br><br></p>
<h2 id="3-static-pre-rendering">3. Static Pre Rendering</h2>
<hr>
<blockquote>
<p>✨ NextJS의 가장 좋은 기능 중 하나는, <span style="color:royalblue"><strong>앱에 있는 페이지들이 미리 렌더링</strong></span>된다는 것이다.</p>
</blockquote>
<br>

<h3 id="1-react-csr">(1) React (CSR)</h3>
<blockquote>
<p>CSR은 나의 <span style="color:royalblue"><strong>브라우저가</strong></span> UI를 만드는 <span style="color:royalblue"><strong>모든 것을 한다</strong></span>는 것을 의미한다!</p>
</blockquote>
<ul>
<li>브라우저는 프론트 서버로부터 JavaScript를 전달받아 웹페이지 상의 모든 UI를 만들어낸다.</li>
<li><code>create-react-app</code>으로 React 프로젝트를 시작할 때를 생각해보자. <code>index.html</code>파일의 body태그에는 <code>&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;</code>밖에 없는 것을 볼 수 있다. 사실상 비어있는 div태그이며, 브라우저가 프론트 서버로부터 프론트 관련 소스(JavaScript파일 등)를 전달받아 UI가 그려진다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/d1c93d33-4f17-4bb7-95a4-33898094cb26/image.png" alt=""></p>
<br>

<h3 id="2-nextjs-ssr">(2) NextJS (SSR)</h3>
<blockquote>
<p>NextJS는 React.js를 백엔드에서 동작시켜서 <span style="color:royalblue"><strong>페이지를 미리 만든다!</strong></span></p>
</blockquote>
<ul>
<li>NextJS는 초기 컴포넌트가 렌더링 된 HTML 파일을 먼저 받아 화면에 띄운다. </li>
<li>그러면 유저는 JavaScript 와 React.js가 로딩되지 않았더라도 콘텐츠를 먼저 볼 수 있게 된다. </li>
<li>그리고 React.js가 로딩되면, 이미 화면에 그려진 것들과 연결이 되어서 일반적인 React.js 앱이 되는 것이다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/a8ed9a81-c916-4cc4-973e-71ea2f39f389/image.png" alt=""></p>
<p><br><br></p>
<h2 id="4-routing">4. Routing</h2>
<hr>
<blockquote>
<p>✨ NextJS에 앱 내에서 페이지를 네비게이트할 때 사용해야만 하는 
<span style="color:royalblue"><strong>Link 컴포넌트</strong></span>가 존재한다. (따라서 <strong>a태그</strong>를 사용하면 경고표시가 뜬다!)</p>
</blockquote>
<blockquote>
<p>❓ *<em>Link태그 사용하지 않으면? *</em>
브라우저가 다른 페이지로 보내기 위해 전체 페이지를 새로고침하며, 
이는 속도 저하를 야기한다.</p>
</blockquote>
<pre><code class="language-jsx">import Link from &quot;next/link&quot;;

export default function NavBar() {
  return (
    &lt;nav&gt;
      &lt;Link href=&quot;/&quot;&gt;Home&lt;/Link&gt;
      &lt;Link href=&quot;/about&quot;&gt;About&lt;/Link&gt;
    &lt;/nav&gt;
  );
}</code></pre>
<p><br><br></p>
<h2 id="5-css-modules">5. CSS Modules</h2>
<hr>
<h3 id="1-사용법">(1) 사용법</h3>
<ul>
<li>CSS Modules을 사용해 클래스 이름을 추가할 때, 클래스 이름을 텍스트로서 적지 않는다. 자바스크립트 오브젝트에서의 프로퍼티 형식으로 적는다.</li>
</ul>
<pre><code class="language-jsx">import styles from &quot;./NavBar.module.css&quot;;

export default function NavBar() {
      return (
        &lt;nav className={styles.nav}&gt;
          // 생략
        &lt;/nav&gt;
      );
}</code></pre>
<h3 id="2-장점">(2) 장점</h3>
<ul>
<li><span style="color:royalblue"><strong>클래스이름이 자동적으로 생성됨</strong></span>에 따라 충돌이 일어나지 않는다.</li>
<li>이는 다른 컴포넌트에서도 같은 클래스 이름을 사용할 수 있다는 것을 의미한다.</li>
</ul>
<p><br><br></p>
<h2 id="6-styles-jsx">6. Styles JSX</h2>
<hr>
<pre><code class="language-jsx">&lt;style&gt;{`
    nav {
        background-color: tomato;
    }
    a {
        text-decoration: none;
    }
    .active {
        color: ${props.color};
    }
`}&lt;/style&gt;</code></pre>
<p><br><br></p>
<h2 id="7-custom-app">7. Custom App</h2>
<hr>
<h3 id="1-page-초기화의-효과">(1) page 초기화의 효과</h3>
<p>NextJS는 App 컴포넌트를 사용하여 page를 초기화한다. 이는 다음과 같은 효과가 있다.</p>
<blockquote>
<ol>
<li>페이지 변경 간에 레이아웃 유지   </li>
<li>페이지 탐색 시 state 유지   </li>
<li>componentDidCatch를 사용한 Custom 에러 처리   </li>
<li>페이지에 추가 데이터 삽입    </li>
<li>Global CSS 추가</li>
</ol>
</blockquote>
<br>

<h3 id="2-app-재정의하는-법">(2) App 재정의하는 법</h3>
<ul>
<li>기본 App을 재정의하려면 <code>./pages/_app.js</code> 파일을 만든다.</li>
<li>그러면 NextJS는 <code>index.js</code>를 렌더링하기 전에 <code>_app.js</code>을 보고 내용물을 렌더링한다. 그 뒤, <code>index.js</code>의 내용물을 렌더링한다.</li>
</ul>
<pre><code class="language-jsx">export default function MyApp({ Component, pageProps }) {
  return (
    &lt;&gt;
      &lt;NavBar /&gt;
      &lt;Component {...pageProps} /&gt;
      &lt;style jsx global&gt;{`
        a {
          color: white;
        }
      `}&lt;/style&gt;
    &lt;/&gt;
  );
}</code></pre>
<p><br><br></p>
<h2 id="8-patterns">8. Patterns</h2>
<hr>
<ul>
<li>custom app component를 사용할 때 Layout 패턴을 사용한다.</li>
<li>아주 큰 리액트 App 컴포넌트를 사용하기 보다는, Layout component를 만들어 사용해주는 것이다.</li>
<li><span style="color:royalblue">children</span>은 React가 제공하는 <span style="color:royalblue">prop</span>으로, 하나의 component를 또 다른 component 안에 넣을 때 사용할 수 있다.</li>
</ul>
<br>

<h3 id="1-예시">(1) 예시</h3>
<blockquote>
<p>Layout 컴포넌트를 만들어 App 컴포넌트에 적용시켜준다.</p>
</blockquote>
<pre><code class="language-jsx">// Layout 컴포넌트
import NavBar from &quot;./NavBar&quot;;

export default function Layout({ children }) {
  return (
    &lt;&gt;
      &lt;NavBar /&gt;
      &lt;div&gt;{children}&lt;/div&gt;
    &lt;/&gt;
  );
}</code></pre>
<pre><code class="language-jsx">// _app 컴포넌트
import Layout from &quot;components/Layout&quot;;

export default function MyApp({ Component, pageProps }) {
  return (
    &lt;Layout&gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/Layout&gt;
  );
}</code></pre>
<br>

<h3 id="2-예시">(2) 예시</h3>
<blockquote>
<p>NextJS에서 제공하는 <code>Head</code> 컴포넌트를 사용해
페이지를 이동할 때마다 해당 title이 나타나게 만들어준다.
다음 이미지는 About 페이지로 이동했을 때의 모습이다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/7646bb11-78aa-4553-8ebe-30e63920d0b9/image.png" alt=""></p>
<pre><code class="language-jsx">// Seo.js
import Head from &quot;next/head&quot;;

export default function Seo({ title }) {
  return (
    &lt;Head&gt;
      &lt;title&gt;{title} | Next Movies&lt;/title&gt;
    &lt;/Head&gt;
  );
}</code></pre>
<pre><code class="language-jsx">// About.js
import Seo from &quot;components/Seo&quot;;

export default function about() {
  return (
    &lt;div&gt;
      &lt;Seo title=&quot;Home&quot; /&gt;
      &lt;h1&gt;About&lt;/h1&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p><br><br></p>
<h2 id="9-redirect-and-rewrite">9. Redirect and Rewrite</h2>
<hr>
<h3 id="1-redirect">(1) Redirect</h3>
<blockquote>
<ul>
<li>redirect를 이용해서 <span style="color:royalblue"><strong>한 페이지에서 다른 페이지로 이동</strong></span>하게 할 수도 있고, <span style="color:royalblue"><strong>아예 다른 URL의 웹사이트로 이동</strong></span>하게 할 수도 있다.</li>
</ul>
</blockquote>
<ul>
<li><code>/old-blog/포스트숫자</code>를 url에 입력하면, <code>/new-sexy-blog/포스트숫자</code>로 이동하는 것을 확인할 수 있다.</li>
<li><code>:path*</code> 와 같이 뒤에 별표를 붙여주면 <code>/old-blog/1212/comments/122</code> 와 같이 뒤에 오는 모든 경로를 다 잡아낸다.</li>
</ul>
<pre><code class="language-jsx">module.exports = {
  reactStrictMode: true,
  async redirects() {
    return [
      {
        source: &quot;/old-blog/:path*&quot;,
        destination: &quot;/new-sexy-blog/:path*&quot;,
        permanent: false,
      },
    ];
  },
};</code></pre>
<br>

<h3 id="2-rewrite">(2) Rewrite</h3>
<blockquote>
<ul>
<li>redirects는 old-blog로 접속할 때, 유저가 url이 바뀌는 것을 볼 수 있다. (new-sexy-blog로!)</li>
</ul>
</blockquote>
<ul>
<li>rewrites는 유저를 redirect시키기는 하지만, url은 변하지 않는다!</li>
<li>설정한 source를 통해 destination에 접근할 수 있다! (ex)<code>fetch(&quot;/api/movies&quot;)</code></li>
</ul>
<pre><code class="language-jsx">const API_KEY = &quot;0123456789&quot;;

module.exports = {
  reactStrictMode: true,
  async redirects() {}, // 생략
  async rewrites() {
    return [
      {
        source: &quot;/api/movies&quot;,
        destination: `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`,
      },
    ];
  },
};</code></pre>
<br>

<h3 id="3-api-key-숨기기">(3) API key 숨기기</h3>
<blockquote>
<ul>
<li>.env 파일 생성하고 가져다가 쓰면 된다.</li>
</ul>
</blockquote>
<ul>
<li>gitignore 됐는지 확인할 것!</li>
</ul>
<pre><code class="language-jsx">// .env 파일
API_KEY=0123456789</code></pre>
<pre><code class="language-jsx">// next.config.js
const API_KEY = process.env.API_KEY;</code></pre>
<p><br><br></p>
<h2 id="10-server-side-rendering">10. Server Side Rendering</h2>
<hr>
<h3 id="1-getserversideprops-함수">(1) getServerSideProps 함수</h3>
<blockquote>
<p>💥 <strong>서버에서만 실행되는 함수임</strong></p>
</blockquote>
<ul>
<li>getServerSideProps 함수는 오직 백엔드(서버)에서만 실행된다.</li>
<li>따라서, getServerSideProps 함수에 API key를 써주면 client한테 보여지지 않는다. </li>
</ul>
<blockquote>
<p>🎁 <strong>props란 key를 갖는 객체를 return함</strong></p>
</blockquote>
<ul>
<li>getServerSideProps는 props라는 key를 갖는 object를 return한다.</li>
<li>props라는 key에는 원하는 데이터를 넣을 수 있다. </li>
<li>이로써 원하는 데이터를 props로 page에게 전달 할 수 있다.</li>
</ul>
<pre><code class="language-jsx">// index.js
export default function Home({ results }) {
  // 생략
}
export async function getServerSideProps() {
  const { results } = awiat(await fetch(&quot;/api/movies&quot;)).json();
  return {
    props: {
      results,
    },
  };
}</code></pre>
<br>

<h3 id="2-ssr-vs-csr">(2) SSR vs. CSR</h3>
<blockquote>
<ul>
<li>Server Side Rendering으로 렌더링되는 상태에선 API가 호출되기 전까지 
아무것도 화면에 보이지 않을 것이다. </li>
</ul>
</blockquote>
<ul>
<li><span style="color:royalblue"><strong>데이터가 유효할 때 화면을 보여주는 것(SSR)</strong></span>이 좋은 지, 
<span style="color:royalblue"><strong>loading 화면을 보여준 뒤 데이터를 받는 것(CSR)</strong></span>이 좋은지는 나의 선택이다.</li>
</ul>
<blockquote>
<ul>
<li><strong>SSR 방식</strong>은 해당 페이지의 데이터가 들어오기 전까진 아무것도 볼 수 없다가 해당 페이지의 데이터만 들어오면 전체를 다 볼 수 있다. (다른 페이지를 갈 때도 이 과정이 필요하다.)</li>
</ul>
</blockquote>
<ul>
<li><strong>CSR 방식</strong>은 모든 JS파일들이 들어와야 (’Loading…’) 보여지는데, 그 대신 다른 페이지를 갈 때는 이미 JS 파일들을 받았으니 SSR 방식보다는 빠르게 화면을 볼 수 있다.</li>
</ul>
<p><br><br></p>
<h2 id="11-dynamic-routes">11. Dynamic Routes</h2>
<hr>
<blockquote>
<p>❓ <strong>URL에 변수를 넣는 방법</strong></p>
</blockquote>
<ul>
<li>pages폴더에 movies 폴더 생성해준 뒤 <code>[id].js</code>파일 생성</li>
<li>이름 짓는 것은 자유다. 대괄호만 잘 작성해주기!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/6ebd5e49-03c1-40ef-8e15-76eacb35af86/image.png" alt=""></p>
<p><br><br></p>
<h2 id="12-detail">12. Detail</h2>
<hr>
<h3 id="1-link로-navigating">(1) Link로 navigating</h3>
<pre><code class="language-jsx">&lt;Link href={`/movies/${movie.id}`}&gt;{movie.original_title}&lt;/Link&gt;</code></pre>
<br>

<h3 id="2-이벤트-발생-시-navigating">(2) 이벤트 발생 시 navigating</h3>
<pre><code class="language-jsx">// index.js
export default function Home({ results }) {
    const router = useRouter();
    const onClick = (id) =&gt; {
        router.push(`/movies/${id}`);
    };

    return (
    {results?.map((movie) =&gt; (
       &lt;div onClick={() =&gt; onClick(movie.id)} className=&quot;movie&quot; key={movie.id}&gt;
           {/* 생략 */}
       &lt;/div&gt;
    ))
    )
}</code></pre>
<br>

<h3 id="3-url에서-url로-state-넘기기">(3) URL에서 URL로 state 넘기기</h3>
<blockquote>
<ul>
<li>아래와 같이 router를 설정하면, 영화 상세보기 시에 url이 다음과 같이 나오는 것을 볼 수 있다.
<code>http://localhost:3000/movies/315162?id=315162&amp;title=potatos</code></li>
</ul>
</blockquote>
<ul>
<li>router의 2번째 속성인 <code>as</code>는 브라우저의 URL을 마스킹한다. <code>,</code> 뒤에 브라우저에 보일 URL을 작성하면 된다.</li>
<li><code>router.query.title</code>은 유저가 홈→상세로 넘어올 때만 존재한다.</li>
</ul>
<pre><code class="language-jsx">// index.js Home컴포넌트
const onClick = (id, title) =&gt; {
  router.push(
    {
      pathname: `/movies/${id}`,
      query: {
          title: title,
      },
    },
    `/movies/${id}`
  );
};

// [id].js
export default function Detail() {
      const router = useRouter();
      console.log(router);
      return (
        &lt;div&gt;
          &lt;h4&gt;{router.query.title || &quot;Loading...&quot;}&lt;/h4&gt;
        &lt;/div&gt;
      );
}</code></pre>
<p><br><br></p>
<h2 id="13-catch-all">13. Catch All</h2>
<hr>
<blockquote>
<ul>
<li><code>catch-all URL</code>은 뭐든 캐치해내는 URL이다.</li>
</ul>
</blockquote>
<ul>
<li><code>router.query.params || []</code>와 같은 처리를 해주는 이유<ul>
<li>홈페이지를 거쳐서 가는것이 아니라 바로 상세페이지로 가면, 
서버는 영화에 대한 정보를 모르기 때문에 error 발생</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">// index.js
export default function Home({ results }) {
  const router = useRouter();
  const onClick = (id, title) =&gt; {
    router.push(`/movies/${title}/${id}`);
  };
  return (
        &lt;Link href={`/moives/${movie.original_title}/${movie.id}`}&gt;
       {movie.original_title}
    &lt;/Link&gt;
    )
}</code></pre>
<pre><code class="language-jsx">// [...params].js
export default function Detail() {
  const router = useRouter();
  const [title, id] = router.query.params || [];

  return (
    &lt;div&gt;
      &lt;h4&gt;{title}&lt;/h4&gt;
    &lt;/div&gt;
  );
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Clean Code] 깨끗한 코드]]></title>
            <link>https://velog.io/@hye_rin/Clean-Code-1-%EA%B9%A8%EB%81%97%ED%95%9C-%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@hye_rin/Clean-Code-1-%EA%B9%A8%EB%81%97%ED%95%9C-%EC%BD%94%EB%93%9C</guid>
            <pubDate>Sun, 08 Jan 2023 16:54:02 GMT</pubDate>
            <description><![CDATA[<h3 id="🌱-코드가-존재하리라">🌱 코드가 존재하리라</h3>
<blockquote>
<p>기계가 실행할 정도로 상세하게 요구사항을 명시하는 작업이 프로그래밍이고, 
이렇게 명시한 결과가 바로 코드이다.</p>
</blockquote>
<p>따라서 코드가 사라질 가망은 전혀 없다!
궁극적으로 코드는 요구사항을 표현하는 언어이기 때문이다. 
어느 수준에 이르면 코드의 도움 없이 요구사항을 상세하게 표현하는 것은 불가능하다.</p>
<br>

<h3 id="🙅🏻♀️-나쁜-코드">🙅🏻‍♀️ 나쁜 코드</h3>
<p>가지각색의 이유로 누구나 대충 프로그램을 짠 경험이 있다.
대충 짰어도 프로그램이 돌아간다는 사실에 안도감을 느끼곤 하는데.
다시 돌아와 나중에 정리하겠다고 다짐하곤 한다.
하지만 <strong>나중은 결코 오지 않는다.</strong></p>
<br>

<h3 id="⏳-나쁜-코드로-치르는-대가">⏳ 나쁜 코드로 치르는 대가</h3>
<blockquote>
<p>나쁜 코드는 결국 나쁜 코드를 더 많이 양산한다.
이에 따라 개발 속도를 크게 떨어뜨려 생산성은 점점 0에 수렴한다.</p>
</blockquote>
<h4 id="태도">태도</h4>
<p>좋은 코드를 사수하는 일은 바로 우리 프로그래머들의 책임이다.
나쁜 코드의 위험을 이해하지 못하는 관리자 말을 그대로 따르는 행동은 전문가답지 못하다.</p>
<h4 id="기한-vs-좋은-코드">기한 vs. 좋은 코드</h4>
<p>기한을 맞추기 위해, 빨리 가기 위해 시간을 들이지 않는다.
하지만 기한을 맞추는 유일한 방법은 코드를 최대한 깨끗하게 유지하는 습관이다.</p>
<br>

<h3 id="🧼-깨끗한-코드란">🧼 깨끗한 코드란?</h3>
<blockquote>
<ul>
<li>&#39;보기에 즐거운&#39; 코드</li>
</ul>
</blockquote>
<ul>
<li>세세한 사항까지 꼼꼼하게 처리하는 코드<ul>
<li>오류 처리, 메모리 누수, 경쟁 상태, 일관성 없는 명명법 등</li>
</ul>
</li>
<li>한 가지에 &#39;집중&#39;하는 코드<ul>
<li>함수, 클래스, 모듈의 의도가 뒤섞이거나 목적이 흐려지지 않도록</li>
</ul>
</li>
<li>사실에 기반하여 반드시 필요한 내용만 담은 코드</li>
<li>다른 사람이 고치기 쉬운 코드</li>
<li>&#39;주의 깊게&#39; 작성한 코드<ul>
<li>누군가 시간을 들여 깔끔하고 단정하게 정리한 코드</li>
</ul>
</li>
<li>한 가지 기능만을 수행하고, 중복을 줄이고, 제대로 표현하고, 작게 추상화한 코드</li>
</ul>
<br>

<h3 id="🧺-보이스카우트-규칙">🧺 보이스카우트 규칙</h3>
<blockquote>
<p>캠프장은 처음 왔을 때보다 더 깨끗하게 해놓고 떠나라</p>
</blockquote>
<ul>
<li>코드는 시간이 지나도 언제나 깨끗하게 유지해야 한다.</li>
<li>지속적인 개선이야말로 전문가 정신의 본질이다!</li>
</ul>
<br>

<h3 id="👩🏻💻-결론">👩🏻‍💻 결론</h3>
<blockquote>
<p>예술에 대한 책을 읽는다고 예술가가 되라는 보장이 없듯이
이 책을 읽는다고 뛰어난 프로그래머가 된다는 보장은 없다.</p>
</blockquote>
<p>뛰어난 프로그래머가 생각하는 방식과 그들이 사용하는 기술과 기교와 도구에 대한 소개만 있을뿐
나머지는 나에게 달렸다! 연습하자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] useState의 비동기 처리]]></title>
            <link>https://velog.io/@hye_rin/React-useState%EC%9D%98-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@hye_rin/React-useState%EC%9D%98-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Sun, 08 Jan 2023 16:12:27 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>✍🏻 비동기적으로 동작하는 <code>useState</code>를 알기 위해선
<code>useState</code>에 해당되는 Hook이 무엇인지 알아야 했다.
Hook이 무엇인지를 알고자 하니 Side Effect를 이해해야 했다.<br />
🌊 따라서 Side Effet부터 Hook, <code>useState</code>까지의 흐름을 그대로 타고 내려가며 
최종적으로 비동기적으로 작동하는 <code>useState</code>까지 정리해보고자 한다!</p>
</blockquote>
<p><br><br></p>
<h2 id="side-effect">Side Effect</h2>
<hr>
<blockquote>
<p>❓ React 컴포넌트가 화면에 처음으로 렌더링된 이후에,
<span style="color:royalblue"><strong>비동기적으로 처리</strong></span>되어야 하는 부수적인 효과들을 <span style="color:royalblue"><strong>Side Effect</strong></span>라고 부른다.</p>
</blockquote>
<p>비동기적으로 처리되어야 하는 부수적인 효과..?
완전히 와닿지 않을 수 있으니 예시를 들어보자!</p>
<p>React 컴포넌트에서 외부 API를 호출할 때, 
화면에 그려주는 것들을 먼저 렌더링해준 뒤, 📫<strong><em>실제 데이터</em></strong>📫는 비동기로 가져오는 것이 권장된다.
API 응답이 늦어지거나/없을 때의 영향을 최소화하기 위해 
🎨_<strong>화면에 그려주는 작업</strong>_🎨을 먼저 하는 것이다.</p>
<p>이 때의 <span style="color:royalblue"><strong>Side Effect</strong></span>는 📫<strong><em>실제 데이터</em></strong>📫를 받아오는 작업이 될 수 있겠다.
(첫 렌더링 후, 비동기적으로 처리되어야하는 작업이니까!)</p>
<p><span style="color:royalblue"><strong>Hook</strong></span>은 이런 Side Effect를 수행하는 역할을 한다.</p>
<p><br><br></p>
<h2 id="hook">Hook</h2>
<hr>
<h3 id="❓-hook이란">❓ Hook이란?</h3>
<p>Hook은 React <code>v16.8</code>부터 새로 추가되었다.
(22년 3월에 React <code>v18</code>이 출시된 상태)</p>
<p>함수형 컴포넌트에서 사용되는 기술을 Hook이라고 생각하면 되는데.</p>
<p>함수형 컴포넌트에서 <span style="color:royalblue"><strong>상태관리</strong></span>를 할 수 있게 하는 <code>useState</code>,
<span style="color:royalblue"><strong>렌더링 직후의 작업</strong></span>을 설정하는 <code>useEffect</code>가 Hook에 속한다.</p>
<br>

<h3 id="🤷🏻♂️-클래스형에서-함수형으로-굳이">🤷🏻‍♂️ 클래스형에서 함수형으로 굳이?</h3>
<p>함수형 컴포넌트에서 사용되는 기술이 Hook이라고 했다.
그럼 클래스형으로 잘만 써왔는데 <span style="color:red"><strong>왜 굳이</strong> </span>함수형으로 바꿔 Hook을 사용해야 하는걸까란 의문이 생긴다.</p>
<p>우선 클래스는 <span style="color:royalblue"><strong>진입장벽이 높다</strong></span>.
this 등 기본적인 JavaScript 문법을 알아야 하며, 코드의 재사용성과 코드 구성을 어렵게 한다. 
그리고, React 최신 기술의 적용이 효과적이지 않다.</p>
<p>이런 클래스의 단점을 🚀<span style="color:royalblue"><strong>함수형 컴포넌트로 극복</strong></span>🚀할 수 있다.
하지만, 클래스형 컴포넌트의 장점이었던 _<strong>state 사용</strong>_이나 
_<strong>Life Cycle</strong>_을 직접 다루는 기능을 사용하지 못한다는 단점이 있었다.
이를 해결하기 위해 등장한 것이 바로 <span style="color:royalblue"><strong>Hook</strong></span>이다.
<img src="https://velog.velcdn.com/images/hye_rin/post/827a4f11-5145-490e-a0a7-4754d46d815a/image.png" alt=""></p>
<p><br><br></p>
<h2 id="usestate">useState</h2>
<hr>
<p><code>setState()</code>호출 후 <code>state</code>가 바로 업데이트되지 않는 이슈를 겪은 적이 있을 것이다.
React를 배운 지 얼마되지 않았을 때 나도 굉장히 당황스러웠던 부분이었다.</p>
<p>이건 <span style="color:royalblue"><strong>useState()가 비동기적으로 동작</strong></span>했기 때문이었다!
근데.. 그래서 비동기적인게 뭔데..?</p>
<blockquote>
<p>✅ <strong>useState과 setState 제대로 구분하고 있는지 CHECK!</strong>
    <code>useState</code> : state의 초기값 설정 &amp; return 값으로 state, setState를 돌려주는 <strong>hook</strong>
    <code>setState</code> : state의 값을 변경할 때 사용하는 함수</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/7f61c045-8309-4f6d-a80a-b1fbca3ec5bd/image.png" alt=""></p>
<br>

<h3 id="😤-동기-비동기가-뭔데">😤 동기, 비동기가 뭔데!</h3>
<blockquote>
<p>헷갈리면 <strong><code>동기적으로 === 순차적으로</code></strong>라고 기억하면 편하다👍🏻</p>
</blockquote>
<h4 id="1-동기">1. 동기</h4>
<p>사장님 혼자만 있는 👦🏻<strong>개인카페</strong>👦🏻라고 생각하면 쉽다.
직원이 없으니 주문과 음료 제조를 동시에 처리하기 불가능할 것이다.
이렇게 동시에 작업을 처리하지 않고 <span style="color:royalblue"><strong>순차적으로 처리</strong></span>하는 것이 동기적으로 처리하는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/c75136b4-22ad-47da-a7a0-a66f50dad87b/image.png" alt=""></p>
<br>

<h4 id="2-비동기">2. 비동기</h4>
<p>동기 처리와 다르게 직원이 많은 👨‍👨‍👧‍👦<strong>프렌차이즈 카페</strong>👨‍👨‍👧‍👦를 생각하면 된다.
주문 받는 것과 음료 제조를 동시에 처리할 수 있을 것이다.
이렇듯 한 가지 일을 처리하는 동안 <span style="color:royalblue"><strong>다른 작업이 기다리지 않고 동시에 수행하는 것</strong></span>을 비동기적으로 처리한다고 한다.</p>
<br>

<h3 id="📝-비동기-동작-예시">📝 비동기 동작 예시</h3>
<p>아래의 코드를 보면
증가 버튼을 누를 때마다  count가 1씩 증가할 것이다.</p>
<p>하지만, console에 찍히는 값을 보면 증가시키기 이전의 상태 값을 출력하는 것을 볼 수 있다.</p>
<pre><code class="language-javascript">function AsyncSetState() {
  const [count, setCount] = useState(0);

  const handleClick = () =&gt; {
    setCount(count + 1);
    console.log(count);
  };

  return (
    &lt;&gt;
     &lt;div&gt;현재 값 {count}&lt;/div&gt;
     &lt;button onClick={handleClick}&gt;count+&lt;/button&gt;
    &lt;/&gt;
  );
}</code></pre>
<br>

<h3 id="💥-비동기적으로-동작하는-이유">💥 비동기적으로 동작하는 이유</h3>
<h4 id="1-state가-리렌더링-발생시킴">1. state가 리렌더링 발생시킴</h4>
<p><code>useState</code>가 비동기적으로 동작하는 이유는 <span style="color:royalblue"><strong>state</strong></span>와 연관이 깊다.
state는 <span style="color:royalblue"><strong>값이 변경</strong></span>되면 <span style="color:royalblue"><strong>리렌더링</strong></span>이 발생한다는 특징이 있다.</p>
<p>근데... 만약 값이 변경되는 <span style="color:red"><strong>state가 100개</strong></span> 있다면? 
React는 매번 렌더링만 하다가 생을 마감할 것이다. </p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/4a1106d1-1f76-4ff9-915f-14a59124801e/image.png" alt=""></p>
<br>

<h4 id="2-해결방법">2. 해결방법</h4>
<p>따라서 React는 렌더링을 줄이고자 
<span style="color:royalblue"><strong>상태값이 변한 state를 모두 취합</strong></span>(배치, Batch)한 후에 한 번에 렌더링이 되도록 한다.</p>
<blockquote>
<p>🎀 <strong>배치(Batch)?</strong></p>
</blockquote>
<ul>
<li>React가 너 나은 성능을 위해 여러개의 state 업데이트를 하나의 리렌더링으로 묶는 것</li>
<li><code>16ms</code>마다 변경된 상태값을 모아서(merge) 이전의 Element Tree와 변경된 state가 적용된 Element Tree를 비교하는 작업(reconciliation)을 거쳐 최종적으로 변경된 부분만 DOM에 적용시킨다.</li>
<li>state도 결국 객체다. 상태값이 모아지는 merge 단계에서 같은 키 값을 가진 state들이 있다면 <span style="color:royalblue"><strong>가장 마지막 실행값</strong></span>으로 덮어씌워진다.</li>
</ul>
<br>

<h4 id="3-효과">3. 효과</h4>
<p>앞서 이야기 한 배치(Batch)와 같은 과정을 통해
100번의 상태값 변화를 단 1번의 렌더링으로 최신의 상태로 업데이트할 수 있게 된 것이다.</p>
<p><br><br></p>
<h3 id="✨-동기적으로-처리할-수-있는-방법">✨ 동기적으로 처리할 수 있는 방법</h3>
<blockquote>
<p>이처럼 비동기적으로 동작하는 setState를 동기적으로 처리할 수 있는 방법에는
아래와 같이 2가지의 방법이 있다.</p>
</blockquote>
<p><span style="color:royalblue"><strong>1. useEffect의 의존성 배열 이용</strong></span></p>
<p><span style="color:royalblue"><strong>2. 함수형 업데이트</strong></span></p>
<pre><code class="language-javascript">// 이전
setCount(count + 1);

// 이후
setCount((prevCount) =&gt; prevCount + 1);</code></pre>
<p><br><br></p>
<h2 id="결론">결론</h2>
<hr>
<blockquote>
<p>💁🏻‍♀️ <code>useState</code>가 비동기적으로 동작하는 이유는,
<span style="color:royalblue"><strong>렌더링 횟수를 줄여서 더 빠르게 동작</strong></span>하게 하기 위해서다.</p>
</blockquote>
<br>

<h2 id="참고">참고</h2>
<hr>
<p>이 글은 아래의 글을 바탕으로 공부하며 개인적으로 정리한 글입니다.</p>
<ul>
<li><a href="https://devbirdfeet.tistory.com/52">React(23) 리액트 훅이란?</a></li>
<li><a href="https://velog.io/@zuzokim/React-setState%EA%B0%80-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%9D%B8-%EC%9D%B4%EC%9C%A0">React - setState가 비동기인 이유</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Web] 어쩌다 마주친 CORS에러]]></title>
            <link>https://velog.io/@hye_rin/Web-%EC%96%B4%EC%A9%8C%EB%8B%A4-%EB%A7%88%EC%A3%BC%EC%B9%9C-CORS%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@hye_rin/Web-%EC%96%B4%EC%A9%8C%EB%8B%A4-%EB%A7%88%EC%A3%BC%EC%B9%9C-CORS%EC%97%90%EB%9F%AC</guid>
            <pubDate>Sun, 25 Dec 2022 14:37:28 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가며">들어가며</h2>
<hr>
<p>기업협업 프로젝트를 하며 💥<span style="color:red"><strong>CORS에러</strong></span>💥를 마주쳤던 경험이 있었다.
프론트엔드 개발자라면 꼭 마주치게 되는 에러 중 하나라는 것을 알게되었는데..
그래서 꼭 제대로 정리해두고 기억해두고 싶은 내용이라 기록을 남긴다.<br />
CORS에러가 무엇인지에서부터 
나는 어쩌다 마주친 CORS에러를 어떻게 해결할 수 있었는 지까지 정리해봅시당♪(´▽｀)</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/0d0e8516-a2f2-4237-9f90-499340ba8062/image.png" alt=""></p>
<p><br><br></p>
<h2 id="cors가-뭐지">CORS가 뭐지?</h2>
<hr>
<p>CORS는 <code>Cross-Origin Resourse Sharing</code>(교차 출처 리소스 공유)의 줄임말이다. 
따라서 CORS에 대해 이해하기 위해선 <code>Cross-Origin</code>(교차 출처)이 
무엇을 뜻하는 지에 대해 먼저 짚고 넘어가는 것이 좋겠다.</p>
<br>

<h3 id="span-stylebackgroundcolorlightyellow❔-originspan"><span style="backgroundColor:lightyellow;">❔ Origin</span></h3>
<p><code>Cross-Origin Resourse Sharing</code>에서 <code>Origin</code>(출처)은 
URL에서 <span style="color:royalblue"><strong>프로토콜</strong></span>, <span style="color:royalblue"><strong>도메인</strong></span>, <span style="color:royalblue"><strong>포트</strong></span>를 모두 합친 것을 의미한다. 
아래와 같은 URL에서 프로토콜, 도메인, 포트는 어느 부분일까?</p>
<blockquote>
<p>URL | <code>https://hyerin.com:3000/posts/0426?data=898</code> </p>
</blockquote>
<ul>
<li><span style="color:royalblue"><strong>프로토콜</strong></span> : <code>https://</code></li>
<li><span style="color:royalblue"><strong>도메인</strong></span> : <code>hyerin.com</code></li>
<li><span style="color:royalblue"><strong>포트</strong></span> : <code>:3000</code></li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/0116698d-4845-479b-85b3-b708a44df94c/image.png" alt=""></p>
<p><br><br></p>
<h3 id="span-stylebackgroundcolorlightyellow❓-cross-originspan"><span style="backgroundColor:lightyellow">❓ Cross-Origin</span></h3>
<p><code>Origin</code>이 무엇인지에 대해는 이제 알았다. 그럼 <code>Cross-Origin</code>은 무슨 의미일까? 
<code>Cross-Origin</code>이란 아래 중 한 가지라도 다른 경우를 말한다.</p>
<blockquote>
<ul>
<li><span style="color:royalblue"><strong>프로토콜</strong></span> : http와 https같이 다른 프로토콜</li>
</ul>
</blockquote>
<ul>
<li><span style="color:royalblue"><strong>도메인</strong></span> : domain.com와 other-domain.com 같이 다른 도메인</li>
<li><span style="color:royalblue"><strong>포트</strong></span> : 8002포트와 3000포트 같이 다른 포트</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/1d721dff-2553-4ff7-93a5-cb9d089054b1/image.png" alt=""></p>
<br />

<h3 id="span-stylebackgroundcolorlightyellow🤷🏻♀️-그래서-cors가-뭔데span"><span style="backgroundColor:lightyellow">🤷🏻‍♀️ 그래서 CORS가 뭔데?</span></h3>
<p>브라우저에서는 <span style="color:royalblue"><strong>보안상의 이유로</strong></span> <code>cross-origin</code> HTTP 요청(GET, POST등)을 <span style="color:royalblue"><strong>제한</strong></span>한다. 
그래서 <code>cross-origin</code> 요청을 하기 위해선 ⭕<strong><em>서버의 동의</em></strong>⭕가 필요하다. </p>
<p>만약 서버가 동의한다면 브라우저에서는 요청을  <span style="color:yellowgreen">허락</span>하고, 
동의하지 않는다면 브라우저에서 <span style="color:red">거절</span>한다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/7bcf4d0c-4db5-4b62-8205-f4f3a94fbe13/image.png" alt=""></p>
<blockquote>
<p>이렇게 허락을 구하고 거절하는 과정은 <span style="color:royalblue"><strong>HTTP-header</strong></span>를 통해 가능한데,
특별한 헤더인 <code>Access-Control-Allow-Origin</code>를 응답에 추가하면 된다.</p>
</blockquote>
<p>이러한 <strong>정책</strong>을 CORS(Cross-Origin Resourse Sharing, 크로스 오리진 리소스 공유)라고 한다.</p>
<p><br><br></p>
<h3 id="span-stylebackgroundcolorlightyellow🔎-cors가-탄생한-이유span"><span style="backgroundColor:lightyellow">🔎 CORS가 탄생한 이유</span></h3>
<blockquote>
<p>결론부터 말하자면 CORS는 악의를 가진 해커로부터 <span style="color:royalblue"><strong>인터넷을 보호</strong></span>하기 위해 만들어졌다. </p>
</blockquote>
<p>CORS는 악의를 가진 해커로부터 <span style="color:royalblue"><strong>인터넷을 보호</strong></span>하기 위해 만들어졌다. </p>
<p>CORS라는 정책 없이 누구나 데이터를 요청할 수 있다고 가정해보자. 
그렇다면 😈<span style="color:red">원래 있던 기존의 사이트와 똑같은 사이트를 만들어, 
사용자의 로그인을 유도해 정보를 추출해가는 것</span>😈은 식은 죽 먹기일 것이다!</p>
<p>따라서, CORS는 필요한 경우에만 서버에 요청이 가능하게 하여 
인터넷을 보호하기 위해 필요하다.</p>
<p><br><br></p>
<h2 id="cors-동작원리">CORS 동작원리</h2>
<hr>
<h3 id="span-stylebackgroundcolorlightyellow1--preflight-requestspan"><span style="backgroundColor:lightyellow">1.  Preflight Request</span></h3>
<p><code>Preflight</code> 요청은 웹 개발 시 가장 자주 마주치게 되는 시나리오다.
브라우저는 본 요청을 보내기 전, 이 요청이 <strong><em>안전한 것인지 확인</em></strong>하기 위해 
<span style="color:royalblue"><strong>예비 요청</strong></span>과 <span style="color:royalblue"><strong>본 요청</strong></span>으로 나누어 서버에 전송한다.</p>
<blockquote>
<p> 🤷🏻‍♀️ <strong>Preflight란?</strong>
브라우저가 본 요청을 보내기 전에 보내는 예비 요청을 <code>Preflight</code>라고 부른다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/bbe7ef5b-c72c-45e0-82e2-850d711dfff4/image.png" alt=""></p>
<blockquote>
<p> 🚚 <strong>동작과정</strong></p>
</blockquote>
<ol>
<li><code>fetch API</code>등을 통해 브라우저에게 데이터를 받아오라 명령함</li>
<li>브라우저는 서버에게 <span style="color:royalblue"><strong>예비 요청</strong></span>(Preflight)을 먼저 보냄</li>
<li>서버는 이에 대한 응답으로 <span style="color:royalblue"><strong>자신이 어떤 것들을 허용하고 금지하는지에 대한 정보</strong></span>를 응답 헤더에 담아 브라우저에게 다시 보냄</li>
<li>브라우저는 자신이 보낸 예비 요청(Preflight)과 서버가 응답에 담아준 허용 정책을 <span style="color:royalblue"><strong>비교</strong></span>함</li>
<li>안전하다고 판단되면 다시 <span style="color:royalblue"><strong>본 요청</strong></span>을 보냄</li>
<li>서버가 본 요청에 대한 응답을 하면 최종적으로 응답 데이터를 JavaScript에 넘겨줌</li>
</ol>
<br>

<h3 id="span-stylebackgroundcolorlightyellow2--simple-requestspan"><span style="backgroundColor:lightyellow">2.  Simple Request</span></h3>
<p>대부분의 경우 preflight 방식을 사용하지만,
특정 조건들이 전부 만족된 경우 <span style="color:royalblue"><strong>예비 요청 없이 본 요청만으로</strong></span> 
CORS 정책 위반 여부를 검사할 수도 있다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/5c7e8c1a-04ce-4383-b5b6-77be97cea8d4/image.png" alt=""></p>
<blockquote>
<p> 🚚 <strong>동작과정</strong></p>
</blockquote>
<ol>
<li><code>fetch API</code>등을 통해 브라우저에게 데이터를 받아오라 명령함</li>
<li>브라우저는 서버에게 <span style="color:royalblue"><strong>바로 본 요청</strong></span>을 보냄</li>
<li>서버는 이에 대한 응답으로 <code>Access-Control-Allow-Origin</code>과 같은 값을 보내줌</li>
<li>브라우저가 CORS 정책 위반 여부를 검사함
<span style="color:gray"><em>(Preflight와 전반적인 과정은 동일하고, 예비 요청의 존재 유무만 다르다!)</em></span></li>
</ol>
<p>그러면 만족해야하는 조건들에는 어떤 것들이 있을까?
아래의 조건을 모두 만족해야만 예비 요청의 과정이 생략될 수 있다.</p>
<blockquote>
<p>🤢 <strong>만족해야하는 조건들</strong></p>
</blockquote>
<ol>
<li><span style="color:royalblue"><strong>요청 메소드</strong></span>가 <code>GET</code>, <code>POST</code>, <code>HEAD</code> 중 하나여야 함.</li>
<li><code>Accept</code>, <code>Accept-Language</code>, <code>Content-Language</code>, <code>Content-Type</code>, <code>DPR</code>, <code>Downlink</code>, <code>Save-Data</code>, <code>Viewport-Width</code>, <code>Width</code>를 제외한  <span style="color:royalblue"><strong>헤더</strong></span>를 사용하면 안됨</li>
<li>만약 <code>Content-Type</code>를 사용하는 경우에는 <code>application/x-www-form-urlencoded</code>, <code>multipart/form-data</code>, <code>text/plain</code>만 허용됨.</li>
</ol>
<p>그런데 아래의 조건들 중에서도 2번과 3번이 까다로워 만족시키기 어렵다고 한다.
왜냐하면 사용자 인증에 사용되는 <code>Authorization</code>나
<code>application/json</code>과 같은 콘텐츠 타입도 사용하면 안되기 때문..</p>
<p>따라서  <span style="color:royalblue"><strong>이러한 조건을 모두 만족시키기 어렵</strong></span>기 때문에
본 요청을 바로 보내는 <code>Simple Request</code>보다
예비 요청을 먼저 보내는 <code>Preflight Request</code>를 더 자주 접할 수 있는 것이다.</p>
<p><br><br></p>
<h2 id="cors-해결방법">CORS 해결방법</h2>
<hr>
<h3 id="span-stylebackgroundcolorlightyellow1--chrome-확장-프로그램span"><span style="backgroundColor:lightyellow">1.  Chrome 확장 프로그램</span></h3>
<p>처음에 CORS에러를 마주쳤을 때 임시방편으로나마 사용했던 방법이다..
바로 Chrome에서 제공하는 확장 프로그램 <code>Allow CORS</code>를 설치하는 것!</p>
<p><span style="color:royalblue"><strong>로컬 환경에서</strong></span>는 CORS에러를 <span style="color:royalblue"><strong>해결</strong></span>할 수 있을 것이다.
하지만, 서비스를 로컬 환경에서만 돌리는건 아니니.. 
사실상 <span style="color:royalblue"><strong>근본적인 문제를 해결해주지는 못한다.</strong></span>
<del>(그것도 모르고 해결했다고 좋아했다가 바로 지웠던 기억이..😂)</del></p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/1f161b01-506b-47f9-ae14-de01c9e2fac4/image.png" alt=""></p>
<br>

<h3 id="span-stylebackgroundcolorlightyellow2-proxy-서버-이용span"><span style="backgroundColor:lightyellow">2. Proxy 서버 이용</span></h3>
<blockquote>
<p>📒 <strong>Proxy가 뭔가요?</strong>
프록시(Proxy)란 클라이언트와 서버 사이의 서버 대리점 역할을 한다고 보면 된다.</p>
</blockquote>
<p>서버에 따로 설정을 안한 상태에서, 
클라이언트가 서버에 리로스 요청을 한다면 CORS 에러가 발생할 것이다.</p>
<p>이런 경우, <span style="color:royalblue"><strong>모든 출처를 허용한 서버 대리점</strong></span>인 프록시(Proxy) 서버를 통해 요청을 하면 되는 것이다! 하지만, 무료 프록시(Proxy) 서버 대여 서비스들은 악용 사례가 있어 <span style="color:royalblue"><strong>직접 프록시(Proxy) 서버를 구축하여 사용</strong></span>해야 한다.</p>
<p>내가 기업협업 프로젝트에서 마주한 CORS에러도
프록시(Proxy)서버를 통해 해결할 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/525685f5-62b1-4895-91bb-751d6071e9cb/image.png" alt=""></p>
<br>

<h3 id="span-stylebackgroundcolorlightyellow3-서버에서-access-control-allow-origin-헤더-세팅span"><span style="backgroundColor:lightyellow">3. 서버에서 Access-Control-Allow-Origin 헤더 세팅</span></h3>
<blockquote>
<p>📜 <strong>CORS 해결의 정석</strong>
직접 서버에서 HTTP 헤더 설정을 통해 출처를 허용하게 설정하는 가장 정석적인 해결책이라고 한다.</p>
</blockquote>
<p>서버의 종류마다 해결방법이 있는 것처럼 보이는데.
프론트 단에서 해결할 수 있는 방법에 대한 이야기는 아니기에 이에 대한 내용은 추후에 차차 알아가보고 싶다.
<del>(삐약삐약거리는 나로서..모르겠어요.그냥 모르겠어요..ㅎ)</del></p>
<p><br><br></p>
<h2 id="나의-경험에-대하여">나의 경험에 대하여</h2>
<hr>
<blockquote>
<p>💬 내가 CORS에러를 마주했던 경험에 대한 이야기를 잠깐 하고 글을 마무리하려고 한다. 기업협업 프로젝트 당시 이 에러로 하루종일 애를 먹었었기에..ヽ(*。&gt;Д&lt;)o゜</p>
</blockquote>
<br>

<h3 id="span-stylebackgroundcolorlightyellow💥-문제상황span"><span style="backgroundColor:lightyellow">💥 문제상황</span></h3>
<p><code>Next.js</code>로 개발을 하던 도중, CORS에러를 마주쳤다. <code>Next.js</code>의 <code>getSeverSideProps()</code>로 API 호출을 하지 않고, 전역 상태 라이브러리 MobX store에서 API 호출해 데이터를 받아와야하는 상황이었다. </p>
<p>store에서 API를 호출해 데이터를 받아오는 함수를 만들어주었다.
그리고 받아온 데이터를 사용할 컴포넌트에서 해당 함수를 호출해 데이터를 사용하고자 했다.</p>
<pre><code class="language-jsx">// BrandStore.jsx
getModalBrandList = async () =&gt; {
  // 데이터 받아오기
  try {
      const res = await axios({
        method: &#39;get&#39;,
        url: &#39;http://example.co.kr:8000/brands/all&#39;,
      });

      if (res.status === 200) {
        runInAction(() =&gt; {
          this.modalBrandList.data = res.data.results;
        });
      }
    } catch (err) {
      console.log(err);
    } finally {
      return this.modalBrandList;
    }
};

// BrandModal.jsx
useEffect(() =&gt; {
    getModalBrandList();
}, []);</code></pre>
<br />

<p>그랬더니 <span style="color:red"><code>Access to XMLHttpRequest at &#39;API 호출 주소&#39; from origin &#39;http://localhost:3000&#39;has been blocked by CORS policy</code></span>란 error 메시지를 확인할 수 있었다. 개발자도구의 Network탭에서도 마찬가지로 <span style="color:red">CORS에러</span>인 것을 확인할 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/d6a2a340-1b1e-499c-a9f0-e456c177b0a3/image.png" alt=""></p>
<p><br><br></p>
<h3 id="span-stylebackgroundcolorlightyellow💢-원인span"><span style="backgroundColor:lightyellow">💢 원인</span></h3>
<blockquote>
<p>🤦🏻‍♀️ <strong><em>그럼 SSR에선 왜 되는건데!!</em></strong> </p>
</blockquote>
<p>가장 의문이 들었던 점은 <code>getSeverSideProps()</code>로 API를 호출했을 때는 CORS 에러가 발생하지 않는다는 것이었다.</p>
<p>알고보니 <span style="color:royalblue"><strong>SSR는</strong></span> 브라우저를 거치지 않고
프론트 서버에서 백엔드 서버로 요청을 보내는 것이기 때문에
<span style="color:royalblue"><strong>브라우저의 개입이 없어</strong></span> CORS 에러가 발생하지 않았던 것이다!</p>
<p><br><br></p>
<h3 id="span-stylebackgroundcolorlightyellow🎀-해결방법span"><span style="backgroundColor:lightyellow">🎀 해결방법</span></h3>
<p>직접 프록시(Proxy)서버를 구축하지 않아도
몇 줄의 코드로 경로를 우회시킬 수 있다니 너무 신기했다.. 갓넥스트✨</p>
<blockquote>
<ul>
<li><code>Next.js</code>에서 Proxy 설정을 해주려면 아래의 코드만 작성해주면 된다😱</li>
</ul>
</blockquote>
<ul>
<li>이는 <code>Next.js</code> <a href="https://nextjs.org/docs/api-reference/next.config.js/rewrites">공식문서</a>를 통해 쉽게 확인하여 적용시킬 수 있다.</li>
<li><code>rewrites</code>는 URL 프록시 역할을 한다는 점!</li>
</ul>
<pre><code class="language-jsx">// next.config.js
module.exports = {
    async rewrites() {
        return [
            {
                source: &quot;/:path*&quot;, // 들어오는 요청 경로 패턴
                destination: &quot;http://localhost:5000/:path*&quot;, // 라우팅하려는 경로
            },
        ];
    },
}</code></pre>
<blockquote>
<p>❓ <strong>프론트에서 해결하는 이유?</strong>
서버에서 <code>Access-Control-Allow-Origin</code> 헤더를 세팅하는 방법도 
있다는 것을 알았기 때문에 프론트 단에서 이를 해결한 이유에 대해 궁금해
프론트 사수분께 이를 여쭤보았다. <br >
서버에서 CORS에러에 대한 문제를 해결하는 방법도 있지만,
<span style="color:royalblue"><strong>만약 서비스가 배포된 상태라고 할 때, 수정이 어렵기 때문에</strong></span> 프론트 단에서
이를 해결해준 것이라는 답변을 얻을 수 있었다.</p>
</blockquote>
<p><br><br></p>
<h2 id="배운점">배운점</h2>
<hr>
<h3 id="span-stylebackgroundcolorlightyellow⭐-cors에러는-브라우저에서만-발생span"><span style="backgroundColor:lightyellow">⭐ CORS에러는 브라우저에서만 발생</span></h3>
<blockquote>
<p>🤦🏻‍♀️ SSR과 CSR의 방식에는 백엔드 서버로부터 <span style="color:royalblue"><strong>데이터를 호출하는
주체가 다르기 때문에</strong></span> SSR의 방식에선 CORS에러가 발생하지 않고,
CSR 방식에서 CORS에러가 발생한다는 것을 알게 되었다. <br>
💁🏻‍♀️ 결론부터 말하자면,
<span style="color:royalblue"><strong>SSR</strong></span>은 <span style="color:royalblue"><strong>프론트 서버</strong></span>가 백엔드 서버에 데이터를 요청하는 반면
<span style="color:royalblue"><strong>CSR</strong></span>에선 <span style="color:royalblue"><strong>클라이언트(브라우저)</strong></span>에서 백엔드 서버에 데이터를 요청한다.</p>
</blockquote>
<br>

<h4 id="1-ssr-server-side-rendering">(1) SSR (Server Side Rendering)</h4>
<p>전통적인 SSR 방식은 <code>클라이언트 - 프론트 서버 - 백엔드 서버</code> 간의 통신 순서를 지킨다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/cffd3e51-772d-4282-9c89-b9714457197b/image.png" alt=""></p>
<blockquote>
<ol>
<li>웹사이트 접속</li>
<li>프론트 서버가 백엔드 서버한테 데이터를 요청</li>
<li><span style="color:royalblue"><strong>프론트 서버</strong></span>는  <span style="color:royalblue"><strong>백엔드 서버로부터 전달받은 데이터</strong></span>를 <code>HTML</code>, <code>CSS</code>, <code>JS</code>와 같은 프론트 소스와 함께 클라이언트에게 응답</li>
</ol>
</blockquote>
<br>

<h4 id="2-client-side-rendering-csr">(2) Client Side Rendering (CSR)</h4>
<p>반면에, CSR은 SSR과는 다른 방식으로 통신이 진행되며 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/a8d60e5b-fa52-4e89-b0d3-49c638404c61/image.png" alt=""></p>
<blockquote>
</blockquote>
<ol>
<li>웹사이트 접속 &amp; 클라이언트가 백엔드 서버로 직접 데이터 요청</li>
<li>프론트 서버로부터 프론트 관련 소스만 응답받음 &amp; <span style="color:royalblue"><strong>클라이언트가 백엔드 서버로부터 데이터 응답</strong></span>받음</li>
</ol>
<p><br><br></p>
<h3 id="span-stylebackgroundcolorlightyellow🌍-브라우저가-보내는-요청span"><span style="backgroundColor:lightyellow">🌍 브라우저가 보내는 요청</span></h3>
<blockquote>
<p>🤷🏻‍♀️ <em><strong>그럼 왜 브라우저가 보내는 요청은 그 출처가 다른걸까?</strong></em></p>
</blockquote>
<p>대부분의 브라우저는 요청을 보낼 때 해당 <span style="color:royalblue"><strong>요청이 안전한지 확인</strong></span>하기 위해 미리 찔러보는 작업을 한다고 한다. </p>
<p>바로 <span style="color:royalblue"><strong>미리 요청</strong></span>을 보내보는 것인데, 이를 <code>Preflight(프리플라이트)</code>라고 한다.
_<span style="color:gray">(위의 &#39;CORS 동작원리&#39;에서 다루었던 <strong>Preflight Request</strong>와 <strong>Simple Request</strong> 떠올리기!)</span>_</p>
<p>이 때, 서버에서 올바른 응답을 하더라도 응답 header에 <code>Access-Control-Allow-Origin</code>이 없거나, 설정된 <code>Access-Control-Allow-Origin</code>의 값이 요청을 보낸 클라이언트의 도메인과 다르면 브라우저에서 자체적인 오류를 발생시커 요청을 진행하지 않는다고 한다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/a1b0d0cc-aaa2-4852-a220-496eec55fe6b/image.png" alt=""></p>
<p><br><br></p>
<h2 id="📜-참고">📜 참고</h2>
<hr>
<p>이 글은 아래의 글을 바탕으로 공부하며 개인적으로 정리한 글입니다.
이미지에 대한 출처는 아래의 포스팅에 있습니다.</p>
<ul>
<li><a href="https://ko.javascript.info/fetch-crossorigin">https://ko.javascript.info/fetch-crossorigin</a></li>
<li><a href="https://it-eldorado.tistory.com/163">https://it-eldorado.tistory.com/163</a></li>
<li><a href="https://hannut91.github.io/blogs/infra/cors">https://hannut91.github.io/blogs/infra/cors</a></li>
<li><a href="https://jjnooys.medium.com/web-hello-cors-f8cfe39d9265">https://jjnooys.medium.com/web-hello-cors-f8cfe39d9265</a></li>
<li><a href="https://velog.io/@wiostz98kr/CORS%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83">https://velog.io/@wiostz98kr/CORS%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[lighthouse를 이용한 성능 최적화]]></title>
            <link>https://velog.io/@hye_rin/lighthouse%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94</link>
            <guid>https://velog.io/@hye_rin/lighthouse%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94</guid>
            <pubDate>Wed, 21 Dec 2022 07:36:24 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>⚡ Chrome에서 제공하는 웹사이트 성능 측정 도구, LightHouse를 사용해서 성능 최적화를 해봤다. 2차 프로젝트에 적용했으며, <strong><span style="color:red">18점</span></strong>까지도 내려갔던 점수를 <strong><span style="color:red">90점 이상</span></strong>까지 끌어올릴 수 있었다.</p>
</blockquote>
<p><br><br></p>
<h2 id="0-lighthouse-결과항목-분석">0. lighthouse 결과항목 분석</h2>
<hr>
<p>우선 lighthouse에는 다음과 같은 항목이 존재한다.
항목 별 점수를 모두 90점 이상으로 끌어올리는 것이 목표였다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/3a7f456a-b64c-4340-8ce8-806c8d480419/image.png" alt=""></p>
<blockquote>
<ol>
<li>✔ <strong>Performance</strong><ul>
<li>웹 페이지의 로딩 속도 등 실제 성능을 측정한다.</li>
</ul>
</li>
<li>🐾 <strong>Accessibility</strong><ul>
<li>웹 페이지의 접근성을 측정한다.</li>
</ul>
</li>
<li>🧾 <strong>Best Practices</strong><ul>
<li>웹 페이지가 웹에 대한 표준 모범 사례를 따르고 있는지 확인한다.</li>
</ul>
</li>
<li>🔎 <strong>SEO (Search Engine Optimization)</strong><ul>
<li>검색 엔진 수집 최적화가 된 정도를 측정한다.</li>
</ul>
</li>
<li>📱 <strong>PWA (Progressive Web App)</strong><ul>
<li>해당 웹사이트가 모바일 애플리케이션으로도 잘 작동하는지 확인한다.</li>
</ul>
</li>
</ol>
</blockquote>
<p><br><br></p>
<h2 id="1-📸-이미지-용량-줄이기">1. 📸 이미지 용량 줄이기</h2>
<hr>
<h3 id="1-문제상황">(1) 문제상황</h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/8550c2f3-ac2b-4f44-b067-0d8b84365fbb/image.png" alt=""></p>
<p>성능 최적화를 진행한 Main 페이지에는 크기가 큰(용량도 큰) 이미지가 많다.
이미지 슬라이드(캐러셀)은 물론이고, 클래스 항목별로 이미지를 불러오기 때문이다.
그래서 처음 lighthouse로 성능을 측정했을 때 점수가 정말 참담했다..╚(•⌂•)╝</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/a7838f38-95bb-4a40-8ac5-54b0eb2a8358/image.png" alt=""></p>
<br>

<h3 id="2-개선방법">(2) 개선방법</h3>
<p>보통 이미지는 api 호출을 통해 url을 가져와 사용한다.
이렇게 받아온 이미지의 용량을 줄일 수 있는 방법은 image cdn을 사용하면 됐다.</p>
<blockquote>
<p>📘 <strong><span style="color:blue">image cdn?</span></strong>
image cdn을 사용하면 원하는 형태로 이미지를 바꿀 수 있다.</p>
</blockquote>
<p>나같은 경우, 무료로 사용 가능한 unsplash의 이미지를 사용했기 때문에
upsplash에서 자체 제공하는 <strong><span style="color:red">image cdn</span></strong>을 사용했다.
<code>getParametersForUnsplash()</code> 함수를 선언해준 뒤, 이미지를 불러올 때 URL뒤에 해당 함수와 함께 원하는 크기값을 지정해주면 된다.</p>
<p>이미지 슬라이드는 <code>react-slick</code>라이브러리를 사용했다. 따라서 아래의 코드는 슬라이드 관련 코드를 생략하고 직접적으로 image cdn이 사용되는 부분만 가져왔다.</p>
<pre><code class="language-jsx">function Carousel() {
  // unsplash에서 제공하는 image cdn
  function getParametersForUnsplash({ width, height, quality, format }) {
    return `?w=${width}&amp;h=${height}&amp;q=${quality}&amp;fm=${format}&amp;fit=crop`;
  }

  return (
    // 생략
    &lt;Image
      src={
        image.url +
        getParametersForUnsplash({
          width: 676,
          height: 415,
          quality: 80,
          format: &#39;jpg&#39;,
        })
      }
      alt=&quot;이미지 슬라이드&quot;
    /&gt;
  );
}</code></pre>
<br>

<h3 id="3-결과">(3) 결과</h3>
<p><span style="color:red"><strong>18점</strong></span>이었던 Performance 점수가 <span style="color:red"><strong>78점</strong></span>까지 올라갔다. 
이미지 용량이 얼마나 많은 비중을 차지하고 있었던건가..(ﾟДﾟ*)ﾉ</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/b9c5257a-3028-462e-b98a-79e8b9c32cfa/image.png" alt=""></p>
<p><br><br></p>
<h2 id="2-😊-react-icons-번들-사이즈-줄이기">2. 😊 <code>react-icons</code> 번들 사이즈 줄이기</h2>
<hr>
<h3 id="1-문제상황-1">(1) 문제상황</h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/8357ee87-1e98-4747-9f95-aa663ec6a735/image.png" alt=""></p>
<p><code>Opportunity</code>에서는 리소스 관점에서의 가이드를 확인할 수 있다. 즉, 로딩 성능을 이야기하는데. <code>Reduce unused JavaScript</code>가 가장 많은 시간을 잡어먹고 있는 것을 확인할 수 있었다. </p>
<p>그런데 그 중에서도 눈에 띄었던 것은 바로 <code>react-icons</code>였다. 아이콘 이미지를 따로 저장해 사용하지 않고, <code>react-icons</code>라이브러리를 설치해서 사용해주었었는데 <code>bundle.js</code>에서 이렇게나 많은 비중을 차지하고 있을 줄 몰랐다. </p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/4d765530-e60d-431c-9564-f91d5df6020d/image.png" alt=""></p>
<br>

<h3 id="2-개선방법-1">(2) 개선방법</h3>
<p><code>react-icons</code>는 아이콘의 종류별로 하나의 JavaScript파일에 아이콘 전체를 포함하고 있다고 한다. 따라서 나는 하나만 import해왔다고 생각했지만 해당 아이콘을 담고있는 전체 파일을 가져와 성능상 문제가 생겼던 것이다.</p>
<p>따라서, <code>react-icons</code>에서 제공하는 <code>@react-icons/all-files</code>라이브러리를 사용했다. 이를 사용하면 아이콘 별로 JavaScript 파일을 가지고 있기 때문에 빌드할 때 <span style="color:red"><strong>보다 적은 크기의 chunk를 만들어낼 수 있다</strong></span>고 한다.</p>
<blockquote>
<p>📘 <strong><span style="color:blue">chunk?</span></strong>
Webpack에서 애플리케이션 코드를 각기 다른 파일로 나눈것을 chunk라고 부른다고 한다.</p>
</blockquote>
<pre><code class="language-jsx">// Before
import { AiOutlineClose, AiFillFacebook } from &#39;react-icons/ai&#39;;
import { RiKakaoTalkFill } from &#39;react-icons/ri&#39;;
import { FiLink2 } from &#39;react-icons/fi&#39;;

// After
import { AiOutlineClose } from &#39;@react-icons/all-files/ai/AiOutlineClose&#39;;
import { AiFillFacebook } from &#39;@react-icons/all-files/ai/AiFillFacebook&#39;;
import { RiKakaoTalkFill } from &#39;@react-icons/all-files/ri/RiKakaoTalkFill&#39;;
import { FiLink2 } from &#39;@react-icons/all-files/fi/FiLink2&#39;;</code></pre>
<br>

<h3 id="3-결과-1">(3) 결과</h3>
<p><span style="color:red"><strong>1.56초</strong></span>였던 <code>Reduce unused JavaScript</code>항목이 <span style="color:red"><strong>0.99초</strong></span>로 
절반가량의 시간이 단축된 것을 확인할 수 있었다!🎊
<span style="color:orange"><em>(라이브러리 사용하면 편하다고 이것저것 막 갖다가 사용하면 나중에 성능상으로 문제가 생길 수 있겠단 생각이 들었다..)</em></span></p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/760cf435-3199-45ab-8037-8c7b84535ccc/image.png" alt=""></p>
<p><br><br></p>
<h2 id="3-✂️--코드-분할">3. ✂️  코드 분할</h2>
<hr>
<h3 id="1-문제상황-2">(1) 문제상황</h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/2479446e-5538-4b5f-b558-5c4eaf6176ee/image.png" alt=""></p>
<p><code>react-icons</code>번들링을 줄였음에도 <code>Reduce unused JavaScript</code>에서 많은 시간이 지체된다고 생각했다. </p>
<p>이런 문제가 생긴 이유는 CRA(Create-react-app)으로 프로젝트 환경을 세팅했기 때문인데. CRA(Create-react-app)으로 환경 세팅할 경우, 기본적인 Webpack 및 Babel 설정이 자동적으로 되어있다. 그리고 번들링이 되면 모든 JavaScript의 파일이 하나의 JavaScript 파일로 합쳐지는 과정(bundle.js)을 거치게 된다.</p>
<p>이를 개선하는 방법으로 React에서는 <a href="https://ko.reactjs.org/docs/code-splitting.html">코드 분할(Code Splitting)</a>에 대해 설명하고 있다. 그래서 나도 코드 분할을 해보기로 했다!</p>
<br>

<h3 id="2-개선방법-2">(2) 개선방법</h3>
<blockquote>
<p>📘 <strong><span style="color:blue">코드 분할(Code Splitting) 사용방법</span></strong>
<code>React.lazy()</code>함수를 사용하면 동적 import를 사용해 컴포넌트를 렌더링할 수 있다.</p>
</blockquote>
<pre><code class="language-jsx">// Before
import Detail from &#39;./pages/Detail/Detail&#39;;</code></pre>
<pre><code class="language-jsx">// After
import { lazy } from &#39;react&#39;;
const Detail = lazy(() =&gt; import(&#39;./pages/Detail/Detail&#39;));</code></pre>
<p>모든 <code>import</code>가 아닌 <code>Route</code>(페이지)에 기반해여 코드 분할 방법을 사용했다. 그런데 여기서 또 문제💥가 발생했다. <code>lazy</code>를 건 컴포넌트 페이지로 이동 시 아래와 같은 error 문구가 나오며 페이지가 정상적으로 나오지 않았다.</p>
<p>error가 하는 말은 다음과 같았다. 코드 분할로 페이지 로딩하는 시간이 생겼는데 <strong><span style='color:Red'>loading indicator가 없다</span></strong>는 것!</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/82d4f38c-f36a-4e6d-88d8-a087d1ba08b5/image.png" alt=""></p>
<p>그래서 다음과 같이 <code>lazy</code>를 걸어 import하는 컴포넌트를 감싸는 <code>Suspense</code>를 통해 해결할 수 있었다. 로딩하는 동안 <code>fallback</code>속성의 내용이 화면에 보이게 된다. </p>
<p>Loading이란 텍스트만 임시로 넣어두었지만, spinner 컴포넌트를 따로 만들어 넣어준다면 더 사용자 경험이 좋아지겠지?👍🏻</p>
<pre><code class="language-jsx">import { lazy, Suspense } from &#39;react&#39;;
import { Routes, Route } from &#39;react-router-dom&#39;;
import Nav from &#39;./components/Nav/Nav&#39;;
import Main from &#39;./pages/Main/Main&#39;;
const Detail = lazy(() =&gt; import(&#39;./pages/Detail/Detail&#39;));
const MyPage = lazy(() =&gt; import(&#39;./pages/MyPage/MyPage&#39;));
const Footer = lazy(() =&gt; import(&#39;./components/Footer/Footer&#39;));

const NavVisibleComponents = () =&gt; {
  return (
    &lt;&gt;
      &lt;Nav /&gt;
      &lt;Suspense fallback={&lt;div&gt;Loading...&lt;/div&gt;}&gt;
        &lt;Routes&gt;
          &lt;Route path=&quot;/&quot; element={&lt;Main /&gt;} /&gt;
          &lt;Route path=&quot;/classes/detail/:id&quot; element={&lt;Detail /&gt;} /&gt;
          &lt;Route path=&quot;/mypage&quot; element={&lt;MyPage /&gt;} /&gt;
        &lt;/Routes&gt;
      &lt;/Suspense&gt;
      &lt;Footer /&gt;
    &lt;/&gt;
  );
};

export default NavVisibleComponents;
</code></pre>
<br>

<h3 id="3-결과-2">(3) 결과</h3>
<p><span style="color:red"><strong>0.99초</strong></span>였던 <code>Reduce unused JavaScript</code>항목이 <span style="color:red"><strong>0.8초</strong></span>로 
조금이나마 줄어든 것을 확인할 수 있었다!(@^0^@)</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/08d8c366-2ce4-4f27-b363-3d866e1fa932/image.png" alt=""></p>
<p><br><br></p>
<h2 id="4-⚡-cls-개선">4. ⚡ CLS 개선</h2>
<hr>
<h3 id="1-문제상황-3">(1) 문제상황</h3>
<p>위의 내용을 개선해나가며 Performance점수가 많이 좋아졌지만,
한 가지 계속 괴롭히는 항목이 있었는데.. <code>Cumulative Layout Shift</code>였다.</p>
<p>이 항목은 동적 DOM 변경 등으로 웹 페이지의 레이아웃이 얼마나 변하는 지 측정한 값으로, 사용자가 잘못된 클릭을 하도록 유발하는 시각적 불안정성을 체크하는 지표다. </p>
<p>아래의 예시와 같이 <strong>❌No, go back❌</strong>을 클릭했지만, 클릭하는 순간 광고창이 나오면서 <strong>⭕Yes, place my order⭕</strong>버튼을 클릭하게 되는 경우이다. 이렇게 <span style="color:blue">예상하지 못한 레이아웃 이동이 많다면 좋은 사용자 경험을 제공하고 있다고 할 수 없을 것이다.</span></p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/f1b04d6c-0f82-48ee-9ad0-416ad6e02862/image.gif" alt=""></p>
<p>아무튼 CLS에 걸리는 시간이 많다는 것은, 지금의 내 웹사이트에서
레이아웃 이동이 일어나고 있다는 것이었다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/ffc52eb5-3a08-48b1-968d-c4a7454d6d85/image.png" alt=""></p>
<br>

<h3 id="2-개선방법-3">(2) 개선방법</h3>
<p>페이지 가장 하단에 있는 <code>footer</code>에서 계속 CLS점수가 높게 나오고 있었다.
<code>footer</code>는 동적으로 콘텐츠가 삽입되는 일이 없는데 왜 자꾸 <code>footer</code>에서
점수가 높게 나오는건지 알 지 못해서 계속 <code>footer</code>위치만 조정해주며 헤맸었다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/0a298591-81d2-43a0-a0b6-e09a7177f3ce/image.png" alt=""></p>
<p>그런데 <code>lighthouse performance</code>탭을 통해 웹페이지가 화면에 그려지는 과정을 단계적으로 보던 그 순간..! 중간에 강의 목록들이 동적으로 추가되어서 처음에 <code>footer</code>가 그려졌다가 밑으로 쭉 밀리는 모습을 볼 수 있었다. 그렇다.. 애초에 <code>footer</code> 문제가 아니었다. <span style="color:red"><strong>동적으로 요소가 추가되고 있는건 그 위의 강의목록들</strong></span>이었다. </p>
<p>그래서 강의목록들이 동적으로 추가되는 전체 Container에 <code>height</code>를 지정해주었다. 그랬더니 Performance 점수가 놀랍게 올라가는 것을 확인할 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/87911275-1de4-4758-83be-5cc50b92b020/image.png" alt=""></p>
<br>

<h3 id="3-💝결과💝">(3) 💝결과💝</h3>
<p>맨 처음 <span style="color:red"><strong>18점</strong></span>이었던 Performance 점수가 <span style="color:red"><strong>91점</strong></span>까지 올라감으로써
성능 최적화를 <strong>모두 90점 이상</strong>인 ✅<span style="color:yellowgreen"><strong>초록불</strong></span>✅로 끝낼 수 있게 되었다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/8848e5af-d50c-4b55-930e-7e06a83ddf8b/image.png" alt=""></p>
<p><br><br></p>
<h2 id="참고">참고</h2>
<hr>
<ul>
<li><a href="https://kyounghwan01.github.io/blog/React/optimize-performance/properly-size-images/#%E1%84%92%E1%85%A2%E1%84%80%E1%85%A7%E1%86%AF">https://kyounghwan01.github.io/blog/React/optimize-performance/properly-size-images/#%E1%84%92%E1%85%A2%E1%84%80%E1%85%A7%E1%86%AF</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] require와 import의 차이]]></title>
            <link>https://velog.io/@hye_rin/React-require%EC%99%80-import%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@hye_rin/React-require%EC%99%80-import%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Tue, 20 Dec 2022 05:27:49 GMT</pubDate>
            <description><![CDATA[<h2 id="🧩-모듈이란">🧩 모듈이란?</h2>
<hr>
<ul>
<li><p>하나의 클래스, 혹은 특정한 목적을 가진 복수의 함수로 구성된 것을 <strong><span style="color:orange">모듈</span></strong>이라고 한다.</p>
</li>
<li><p>이후 설명할 <code>require</code>와 <code>exports</code> 키워드를 사용하는 <strong><span style="color:orange">CommonJS</span></strong>는 Node.js 서버를 위해 만들어진 모듈 시스템이다. 여기서 모듈 시스템이란, 프로그램 코드를 기능별로 나눠서  독립된 파일에 저장하여 관리하는 방식이라고 할 수 있다.</p>
</li>
<li><p><code>export</code>와 <code>import</code>와 같은 특수한 키워드를 통해 다른 모듈들을 불러와 
불러온 모듈에 있는 함수를 호출하는 것과 같은 <strong><span style="color:orange">기능 공유</span></strong>가 가능하다.</p>
</li>
</ul>
<p><br><br></p>
<h2 id="💌-require와-import">💌 require와 import</h2>
<hr>
<blockquote>
<p>🎃 <strong><span style="color:orange">require와 import의 공통점</span></strong>
하나의 파일에서 다른 파일의 코드를 불러온다는 동일한 목적을 가지고 있다.</p>
</blockquote>
<br>

<h3 id="1-require--exports-commonjs">1. <code>require</code> / <code>exports</code> (CommonJS)</h3>
<blockquote>
<ul>
<li>NodeJS에서 사용되는 CommonJS 키워드</li>
</ul>
</blockquote>
<ul>
<li>변수를 할당하듯 모듈을 불러온다.</li>
</ul>
<pre><code class="language-jsx">// exports
const name = &#39;고양이&#39;;
module.exports = name;</code></pre>
<pre><code class="language-jsx">// require
const name = require(&#39;./module.js&#39;);</code></pre>
<br>

<h3 id="2-import--export-es6">2. <code>import</code> / <code>export</code> (ES6)</h3>
<blockquote>
<ul>
<li>ES6(ES2015)에서 새롭게 도입된 키워드</li>
</ul>
</blockquote>
<pre><code class="language-jsx">// export
const name = &#39;고양이&#39;;
export default name;</code></pre>
<pre><code class="language-jsx">// import
import name from &#39;./module.js&#39;</code></pre>
<br>

<h3 id="3-exports와-export">3. <code>exports</code>와 <code>export</code></h3>
<blockquote>
<ul>
<li>exports는 CommonJS와 ES6라는 모듈 시스템에서 존재하는 객체이다.</li>
</ul>
</blockquote>
<ul>
<li>모듈로부터 내보내지는 데이터들을 담고있는 하나의 객체인 것이다.</li>
<li>ES6의 <code>export default</code>는 CommonJS의 <code>module.exports</code> 구문 동작을 대체하기 위한 문법이다.</li>
</ul>
<p><br><br></p>
<h2 id="📤-모듈-전체-내보내고-가져오기">📤 모듈 전체 내보내고 가져오기</h2>
<hr>
<h3 id="1-require--exports-commonjs-1">1. require / exports (CommonJS)</h3>
<pre><code class="language-jsx">// 모듈 전체를 export, 파일내 한번만 사용가능하다.
const obj = {
   num: 100,
   sum: function (a, b) {
      console.log(a + b);
   },
   extract: function (a, b) {
      console.log(a - b);
   },
};
module.exports = obj;</code></pre>
<pre><code class="language-jsx">// require
const obj = require(&#39;./exportFile.js&#39;);

obj.num; // 100
obj.sum(10, 20); // 30
obj.extract(10, 20); // -10</code></pre>
<br>

<h3 id="2-import--export-es6-1">2. import / export (ES6)</h3>
<pre><code class="language-jsx">// 모듈 전체를 export, 파일내 한번만 사용가능하다.
const obj = {
   num: 100,
   sum: function (a, b) {
      console.log(a + b);
   },
   extract: function (a, b) {
      console.log(a - b);
   },
};

export default obj;</code></pre>
<pre><code class="language-jsx">// 전체 자체를 export 할 경우 중괄호 없이 그냥 씀
import obj from &#39;./exportFile.js&#39;;

obj.num; // 100
obj.sum(10, 20); // 30
obj.extract(10, 20); // -10</code></pre>
<p><br><br></p>
<h2 id="📤-모듈-개별-내보내고-가져오기">📤 모듈 개별 내보내고 가져오기</h2>
<hr>
<h3 id="1-require--exports-commonjs-2">1. require / exports (CommonJS)</h3>
<blockquote>
<p>🎃  <strong><span style="color:orange">이것만 기억하자!</span></strong></p>
</blockquote>
<ol>
<li>여러개의 객체를 내보낼 때 → <code>exports.변수</code></li>
<li>딱 하나의 객체를 내보낼 때 → <code>module.exports = 객체</code></li>
</ol>
<pre><code class="language-jsx">// exports
exports.name = &#39;Ann&#39;; // 변수

exports.sayHello = function() { // 함수
    console.log(&#39;Hello World!&#39;);
}

exports.Person = class Person { // 클래스
    constructor(name){
        this.name = name;
    }
}

// require
const { name, sayHello, Person } = require(&#39;./exportFile.js&#39;);

console.log(name); // Ann
sayHello(); // Hello World!
const person = new Person(&#39;inpa&#39;);</code></pre>
<br>

<h3 id="2-import--export-es6-2">2. import / export (ES6)</h3>
<h4 id="✅-span-stylecoloryellowgreenexport-개별span">✅ <span style="color:yellowgreen">export 개별</span></h4>
<pre><code class="language-jsx">export const name = &#39;Ann&#39;; // 변수의 export

export function sayHello() { // 함수의 export
    console.log(&#39;Hello World!&#39;);
}

export class Person { // 클래스의 export
    constructor(name){
        this.name = name;
    }
}</code></pre>
<br>

<h4 id="✅-span-stylecoloryellowgreenexport-한꺼번에span">✅ <span style="color:yellowgreen">export 한꺼번에</span></h4>
<pre><code class="language-jsx">const name = &#39;Ann&#39;;

function sayHello() {
    console.log(&#39;Hello World!&#39;);
}

class Person {
    constructor(name){
        this.name = name;
    }
}

export {name, sayHello, Person}; // 변수, 함수, 클래스를 하나의 객체로 구성하여 export</code></pre>
<br>

<h4 id="✅-span-stylecoloryellowgreenimport-일반span">✅ <span style="color:yellowgreen">import 일반</span></h4>
<pre><code class="language-jsx">import { name, sayHello, Person } from &#39;./exportFile.js&#39;;</code></pre>
<br>

<h4 id="✅-span-stylecoloryellowgreenimport--as-별칭span">✅ <span style="color:yellowgreen">import * as 별칭</span></h4>
<blockquote>
<ul>
<li>개별로 export 된걸 * 로 한번에 묶고 as 로 별칭을 줘서, 마치 전체 export default 된걸 import 한 것 처럼 사용 가능하다.</li>
</ul>
</blockquote>
<pre><code class="language-jsx">import * as obj from &#39;./exportFile.js&#39;; 

console.log(obj.name); // Ann
obj.sayHello(); // Hello World!
const person = new obj.Person(&#39;inpa&#39;);</code></pre>
<p><br><br></p>
<h2 id="✨-commonjs-모듈-시스템의-필요성">✨ CommonJS 모듈 시스템의 필요성</h2>
<hr>
<blockquote>
<ul>
<li>많은 프로젝트에서 ES6 모듈 시스템을 점점 널리 사용하는 추세이지만,</li>
</ul>
</blockquote>
<ul>
<li>항상 <code>import</code>만을 사용하여 코딩할 수 있는 것은 아니다.</li>
<li><code>&lt;script&gt;</code>태그를 사용하는 브라우저 환경, NodeJS에서 CommonJS를 기본 모듈 시스템으로 채택하고 있기 때문에</li>
<li>Babel과 같은 ES6코드를 변환해주는 도구를 사용할 수 없는 상황에선 <code>require</code>를 사용해야 한다.</li>
</ul>
<p><br><br></p>
<h2 id="🎀-정리">🎀 정리</h2>
<hr>
<blockquote>
<ul>
<li>require와 import는 모듈 키워드입니다.</li>
</ul>
</blockquote>
<ul>
<li>외부 파일이나 라이브러리를 불러올 때 사용한다는 같은 목적을 가지고 있지만, 다른 문법구조를 가지고 있습니다.</li>
<li>require는 exports와 함께 사용되며, NodeJS에서 사용되는 CommonJS의 키워드이고,</li>
<li>import는 export와 함께 사용되며, ES6에서 새롭게 도입된 키워드입니다.</li>
<li>Babel과 같은 ES6 변환도구가 없이는 CommonJS의 require, exports를 사용해야 합니다.</li>
</ul>
<p><br><br></p>
<h2 id="📜-참고">📜 참고</h2>
<hr>
<p>이 글은 아래의 글을 바탕으로 공부하며 개인적으로 정리한 글입니다.</p>
<ul>
<li><a href="https://inpa.tistory.com/entry/NODE-%F0%9F%93%9A-require-%E2%9A%94%EF%B8%8F-import-CommonJs%EC%99%80-ES6-%EC%B0%A8%EC%9D%B4-1">https://inpa.tistory.com/entry/NODE-📚-require-⚔️-import-CommonJs와-ES6-차이-1</a></li>
<li><a href="https://www.daleseo.com/js-module-require/">https://www.daleseo.com/js-module-require/</a></li>
<li><a href="https://code-designer.tistory.com/103">https://code-designer.tistory.com/103</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[리팩토링하며 신경썼던 것들에 대해]]></title>
            <link>https://velog.io/@hye_rin/%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81%ED%95%98%EB%A9%B0-%EC%8B%A0%EA%B2%BD%EC%8D%BC%EB%8D%98-%EA%B2%83%EB%93%A4%EC%97%90-%EB%8C%80%ED%95%B4</link>
            <guid>https://velog.io/@hye_rin/%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81%ED%95%98%EB%A9%B0-%EC%8B%A0%EA%B2%BD%EC%8D%BC%EB%8D%98-%EA%B2%83%EB%93%A4%EC%97%90-%EB%8C%80%ED%95%B4</guid>
            <pubDate>Sun, 18 Dec 2022 15:14:38 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가며">들어가며</h2>
<p><a href="https://velog.io/@hye_rin/React-%EB%9F%AC%EC%89%AC%EC%BD%94%EB%A6%AC%EC%95%84-%ED%81%B4%EB%A1%A0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0">프로젝트</a>할 때 기능 구현에만 급급해 
좋은 코드를 작성하지 못했다는 생각이 들었다.</p>
<p>9월에 진행했던 프로젝트 코드를 다시 들여다보니
컴포넌트가 분리되어 있지 않아 가독성이 떨어졌으며,
동일한 로직을 반복하여 작성한 경우도 많았고,
함수명도 분명하지 않은 등..고쳐야할 부분이 많이 보였다.</p>
<p>리팩토링에 더해 TypeScript와 Redux를 공부해 적용해보기도 했던 지난2주!
리팩토링을 하며 내가 신경쓰며 진행했던 부분에 대해 정리해놓고자 한다.</p>
<blockquote>
<p>👩🏻‍🔧 <strong><span style="color:orange">리팩토링 (Refactoring)</span></strong>
프로그램의 외부 동작은 그대로 둔 채, 내부의 코드를 정리하면서 개선하는 것</p>
</blockquote>
<br>

<h2 id="1-컴포넌트의-분리🧩">1. 컴포넌트의 분리🧩</h2>
<p>왼쪽의 코드가 리팩토링 이전의 코드다.
한 파일, 한 컴포넌트에 한 페이지에 대한 거의 모든 내용을 담아냈었다.
내가 작성한 코드였고, 기능 구현에만 급급했기에
가독성에 대해 생각하지 못했었다.</p>
<p>그로부터 2-3달 정도가 지났기에
내가 작성한 코드임에도 파악하는 것이 쉽지 않았다.
어디서부터 어디까지가 어떤 기능을 하는지 하나하나 확인을 해야했다.</p>
<p>나조차도 이런데, 다른 사람이 이 코드를 보면 어떨까란 생각이 들었다.
그래서 컴포넌트를 최대한 분리하기 시작했다.
그러자 가독성도 좋아졌으며, 구조를 파악하기가 훨씬 좋았다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/c6262619-aba2-40c8-8482-4e4205b01393/image.png" alt=""></p>
<br>

<h2 id="2-이미지-용량-줄이기📸">2. 이미지 용량 줄이기📸</h2>
<p><code>lighthouse</code>로 해당 프로젝트에 대한 성능을 점수로 확인할 수 있었다.
LCP(Largest Contentful Paint)에 영향을 미치는 요소 중 하나인 <code>&lt;img&gt;</code>. 이미지 로딩에 차지하는 시간이 큰 듯했다.</p>
<p><code>width</code>와 <code>height</code>를 명시적으로 지정해주거나
다양한 버전의 크기를 지정해놓는 등 여러 방법이 있었는데,
우선 <code>jpeg</code> 파일 형식 자체가 용량이 크다고 판단했다. (png는 더 크고..╚(•⌂•)╝)
그래서 우선 메인 페이지의 이미지 슬라이드(캐러셀)에 들어가는
이미지 확장자를 <code>avif</code>로 변환해 바꿔주었다.</p>
<p>웹 성능이 20점이 넘게나 높아지는 걸 확인할 수 있었다.😱
(<del>메인페이지에 들어가는 이미지가 많은데 이미지 슬라이드에 해당되는 이미지만 변환시켜주어서 아직 성능이 썩 좋진 않다..</del>)
<img src="https://velog.velcdn.com/images/hye_rin/post/b230b862-4793-4fa0-a319-f7c350025dbf/image.png" alt=""></p>
<br>

<h2 id="3-로직-분리🍛">3. 로직 분리🍛</h2>
<p>장바구니 페이지나, 찜목록 페이지나 전체 데이터를 받아오는
api호출 내용이 동일한데, 불필요하게 반복되고 있다는 생각이 들었다.</p>
<p>Custom Hook을 사용해 각 페이지에서 useFetch를 가져다가 사용할 수 있었다.
하지만, 각 페이지에서 받아온 데이터는 store에서 전역적으로 관리되고 있었다.
두 데이터를 구분지어 받아오는 것이 필요하다고 생각해 
장바구니인지 찜목록인지 구분할 수 있는 인자를 추가적으로 넣었다.</p>
<p>지금까지 고안해낸 방법은 이러한 방식인데, 
최선의 방법은 아니란 생각이 들어서 차차 보완해나갈 생각이다.</p>
<pre><code class="language-jsx">// useFetch.tsx
import { useDispatch } from &#39;react-redux&#39;;
import { useEffect } from &#39;react&#39;;
import { getData, getLikeData } from &#39;../store/slices&#39;;

function useFetch(url: string, title: string) {
  const dispatch = useDispatch();
  const requestHeaders: HeadersInit = new Headers();
  const accessToken = localStorage.getItem(&#39;accessToken&#39;);
  requestHeaders.set(&#39;authorization&#39;, accessToken || &#39;Token not found&#39;);

  useEffect(() =&gt; {
    fetch(url, {
      headers: requestHeaders,
    })
      .then(response =&gt; {
        if (response.ok) {
          return response.json();
        }
        throw new Error(&#39;에러 발생!&#39;);
      })
      .catch(error =&gt; {
        alert(error);
      })
      .then(data =&gt; {
        if (title === &#39;cart&#39;) dispatch(getData(data));
        if (title === &#39;like&#39;) dispatch(getLikeData(data));
      });
  }, []);
}

export default useFetch;</code></pre>
<br>

<h2 id="4-상수데이터-관리📂">4. 상수데이터 관리📂</h2>
<p>Footer와 같은 경우, 상수데이터가 정말 많았다.
상수데이터를 따로 관리해 사용하지 않다보니, 
나중에 유지보수하기가 정말 힘들겠단 생각이 들었다.</p>
<p>지금이야 작은 팀프로젝트이니 크게 문제가 되지 않겠지만
만약 정말 많은 상수값이 코드에 녹여져있는데
수정을 해야하는 상황이 온다면..?
상수데이터가 분리되어 있지 않다면 얼마나 불편할까.</p>
<p>&#39;고객센터&#39;를 &#39;CS Center&#39;라는 문구로 바꾼다고 가정해본다면,
상수데이터화 시켜놓지 않은 코드는 &#39;고객센터&#39;라는 문구를
전부 찾아 일일이 바꿔줘야할 것이다.🤧 
그런상황이 오지않게 미리미리 연습해두자!</p>
<pre><code class="language-jsx">// FooterConstant.jsx
export default {
  // 생략
  CS_CENTER: {
    CENTER: [
      {
        TITLE: &#39;고객센터&#39;,
        NUMBER: &#39;1644-9825&#39;,
        EMAIL: &#39;eogh773@Naver.com&#39;,
      },
      {
        TITLE: &#39;기업선물&#39;,
        NUMBER: &#39;010-3633-3190&#39;,
        EMAIL: &#39;order@hush.co.kr&#39;,
      },
    ],
    CONTACT: [
      {
        TITLE: &#39;상담전화&#39;,
        HOUR: &#39;13:00 16:00(평일)&#39;,
      },
      {
        TITLE: &#39;상담톡&#39;,
        HOUR: &#39;10:00 16:00(평일)&#39;,
      },
    ],
  },
}</code></pre>
<br>

<h2 id="마치며">마치며</h2>
<p>약 2주에 걸쳐 리팩토링을 진행하며
<strong><span style="color:orange">리팩토링에 끝이 존재하긴 할까..</span></strong>란 생각이 가장 많이 들었다.
손을 대면 댈수록 손을 대야할 부분이 계속 눈에 보였고,
고치고 고쳐도 더 나은 코드로 만들 수 있을 것만 같았다.</p>
<p>보수공사는 계속해서 필요한거니까!👩🏻‍🔧
이대로 1차 프로젝트에 대한 리팩토링을 종료할 생각은 없다.
2차 프로젝트 리팩토링을 하며
또 깨닫는 점이 있다면 1차 프로젝트에도 이어서 적용시켜서
더 나은 코드로 점점 발전시키고 싶다.🛬🛫</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 타입스크립트를 사용하는 이유는 뭘까?]]></title>
            <link>https://velog.io/@hye_rin/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EB%8A%94-%EB%AD%98%EA%B9%8C</link>
            <guid>https://velog.io/@hye_rin/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EB%8A%94-%EB%AD%98%EA%B9%8C</guid>
            <pubDate>Thu, 08 Dec 2022 12:12:39 GMT</pubDate>
            <description><![CDATA[<h2 id="1-javascript">1. JavaScript</h2>
<hr>
<p>TypeScript를 알기 전에 JavaScript를 먼저 짚고 넘어가보자!</p>
<blockquote>
<ul>
<li>JavaScript는 1995년 넷스케이프사의 브렌던 아이크(Brendan Eich)가 개발한 스크립트 언어이다. </li>
</ul>
</blockquote>
<ul>
<li>서둘러 출시된 언어인데다가 과거 웹페이지의 보조적인 기능을 수행하기 위해 한정적인 용도로 만들어진 태생적인 한계를 가지고 있다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/bd69e2a9-9488-40db-9c53-f0ddd5aa9cdf/image.png" alt=""></p>
<br>

<h3 id="1-1-javascript-인기-급상승-시기">1-1. JavaScript 인기 급상승 시기</h3>
<p>하지만 한낮 보조 기능을 수행하는데 불과했던 
JavaScript의 위상은 달라지기 시작하는데..🚀</p>
<blockquote>
<ol>
<li>HTML5의 등장 (2014.10.28)<ul>
<li>기존의 웹 애플리케이션은 플러그인에 의존하여 구축되었다면,
HTML5 등장으로 JavaScript가 그 자리를 대신하게 되었다.<br></li>
</ul>
</li>
<li>AJAX의 활성화<ul>
<li>AJAX(Asynchronous  JavaScript and XML)는 JavaScript를 이용해 비동기식으로 XML을 이용해 서버와 통신하는 방식</li>
<li>서버 측이 담당하던 많은 일들이 클라이언트측으로 이동하게 되었다.</li>
</ul>
</li>
</ol>
</blockquote>
<br>

<h3 id="1-2-javascript-단점">1-2. JavaScript 단점</h3>
<p>JavaScript는 C, JAVA와 구별되는 특성이 있는데 다음과 같다.</p>
<blockquote>
<ol>
<li>프로토타입 기반 프로그래밍(Prototype-based Object Oriented Language)</li>
<li>Scope와 this</li>
<li>동적 타입(dynamic typed) 언어 혹은 느슨한 타입(loosely typed) 언어</li>
</ol>
</blockquote>
<p>이러한 특징은 클래스 기반 객체지향 언어(Java, C++, C# 등)에 익숙한 개발자를 혼란스럽게 했다. 이러한 문제를 극복하고자 자바스크립트 대체 언어가 등장하기 시작했다. 그 예로, CoffeScript, Dart, Haxe 등이 있겠다.</p>
<p>아무튼 <strong>타입스크립트</strong> 역시 자바스크립트의 문제를 극복하고자 등장한 
<strong>자바스크립트 대체 언어</strong>이다.</p>
<p><br><br></p>
<h2 id="2-typescript🎉">2. TypeScript🎉</h2>
<hr>
<ul>
<li>앞서 언급했듯 TypeScript JavaScript 대체 언어의 하나로, </li>
<li><em>ES5*</em>의 상위확장(Superset) 언어이다.</li>
<li>Microsoft에서 C#의 창시자가 2012년에 발표했다.
(Microsoft의 VSCode도 TypeScript로 개발되었다고 한다👀)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/e048a4df-9e50-432f-9887-8d39bf8f5343/image.png" alt=""></p>
<p><br><br></p>
<h2 id="3-typescript-특징">3. TypeScript 특징</h2>
<hr>
<h4 id="1-정적-타이핑을-지원한다">(1) 정적 타이핑을 지원한다.</h4>
<p>정적타입과 동적타입은 아래에서 조금 더 자세하게 다뤄보겠다.</p>
<h4 id="2-es5의-문법을-그대로-사용할-수-있다">(2) ES5의 문법을 그대로 사용할 수 있다.</h4>
<h4 id="3-ecmascript의-가장-최신-업데이트를-빠르게-반영한다">(3) ECMAScript의 가장 최신 업데이트를 빠르게 반영한다.</h4>
<blockquote>
<p>💁🏻‍♀️ <strong>ECMAScript</strong></p>
</blockquote>
<ul>
<li>JavaScript의 기반이 되는 스크립팅 언어 명세</li>
<li>ES6 (ECMAScript 2015)의 클래스, 모듈 등과 ES7의 Decorator 등을 지원한다.</li>
<li>ES6의 새로운 기능을 사용하기 위해 <strong>Babel</strong>과 같은 트랜스파일러(Transpiler)를 사용하지 않아도 실행할 수 있다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/a7230e98-e60e-4acd-989c-e3ee51a78d73/image.png" alt=""></p>
<br>

<h4 id="4-꾸준히-관심도가-증가하는-추세다">(4) 꾸준히 관심도가 증가하는 추세다.</h4>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/2810603f-8bd2-40ad-b182-4e0cf2768ce9/image.png" alt=""></p>
<p><span style="color:lightgray">출처: Google Trends, 검색어 TypeScript</span></p>
<br>

<h4 id="5-ms의-경쟁사도-선택한-언어다">(5) MS의 경쟁사도 선택한 언어다!</h4>
<ul>
<li><strong>구글</strong>은 구글이 개발한 JS 프레임워크 <strong>Angular</strong>의 주력 언어로 <strong>TypeScript</strong>를 채택했다.
(TypeScript의 상위집합인 AtScript라는 것도 계획했다하지만..결국엔..)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/84567757-07d1-41fb-bf03-67d2a4b8468f/image.png" alt=""></p>
<ul>
<li>또한,  2017년 TypeScript를 <strong>사내 표준 언어</strong>(Canonical Languages)로 승인함으로써</li>
<li>구글애널리틱스, 파이어베이스, 구글 클라우드 플랫폼 등 대규모 프로젝트, 그리고
핵심적인 내부 도구에 TypeScript와 TypeScript 기반 Angular를 사용하고 있다.</li>
</ul>
<p><br><br></p>
<h2 id="4-typescript-사용이유장점">4. TypeScript 사용이유/장점</h2>
<hr>
<h3 id="1-정적-타입⭐">(1) 정적 타입⭐</h3>
<p>TypeScript를 <strong>사용하는 가장 큰 이유</strong> 중 하나는 정적 타입을 지원한다는 것이다.</p>
<blockquote>
<p>💁🏻‍♀️ <strong>동적 타입이란? (Dynamic)</strong></p>
</blockquote>
<ul>
<li>컴파일 시 자료형을 정하지 않고, 코드를 실행할 때 결정한다.</li>
<li>예시<pre><code class="language-jsx">  let num = 1; // 숫자
  num = &quot;number 1&quot;;  // 문자</code></pre>
</li>
</ul>
<blockquote>
<p>💁🏻‍♀️ <strong>정적 타입이란? (Static)</strong></p>
</blockquote>
<ul>
<li><strong>컴파일 시</strong> 변수의 타입이 결정되는 언어</li>
<li>변수 생성 시 타입을 같이 명시해주는 것</li>
<li>예시<ul>
<li>num 변수가 int로 타입 선언된다.<pre><code class="language-java">Int num = 1; </code></pre>
</li>
</ul>
</li>
</ul>
<p>아래의 함수는 두개의 인자를 받아 합계를 구하는 함수로 보인다.
하지만, 전달되는 인수나 return되는 값이나 <strong>Type이 명확하지 않다</strong>.
이는 JavaScript의 동적 타이핑에 의해 발생된 것이다.</p>
<pre><code class="language-jsx">// JavaScript
function sum(a, b) {
  return a + b;
}

sum(&#39;x&#39;, &#39;y&#39;); // &#39;xy&#39;</code></pre>
<br>

<p>그럼 정적 타입핑은 왜 좋은 것일까?
우선 첫째, 컴파일 단계에서 오류를 잡아낼 수 있다.
그리고 둘째, 개발자의 의도를 명확하게 하여, 예측할 수 있게하고 디버깅을 쉽게 한다.</p>
<pre><code class="language-tsx">// TypeScript
function sum(a: number, b: number) {
  return a + b;
}

sum(&#39;x&#39;, &#39;y&#39;); // error</code></pre>
<br>

<h3 id="2-도구의-지원⭐">(2) 도구의 지원⭐</h3>
<p>TypeScript를 사용하는 가장 큰 장점은 
IDE(통합개발환경)을 포함한 다양한 도구의 지원을 받을 수 있다는 것이다.</p>
<blockquote>
<p>💁🏻‍♀️ <strong>IDE(Integrated Development Environment)</strong></p>
</blockquote>
<ul>
<li>코딩, 디버그, 컴파일, 배포 등 프로그램 개발에 관련된 모든 작업을 
하나의 프로그램 안에서 처리하는 환경을 제공하는 소프트웨어</li>
<li>대표적인 IDE : VScode, Eclipse</li>
</ul>
<br>

<h3 id="3-강력한-객체지향-프로그래밍-지원">(3) 강력한 객체지향 프로그래밍 지원</h3>
<p>TypeScript는 <strong>인터페이스</strong>, <strong>제네릭</strong> 등과 같은 강력한 객체지향 프로그래밍 지원한다.</p>
<ul>
<li><strong>크고 복잡한 프로젝트의 코드</strong> 기반을 쉽게 구성할 수 있도록 해준다.<ul>
<li>JavaScript의 동적 타이핑으로 인해, 자료형 추적이 안되는 객체가 많으며
속성 변경 역시 너무나 쉬워 버그가 생길 가능성이 매우 높다.</li>
</ul>
</li>
<li>Java, C# 등의 클래스 기반 객체지향 언어에 익숙한 개발자가 
자바스크립트 <strong>프로젝트를 수행하는 데 진입 장벽</strong>을 낮추는 효과가 있다.</li>
</ul>
<br>

<h3 id="4-최신-문법-지원">(4) 최신 문법 지원</h3>
<ul>
<li>브라우저<ul>
<li>ES5는 컴파일러 등의 개발환경 구축 없이 바로 사용할 수 있다.</li>
<li>하지만 ES6는 완전히 지원하지 않고 있다. (Babel 써야함)</li>
</ul>
</li>
<li>TypeScript<ul>
<li>개발환경 구축이 까다롭다는 점이 있지만,</li>
<li>최신 문법을 컴파일러 없이 사용 가능한걸요?</li>
</ul>
</li>
</ul>
<p><br><br></p>
<h2 id="5-장점이-있으면-단점도-있기-마련">5. 장점이 있으면 단점도 있기 마련!</h2>
<hr>
<h3 id="1-개발환경-구축의-까다롭다">(1) 개발환경 구축의 까다롭다.</h3>
<ul>
<li>JavaScript엔진에서 실행되기 때문에 기본적으로 설치해야 하는 모듈 있고,</li>
<li>컴파일을 위한 옵션도 설정해야 한다.
<em><del>최근에 개발환경 구축부터 해보고있는데 진짜..ㅎ쉽지않네..?</del></em></li>
</ul>
<br>

<h3 id="2-가독성이-떨어진다">(2) 가독성이 떨어진다.</h3>
<ul>
<li>JavaScript와 비교했을 때 확연히 가독성이 떨어지는 것을 알 수 있다.</li>
<li>코드의 길이 역시 길어진다.
<em><del>아무래도 타입을 일일이 지정해주어야하다보니 가독성이 떨어지더라😥</del></em></li>
</ul>
<br>

<h3 id="3-javascript에서-생기는-오류를-피할-수-없다">(3) JavaScript에서 생기는 오류를 피할 수 없다.</h3>
<ul>
<li>Type에러 이외의 에러는 계속 발생할 수 있다.</li>
</ul>
<p><br><br></p>
<h2 id="6-정리">6. 정리</h2>
<hr>
<blockquote>
<p>💁🏻‍♀️ <strong>그래서 TypeScript를 왜 쓰는데요?</strong></p>
</blockquote>
<ol>
<li>정적 타입을 지원<ul>
<li>컴파일 단계에서 오류 잡아낼 수 있음</li>
<li>개발자의 의도를 명확하게 하여, 예측할 수 있게하고 디버깅을 쉽게 한다.</li>
</ul>
</li>
<li>VSCode와 같은 IDE(통합개발환경)을 포함한 다양한 도구의 지원</li>
<li>interface, generic과 같이 객체지향 프로그래밍을 지원</li>
<li>최신문법을 별도의 컴파일러(babel 등) 없이 사용 가능</li>
</ol>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/1787becc-a14c-4666-a214-7c0a8dc4f29d/image.png" alt=""></p>
<p><br><br></p>
<h2 id="참고">참고</h2>
<hr>
<p>이 글은 아래의 글을 바탕으로 공부하며 개인적으로 정리한 글입니다.
이미지에 대한 출처는 아래의 포스팅에 있습니다.</p>
<ul>
<li><a href="https://poiemaweb.com/typescript-introduction">TypeScript - Intro &amp; Install | PoiemaWeb</a></li>
<li><a href="https://imraccoon-developer.tistory.com/11">TypeScript, 왜 써야되나?? (feat. 장단점)</a></li>
<li><a href="https://zdnet.co.kr/view/?no=20170413085316">MS 타입스크립트, 구글 사내 표준 언어 되다</a></li>
<li><a href="https://sangseophwang.tistory.com/101">012_정적 타입 언어와 동적 타입 언어, 그리고 TypeScript</a></li>
<li><a href="https://medium.com/@t2kterrykim/%EC%A0%95%EC%A0%81%ED%83%80%EC%9E%85-%EC%96%B8%EC%96%B4-statically-typed-vs-%EB%8F%99%EC%A0%81%ED%83%80%EC%9E%85-%EC%96%B8%EC%96%B4-dynamically-typed-725539255c56">정적타입 언어 (Statically typed) vs 동적타입 언어 (Dynamically typed)</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 이벤트 버블링]]></title>
            <link>https://velog.io/@hye_rin/JavaScript-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81</link>
            <guid>https://velog.io/@hye_rin/JavaScript-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%B2%84%EB%B8%94%EB%A7%81</guid>
            <pubDate>Thu, 08 Dec 2022 03:17:13 GMT</pubDate>
            <description><![CDATA[<h2 id="0-이벤트-관련-용어-정리">0. 이벤트 관련 용어 정리</h2>
<hr>
<p>이벤트 버블링에 대해 알기 이전에 용어를 정확히해두고 싶어 
흔히 쓰이는 이벤트 리스너와 이벤트 핸들러가 진정 의미하는 것은 무엇인지 대해 알아보았다.</p>
<p>이벤트 리스너와 이벤트 핸들러를 합쳐 이벤트 리스너 혹은 이벤트 핸들러라고 한다.
하지만, 이를 정확하게 말하자면 <span style="color:hotpink">이벤트 리스너에 등록된 콜백함수가 이벤트 핸들러</span>이다.</p>
<pre><code class="language-jsx">div.onClick(() =&gt; {});
div.addEventListener(&#39;click&#39;, () =&gt; {});</code></pre>
<table>
<thead>
<tr>
<th>이벤트</th>
<th>이벤트 속성 (이벤트 리스너)</th>
<th>이벤트 핸들러</th>
</tr>
</thead>
<tbody><tr>
<td><code>click</code></td>
<td><code>addEventListener()</code>, <code>onClick()</code></td>
<td><code>function(){}</code></td>
</tr>
</tbody></table>
<p><br><br></p>
<h2 id="1-이벤트-핸들러의-호출-과정">1. 이벤트 핸들러의 호출 과정</h2>
<hr>
<blockquote>
<ol>
<li>⬇ 하위 요소에 이벤트 전파 <strong>캡처링</strong></li>
<li>💌 타깃 요소에 이벤트 전달 </li>
<li>⬆ 상위 요소로 다시 이벤트 전파 <strong>버블링</strong></li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/2b9f5cfa-531b-40f0-93a7-3b4b0cd9778a/image.png" alt=""></p>
<p><br><br></p>
<h2 id="2-이벤트-버블링-event-bubbling">2. 이벤트 버블링 (Event Bubbling)</h2>
<hr>
<blockquote>
<p>🧼 <strong>이벤트 버블링이란?</strong>
특정 요소에서 이벤트가 발생됐을 때, 해당 이벤트가 상위 요소들로 전달되어 가는 특성을 말한다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/7b866a82-bdd4-40de-8dd9-0dfc2cd1aa50/image.png" alt=""></p>
<br>

<h3 id="2-1-예시">2-1. 예시</h3>
<ul>
<li><code>document</code>객체를 만날 때까지, 각 요소에 할당된 <code>onClick</code>이 동작</li>
<li>이벤트 핸들러의 동작 순서는 다음과 같다. <code>p</code> &gt; <code>div</code> &gt; <code>form</code></li>
</ul>
<p>!codepen[hyerrin/embed/BaVvyVP?default-tab=html%2Cresult]</p>
<br>

<h3 id="2-2-왜-이벤트-버블링인가">2-2. 왜 이벤트 버블링인가?</h3>
<p>이벤트가 제일 깊은 곳의 요소에서부터 시작해 부모 요소를 거슬러 올라가며 이벤트가 발생하는 모양이 마치 물속 거품(bubble)과 같기 때문이다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/d360d618-4442-41ab-9481-df007b2ea397/image.png" alt=""></p>
<br>

<h3 id="2-3-eventtarget-과-eventcurrenttraget-의-차이점">2-3. <code>event.target</code> 과 <code>event.currentTraget</code> 의 차이점</h3>
<h4 id="타깃target-요소">타깃(target) 요소</h4>
<ul>
<li>이벤트가 발생한 가장 안쪽의 요소로, 내가 클릭한 바로 그 요소</li>
<li><code>event.target</code>을 통해 접근 가능하다.</li>
<li>버블링이 진행되어도 변하지 않는다.<br>


</li>
</ul>
<h4 id="eventcurrenttarget와-this"><code>event.currentTarget</code>와 <code>this</code></h4>
<ul>
<li><code>event.currentTarget</code>은 <code>this</code>와 같다.</li>
<li>왜냐? 메소드 내부의 this는 해당 메소드를 호출한 객체에 바인딩되기 때문이다.</li>
<li>다음의 예시를 통해 확인해볼 수 있었다.</li>
</ul>
<pre><code class="language-html">&lt;!--HTML--&gt;
&lt;form&gt;
      FORM
      &lt;div&gt;
        DIV
        &lt;p&gt;P&lt;/p&gt;
      &lt;/div&gt;
&lt;/form&gt;</code></pre>
<pre><code class="language-jsx">// JavaScript
function lalala(e) {
    console.dir(this); // div
      console.log(e) // PointerEvent{}
    console.log(e.target); // &lt;P&gt;P&lt;/P&gt;
    console.log(e.currentTarget); &lt;div&gt;...&lt;/div&gt;
    console.log(e.currentTarget === this); true
      }
const divTest = document.querySelector(&quot;div&quot;);
divTest.addEventListener(&quot;click&quot;, lalala);</code></pre>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/ca726cbe-0d3d-4e11-9874-da9576b92238/image.png" alt=""></p>
<br>

<h4 id="eventcurrenttarget"><code>event.currentTarget</code></h4>
<ul>
<li>this, 즉 eventCurrentTarget은 현재 요소로, 현재 실행 중인 핸들러가 할당된 요소를 참조한다.</li>
<li>아래의 이미지에서 form태그에만 onClick 핸들러가 있다고 했을 때, <code>event.target</code>과 <code>event.currentTarget</code>은 어떻게 다를까?<blockquote>
<ul>
<li><code>event.target</code> : form 안쪽에 내가 실제 클릭한 요소</li>
</ul>
</blockquote>
<ul>
<li><code>event.currentTarget</code> : form 요소</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/12c5fc87-3828-4c04-a553-23d10c99c213/image.png" alt=""></p>
<br>

<h3 id="2-4-버블링-중단시키기">2-4. 버블링 중단시키기</h3>
<pre><code class="language-javascript">event.stopPropagation()</code></pre>
<ul>
<li>이벤트 버블링을 막아야하는 경우는 거의 없다.</li>
<li>위 메소드로 버블링을 막게되면, 사람들이 페이지의 어느 부분을 클릭했는지에 대한 분석 시스템이 동작하지 못하게 된다.</li>
</ul>
<br>

<h3 id="2-5-주의">2-5. 주의</h3>
<p>거의 대부분의 이벤트는 버블링되지만, 몇몇 버블링이되지 않는 이벤트도 있다.
(예) <code>focus()</code></p>
<p><br><br></p>
<h2 id="3-이벤트-캡쳐-event-capture">3. 이벤트 캡쳐 (Event Capture)</h2>
<hr>
<blockquote>
<p>📸 이벤트 캡쳐란?</p>
</blockquote>
<ul>
<li>이벤트 버블링과 반대되는 방법</li>
<li>이벤트 핸들러 호출 과정의 캡처링 과정에서 이벤트를 잡아내는 방법</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/e784ae74-a506-4cde-8e1e-8887dd52bfd0/image.png" alt=""></p>
<br>

<h3 id="3-1-이벤트-핸들러-동작-과정">3-1. 이벤트 핸들러 동작 과정</h3>
<p><code>form</code>, <code>div</code>, <code>p</code> 태그에 모두 click 이벤트를 설정해놓았다고 했을 때, 어떤 순서로 동작하게 될까?</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/61164e75-6c6d-481b-ae5a-b9c8e08b3827/image.gif" alt=""></p>
<blockquote>
<ol>
<li><code>p</code> <strong>클릭</strong></li>
<li><code>HTML</code> → <code>BODY</code> → <code>FORM</code> → <code>DIV</code>  <strong>캡쳐링</strong></li>
<li><code>p</code> <strong>타깃요소에 이벤트 전달</strong></li>
<li><code>DIV</code> → <code>FORM</code> → <code>BODY</code> → <code>HTML</code> <strong>버블링</strong></li>
</ol>
</blockquote>
<br>

<h3 id="3-2-capture-옵션">3-2. capture 옵션</h3>
<ul>
<li><code>false</code> : default 값으로, 이벤트 핸들러가 버블링 단계에서 동작한다.</li>
<li><code>true</code> : 이벤트 핸들러가 캡처링 단계에서 동작한다.</li>
</ul>
<pre><code class="language-jsx">div.addEventListener(&#39;click&#39;, () =&gt; {}, { capture: true }); // (1)
div.addEventListener(&#39;click&#39;, () =&gt; {}, true); // (2)</code></pre>
<br>

<h3 id="3-3-버블링-vs-캡쳐링">3-3. 버블링 vs. 캡쳐링</h3>
<ul>
<li>캡쳐링 단계는 거의 쓰이지 않으며, 주로 버블링 단계의 이벤트만 다뤄진다.</li>
<li>특정 요소를 클릭했을때 해당 내용에 대해서는 그 요소가 가장 잘 알고있기 때문에</li>
<li>지역 사건이 일어났을 때 해당 지역의 담당이 먼저 처리해본뒤, 상위 기관으로 넘기는 것과 같은 원리이다.</li>
</ul>
<p><br><br></p>
<h2 id="4-이벤트-위임-event-delegation">4. 이벤트 위임 (Event Delegation)</h2>
<hr>
<blockquote>
<p>🎁** 이벤트 위임이란?**</p>
</blockquote>
<ul>
<li>이벤트 캡처링과 이벤트 버블링을 활용한 패턴</li>
<li><strong>하위 요소🧑🏻</strong>마다 이벤트를 등록하지 않고도 </li>
<li><em>하위 요소🧑🏻*</em>들의 공통된 <strong>부모 요소👵🏻</strong>에 이벤트를 등록하여  </li>
<li><em>하위 요소🧑🏻*</em>의 이벤트들을 관리하는 방식이다.</li>
</ul>
<br>

<h3 id="4-1-예시">4-1. 예시</h3>
<h4 id="1-이벤트-위임을-사용하지-않았을-때">1. 이벤트 위임을 사용하지 않았을 때</h4>
<pre><code class="language-html">&lt;!--HTML--&gt;
&lt;ul&gt;
    &lt;li&gt;1&lt;/li&gt;
    &lt;li&gt;2&lt;/li&gt;
    &lt;li&gt;3&lt;/li&gt;
    &lt;li&gt;4&lt;/li&gt;
    &lt;li&gt;5&lt;/li&gt;
    &lt;li&gt;6&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<pre><code class="language-jsx">// JavaScript
const li = document.querySelectorAll(&quot;li&quot;);

li.forEach((li) =&gt; {
    li.addEventListener(&quot;click&quot;, () =&gt; {
        li.classList.add(&quot;selected&quot;);
    });
});</code></pre>
<br>

<h4 id="2-이벤트-위임을-사용했을-때">2. 이벤트 위임을 사용했을 때</h4>
<pre><code class="language-jsx">// JavaScript
const ul = document.querySelector(&quot;ul&quot;);

ul.addEventListener(&quot;click&quot;, (event) =&gt; {
    if (event.target.tagName == &quot;LI&quot;) {
        event.target.classList.add(&quot;selected&quot;);
    }
});</code></pre>
<br>

<h3 id="4-2-이벤트-위임을-사용하면-좋은점">4-2. 이벤트 위임을 사용하면 좋은점</h3>
<p>여러 자식 요소에 모두 이벤트를 등록하는 것이 아닌, 
부모 요소 하나에 등록함으로써 관리하기 때문에</p>
<blockquote>
<ol>
<li>이벤트 핸들러의 관리가 수월하다.</li>
<li>하위 요소를 자유롭게 추가하고 삭제할 수 있다.</li>
</ol>
</blockquote>
<p><br><br></p>
<h2 id="정리">정리</h2>
<hr>
<blockquote>
<p>🧼 <strong>이벤트 버블링에 대해 설명해주세요!</strong></p>
</blockquote>
<ul>
<li>이벤트 버블링은 특정 요소에서 이벤트가 발생했을 때 해당 이벤트가 상위 요소들한테 차례로 전달되는 특성이다.</li>
<li>event.propagation() 메소드로 이러한 버블링 현상을 막을 수 있지만, 잘 사용되지 않는다.</li>
<li>하위요소 → 상위요소로 이벤트가 전파되는 것은 이벤트 버블링이며, 이와 반대로 상위요소 → 하위요소로 이벤트가 전파되는 것은 이벤트 캡처링이다.</li>
<li>이러한 이벤트 버블링, 캡쳐링 특성을 이용하여 하위요소마다 이벤트를 등록하지 않아도 공통된 상위요소에 이벤트를 등록해 관리할 수 있는 패턴을 이벤트 위임이라고 한다.</li>
</ul>
<p><br><br></p>
<h2 id="참고">참고</h2>
<hr>
<p>이 글은 아래의 글을 바탕으로 공부하며 개인적으로 정리한 글입니다.
이미지에 대한 출처는 모두 아래에 있는 포스팅에 있습니다.</p>
<ul>
<li><a href="https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/">이벤트 버블링, 이벤트 캡처 그리고 이벤트 위임까지</a></li>
<li><a href="https://ko.javascript.info/bubbling-and-capturing">버블링과 캡처링</a></li>
<li><a href="https://codedragon.tistory.com/5743">이벤트 처리 - 이벤트 핸들러(event handler), 이벤트 리스너(event listener), 이벤트 리스너 등록 방법, 이벤트 호출 순서</a></li>
<li><a href="https://yeoncoding.tistory.com/91">[JS] 자바스크립트 이벤트 위임( Event Delegation )</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] this]]></title>
            <link>https://velog.io/@hye_rin/JavaScript-this</link>
            <guid>https://velog.io/@hye_rin/JavaScript-this</guid>
            <pubDate>Thu, 08 Dec 2022 02:47:00 GMT</pubDate>
            <description><![CDATA[<h2 id="this">this</h2>
<hr>
<p>this는 JAVA에선 자신을 가르키거나 자신이 생성할 인스턴스를 가르키는 자기 참조 변수이다.
하지만, JavaScript에서의 this는 함수 호출 방식에따라 달라진다.</p>
<blockquote>
<p>💁🏻‍♀️ <strong>this란?</strong></p>
</blockquote>
<ul>
<li>JAVA<ul>
<li>자신이 속한 객체 또는 자신이 생성할 인스턴스를 가르키는 자기 참조 변수이다.</li>
</ul>
</li>
<li>JavaScript<ul>
<li>this는 기본적으로 <code>window</code>다.</li>
<li>함수 호출 방식에 따라 this가 가리키는 객체(this에 <strong>바인딩</strong>되는 객체)는 달라질 수 있다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>🎀 <strong>바인딩은 뭘까?</strong></p>
</blockquote>
<ul>
<li>바인딩은 this와 this가 가리킬 객체를 연결하는 것을 말한다.</li>
</ul>
<blockquote>
<p>❓ <strong>함수 호출 방식에 따라 this가 달라지는 이유</strong></p>
</blockquote>
<ul>
<li>this는 실행 컨텍스트가 생성(스코프체인, 변수 객체화, this바인딩)될 때 결정된다.</li>
<li>일반적으로 함수를 호출할 때 실행 컨텍스트가 생성되기 때문에, this는 함수를 호출할 때 결정된다고 할 수 있다.</li>
</ul>
<p><br><br></p>
<h2 id="함수의-호출-방식">함수의 호출 방식</h2>
<hr>
<blockquote>
<p>함수 호출 방식은 아래와 같이 4가지로 분류해 볼 수 있다.</p>
</blockquote>
<br>

<h3 id="1-함수-호출">(1) 함수 호출</h3>
<pre><code class="language-jsx">const foo = function() {
 console.dir(this);
}

foo(); // this는 window</code></pre>
<br>

<h3 id="2-메소드-호출">(2) 메소드 호출</h3>
<pre><code class="language-jsx">const foo = function() {
 console.dir(this);
}

const obj = {
    foo : foo
};

obj.foo(); // this는 obj</code></pre>
<br>

<h3 id="3-생성자-함수-호출">(3) 생성자 함수 호출</h3>
<blockquote>
<ul>
<li>JavaScript에서 모든 함수는 생성자 함수이기도 하다.</li>
</ul>
</blockquote>
<ul>
<li>함수 호출 시 new를 명시하면, 해당 함수(<code>instance</code>)는 객체를 반환하고, 생성자 함수(<code>foo</code>)내부에서 사용된 this는 반환된 객체(<code>instance</code>)를 가르키게 된다.</li>
</ul>
<pre><code class="language-jsx">const foo = function() {
 console.dir(this);
}

const instance = new foo(); // this는 instance</code></pre>
<br>

<h3 id="4-applycall--호출">(4) <code>apply</code>/<code>call</code>  호출</h3>
<pre><code class="language-jsx">const foo = function() {
 console.dir(this);
}

const bar = {
    name : &#39;bar&#39;
};

foo.apply(bar); // this는 bar
foo.call(bar); // this는 bar</code></pre>
<p><br><br></p>
<h2 id="1-함수-호출-1">1. 함수 호출</h2>
<hr>
<blockquote>
<ul>
<li>기본적으로 this는 전역객체(Global Object)에 바인딩된다.</li>
</ul>
</blockquote>
<ul>
<li>전역객체(Global Object)<ul>
<li>모든 객체의 유일한 최상위 객체</li>
<li>Browser-side(브라우저): <code>window</code>객체</li>
<li>Server-side(Node.js): <code>global</code>객체</li>
</ul>
</li>
</ul>
<br>

<h3 id="1-내부함수">(1) 내부함수</h3>
<p>전역함수는 물론 그 내부함수까지 전역객체에 바인딩된다.</p>
<pre><code class="language-jsx">function foo() {
  console.log(this); // this는 window
  function bar() {
    console.log(this); // this는 window
  }
  bar();
}
foo();</code></pre>
<br>

<h3 id="2-메소드의-내부함수">(2) 메소드의 내부함수</h3>
<p>메소드의 내부함수 역시 this는 전역객체에 바인딩된다.</p>
<blockquote>
<p>💁🏻‍♀️ <strong>메소드란?</strong></p>
</blockquote>
<ul>
<li>객체는 키(key)와 값(value)으로 구성된 프로퍼티(property)의 집합입니다.</li>
<li>이 프로퍼티의 값으로 함수가 올 수도 있는데, 이러한 프로퍼티를 메소드(method)라고 합니다.</li>
</ul>
<pre><code class="language-jsx">let value = 1;

let obj = {
  value: 100,
  foo: function() {
    console.log(this);  // this는 obj
    console.log(this.value); // this.value는 100
    function bar() {
      console.log(this); // this는 window
      console.log(this.value); // this.value는 1
    }
    bar();
  }
};

obj.foo();</code></pre>
<br>


<h3 id="3-콜백함수">(3) 콜백함수</h3>
<p>콜백함수도 this는 전역객체에 바인딩된다.</p>
<blockquote>
<p>💁🏻‍♀️ <strong>콜백함수란?</strong>
다른 함수의 인자로서 이용되는 함수</p>
</blockquote>
<pre><code class="language-jsx">let value = 1;

let obj = {
  value: 100,
  foo: function() {
    setTimeout(function() { // 콜백함수
      console.log(this);  // this는 window
      console.log(this.value); // this.value는 1
    }, 100);
  }
};

obj.foo();</code></pre>
<br>

<h3 id="4-내부함수의-this가-전역객체를-참조하는-것을-피하는-방법">(4) 내부함수의 <code>this</code>가 전역객체를 참조하는 것을 피하는 방법</h3>
<blockquote>
<ol>
<li>외부함수에서 외부함수가 가르키는 this를 변수에 담고, 내부함수에서 참조할 수 있도록하기</li>
<li>JavaScript가 제공하는 <code>apply</code>, <code>call</code>메소드 사용하기</li>
</ol>
</blockquote>
<pre><code class="language-jsx">let value = 1;

let obj = {
  value: 100,
  foo: function() {
    let that = this;  // this === obj

    console.log(this);  // obj
    console.log(this.value); // 100
    function bar() {
      console.log(this); // window
      console.log(this.value); // 1

      console.log(that); // obj
      console.log(that.value); // 100
    }
    bar();
  }
};

obj.foo();</code></pre>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/6c22e650-9ddc-4ede-9845-866c0ea2d25d/image.png" alt=""></p>
<p><br><br></p>
<h2 id="2-메소드-호출-1">2. 메소드 호출</h2>
<hr>
<h3 id="1-일반">(1) 일반</h3>
<p>메소드 내부의 this는 해당 메소드를 소유한 객체, 즉 해당 메소드를 호출한 객체에 바인딩된다.</p>
<pre><code class="language-jsx">let obj1 = {
  name: &#39;Lee&#39;,
  sayName: function() { // 메소드
    console.log(this.name); // this === obj1
  }
}

let obj2 = {
  name: &#39;Kim&#39;
}

obj2.sayName = obj1.sayName; 
// obj2에 sayName 생성
// let obj2 = {
//   name: &#39;Kim&#39;,
//   sayName: function() {
//     console.log(this.name); // this === obj2
//   }
// }

obj1.sayName(); // Lee
obj2.sayName(); // Kim</code></pre>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/34d9dbee-1a02-4dbb-862b-1adf0d33e4b2/image.png" alt=""></p>
<br>

<h3 id="2-일반-변형">(2) 일반 변형</h3>
<p>함수를 호출할 때, 호출하는 함수가 객체의 메서드인지 그냥 함수인지에 따라 this가 달라진다.</p>
<pre><code class="language-jsx">let obj1 = {
  sayName: function() { 
    console.log(this); 
  }
}

obj1.sayName(); // obj1

let newSayName = obj1.sayName;
newSayName(); // window</code></pre>
<br>

<h3 id="3-프로토타입-객체">(3) 프로토타입 객체</h3>
<p>프로토타입 객체 메소드 내부의 this 역시 일반 메소드와 마찬가지로 해당 메소드를 호출한 객체에 바인딩된다.</p>
<pre><code class="language-jsx">// 생성자 함수
function Person(name) {
  this.name = name;
}

Person.prototype.getName = function() {
  return this.name;
}

let me = new Person(&#39;Lee&#39;);
console.log(me.getName()); // Lee

Person.prototype.name = &#39;Kim&#39;;
console.log(Person.prototype.getName()); // Kim</code></pre>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/72df3f55-4998-487e-8f8e-7f96b563626a/image.png" alt=""></p>
<p><br><br></p>
<h2 id="3-생성자-함수-호출-1">3. 생성자 함수 호출</h2>
<hr>
<h3 id="1-생성자-함수의-역할">(1) 생성자 함수의 역할</h3>
<p>생성자 함수의 역할은 <code>객체를 생성하는 것</code>이다.</p>
<br>

<h3 id="2-생성자-함수를-동작하게-하는-법">(2) 생성자 함수를 동작하게 하는 법</h3>
<ul>
<li>기존 함수에 <code>new</code> 연산자를 불러 호출하기</li>
<li>생성자 함수명은 대문자로 작성해 일반함수와 생성자함수의 혼란을 방지하는 것이 좋다.</li>
<li><code>new</code> 연산자와 함께 생성자 함수를 호출하지 않으면 생성자 함수로 동작하지 않는다.</li>
<li>함수 me는 생성자 함수로 만들어진 instance이며, 이 경우 내부의 this는 instance 자신이 된다.</li>
</ul>
<pre><code class="language-jsx">// 생성자 함수
function Person(name) {
  this.name = name;
}

let me = new Person(&#39;Lee&#39;); // new 연산자 사용
console.log(me); // Person {name: &quot;Lee&quot;}

let you = Person(&#39;Kim&#39;); // new 연산자 사용안함
console.log(you); // undefined</code></pre>
<p><br><br></p>
<h2 id="4-applycall-호출">4. <code>apply</code>/<code>call</code> 호출</h2>
<hr>
<blockquote>
<ul>
<li>this 바인딩<ul>
<li>암묵적 this 바인딩 : 함수 호출 방식에 따라 결정됨</li>
<li>명시적 this 바인딩 : <code>apply</code>/<code>call</code> 메소드</li>
</ul>
</li>
</ul>
</blockquote>
<ul>
<li>this를 어떤 객체로 지정할 것인가를 명시적으로 정할 수 있다.</li>
<li>이 메서드들은 모든 함수 객체의 프로토타입 객체인 <code>Function.prototype</code> 객체의 메소드이다.</li>
</ul>
<br>

<h3 id="1-apply">(1) apply</h3>
<blockquote>
<p>💁🏻‍♀️ <strong>apply</strong> </p>
</blockquote>
<pre><code class="language-javascript">function.apply(thisArg, [argsArray])</code></pre>
<ul>
<li><code>thisArg</code> : 함수 내부의 this에 바인딩할 객체</li>
<li><code>[argsArray]</code> : 함수에 전달할 argument의 배열</li>
</ul>
<pre><code class="language-jsx">let Person = function (name1, name2) {
  this.name1 = name1;
    this.name2 = name2;
};

let foo = {};

Person.apply(foo, [&#39;name1&#39;, &#39;name2&#39;]);

console.log(foo); // { name1: &#39;name1&#39;; name2: &#39;name2&#39; }</code></pre>
<blockquote>
<p>🚀 <strong>실행 과정</strong></p>
</blockquote>
<ol>
<li><code>apply()</code>를 통해 Person 호출<ul>
<li><code>apply()</code>는 this를 특정 객체에 바인딩할 뿐이다.</li>
<li>본질적인 기능은 함수를 호출하는 것!</li>
</ul>
</li>
<li>this에 객체 foo를 바인딩함</li>
<li>Person 함수의 this는 foo 객체가 됨</li>
<li>Person 함수의 this에 바인딩된 foo 객체에 name 프로퍼티가 추가되고, 값이 할당됨</li>
</ol>
<br>

<h3 id="2-call">(2) call</h3>
<blockquote>
<p>💁🏻‍♀️ <strong>call</strong>
apply와 같은 기능으로, 그 모양만 다르다.</p>
</blockquote>
<pre><code class="language-jsx">Person.apply(foo, [&#39;name1&#39;, &#39;name2&#39;]);
Person.call(foo, &#39;name1&#39;, &#39;name2&#39;);</code></pre>
<pre><code class="language-jsx">let Person = function (name1, name2) {
  this.name1 = name1;
    this.name2 = name2;
};

let foo = {};

Person.call(foo, &#39;name1&#39;, &#39;name2&#39;);

console.log(foo); // { name1: &#39;name1&#39;; name2: &#39;name2&#39; }</code></pre>
<p><br><br></p>
<h2 id="정리">정리</h2>
<hr>
<blockquote>
<p>💁🏻‍♀️ <strong>this의 용법을 아는대로 설명해주세요.</strong></p>
</blockquote>
<ul>
<li>실행컨텍스트는 함수가 호출될 때 생성된다.</li>
<li>this는 함수의 실행컨텍스트가 생성될 때 결정된다.</li>
<li>그 이유는 함수가 호출될 때 함수 컨텍스트가 생성되기 때문이다.</li>
<li>함수의 호출 방법은 아래와 같이 크게 4가지이며, 이때마다 this가 가르키는 객체는 다르다.<ol>
<li>전역범위에서의 함수 호출 (window)</li>
<li>메소드 호출 (메소드가 속한 객체)</li>
<li>생성자 함수 호출 (인스턴스)</li>
<li>apply / call 호출 (this바인딩할 객체 설정)</li>
</ol>
</li>
</ul>
<p><br><br></p>
<h2 id="참고">참고</h2>
<hr>
<p>이 글은 아래의 글을 바탕으로 공부하며 개인적으로 정리한 글입니다.
이미지에 대한 출처는 모두 아래에 있는 포스팅에 있습니다.</p>
<ul>
<li><a href="https://poiemaweb.com/js-this">this | PoiemaWeb</a></li>
<li><a href="https://www.zerocho.com/category/JavaScript/post/5b0645cc7e3e36001bf676eb">ZeroCho Blog</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 실행 컨텍스트]]></title>
            <link>https://velog.io/@hye_rin/JavaScript-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@hye_rin/JavaScript-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Wed, 30 Nov 2022 08:51:14 GMT</pubDate>
            <description><![CDATA[<h2 id="📚-실행-컨텍스트란">📚 실행 컨텍스트란?</h2>
<p>JavaScript 코드가 실행되기 위한 변수객체(Variable Object), 스코프체인(Scope Chain), this와 같은 정보들을 담고 있는 객체를 실행컨텍스트라고 한다.</p>
<br>

<h2 id="1-종류">1. 종류</h2>
<p>실행 컨텍스트는 아래와 같이 2종류가 있다.</p>
<blockquote>
<h4 id="💁🏻♀️-실행-컨텍스트-종류">💁🏻‍♀️ 실행 컨텍스트 종류</h4>
</blockquote>
<ol>
<li>Global Execution Context (전역 실행 컨텍스트)<ul>
<li>JavaScript 엔진이 처음 코드 실행할 때 생성</li>
</ul>
</li>
<li>Function Execution Context (함수 실행 컨텍스트)<ul>
<li>함수가 호출될 때 생성</li>
</ul>
</li>
</ol>
<br> 

<h2 id="2-실행-컨텍스트와-콜스택">2. 실행 컨텍스트와 콜스택</h2>
<p>JavaScript 코드를 실행하면 전역 컨텍스트 및 함수 컨텍스트가 생성되고, 
이것은 콜스택이라는 구조에 쌓여 차례로 처리된다. </p>
<blockquote>
<h4 id="💁🏻♀️-콜스택-call-stack">💁🏻‍♀️ 콜스택 (Call Stack)</h4>
</blockquote>
<ul>
<li>코드가 실행되며 생성되는 실행 컨텍스트 (Execution Context)를 저장하는 자료구조</li>
<li>후입선출 방식으로 컨텍스트를 <code>push</code> / <code>pop</code>한다.</li>
</ul>
<p>아래의 코드는 다음의 이미지와 같이 생성된 컨텍스트를 콜스택에 쌓고(<code>push</code>), 실행이 종료되면 콜스택에서 제거한다(<code>pop</code>). (이미지 속 EC는 Execute Context로 실행 컨텍스트를 의미한다.)</p>
<pre><code class="language-jsx">var x = &#39;xxx&#39;

function foo () { 
  var y = &#39;yyy&#39;;

  function bar () {
    var z = &#39;zzz&#39;;
    console.log(x + y + z);
  }
  bar();
}

foo();</code></pre>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/a901a61c-9f83-44d6-a0ee-c116531959d9/image.png" alt=""></p>
<blockquote>
<h4 id="💁🏻♀️-실행-과정">💁🏻‍♀️ 실행 과정</h4>
</blockquote>
<ol>
<li>함수를 호출한다.</li>
<li>해당 함수의 실행 컨텍스트가 만들어진다.</li>
<li>함수가 <code>return</code>되어 끝난다.</li>
<li>해당 함수의 실행 컨텍스트는 스택에서 pop되고, 메모리에서 제거된다.</li>
</ol>
<p><br><br></p>
<h2 id="3-실행-컨텍스트의-구성">3. 실행 컨텍스트의 구성</h2>
<p>실행컨텍스는 물리적으로 객체 형태이며, 아래의 3가지 프로퍼티를 갖는다.</p>
<blockquote>
<h4 id="💁🏻♀️-실행-컨텍스트-구성요소">💁🏻‍♀️ 실행 컨텍스트 구성요소</h4>
</blockquote>
<ol>
<li>Variable Object (VO, 변수 객체)</li>
<li>Scope Chain</li>
<li>this Value</li>
</ol>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/63f771ed-63d6-46d0-b145-49aad4a9b8af/image.png" alt="실행컨텍스트 구조"></p>
<br>

<h3 id="3-1-variable-object-vo-변수-객체">3-1. Variable Object (VO, 변수 객체)</h3>
<p>변수 객체는 JavaScript 실행에 필요한 여러 정보를 담은 객체를 의미한다. 
변수객체에서는 다음과 같은 정보를 확인할 수 있다.</p>
<blockquote>
<h4 id="💁🏻♀️-변수객체-구성요소">💁🏻‍♀️ 변수객체 구성요소</h4>
</blockquote>
<ul>
<li>변수</li>
<li>매개변수(<code>parameter</code>)와 인수(<code>arguments</code>)</li>
<li>함수 선언 (함수 선언식만 <code>function(){}</code>)</li>
</ul>
<br>

<p>컨텍스트의 종류는 2가지로, 전역 컨텍스트와 함수 컨텍스트가 있다고 했다. 
이 두 컨텍스트가 가리키는 변수 객체는 서로 다르다.</p>
<blockquote>
<p>💁🏻‍♀️ <strong>전역 컨텍스트에서의 변수객체</strong></p>
</blockquote>
<ul>
<li>전역 객체(Global Object, GO)를 가리킨다.</li>
<li>전역 객체란 모든 전역 변수/함수를 포함하는 객체를 말한다.
<img src="https://velog.velcdn.com/images/hye_rin/post/091d209d-8a7d-47d8-8d7f-de273577d003/image.png" alt=""></li>
</ul>
<blockquote>
<p>💁🏻‍♀️ <strong>함수 컨텍스트에서의 변수객체</strong></p>
</blockquote>
<ul>
<li>활성 객체(Activation Object, AO)를 가리킨다.<ul>
<li>활성 객체란 해당 컨텍스트에서 실행에 필요한 여러 정보를 담은 객체를 말한다.</li>
</ul>
</li>
<li>arguments 객체<ul>
<li>활성 객체 속 arguments 객체는 해당 함수의 매개변수와 인수들의 정보를 배열의 형태로 담고 있다.
<img src="https://velog.velcdn.com/images/hye_rin/post/fd644770-193f-4ab5-be22-b664fc587ffe/image.png" alt=""></li>
</ul>
</li>
</ul>
<br>

<h3 id="3-2-scope-chain">3-2. Scope Chain</h3>
<p>스코프 체인은 전역 객체(Global Object) 또는 활성 객체(Activation Object)의 리스트이다.</p>
<p>현재 실행 컨텍스트의 활성 객체(Activation Object)를 시작으로 순차적으로 상위 컨텍스트의 활성객체를 가르키며, 최종적으로 전역 객체(Global Object)를 가리킨다.</p>
<p align="center"><img src="https://velog.velcdn.com/images/hye_rin/post/49bc0b7b-eb5b-46f8-9c65-09142177c1c8/image.png" width=60%></p>

<br>

<h3 id="3-3-this">3-3. this</h3>
<ul>
<li>전역 실행 컨텍스트(Global Execution Context)에서 this는 <code>window</code>다.</li>
<li>함수 실행 컨텍스트에서의 값은 this 함수가 호출되는 방식에 따라 다른데, 이에 대한 내용은 다음 포스팅 때 상세히 다뤄보고자 한다.</li>
</ul>
<p><br><br></p>
<h2 id="4-실행-컨텍스트-생성-과정">4. 실행 컨텍스트 생성 과정</h2>
<pre><code class="language-jsx">var x = &#39;xxx&#39;

function foo () { 
  var y = &#39;yyy&#39;;

  function bar () {
    var z = &#39;zzz&#39;;
    console.log(x + y + z);
  }
  bar();
}

foo();b</code></pre>
<h3 id="전역-컨텍스트-생성">전역 컨텍스트 생성</h3>
<p>전역 컨텍스트가 생성되어 실행 컨텍스트 스택에 쌓이는데,
<code>변수객체</code>, <code>Scope Chain</code>, <code>this</code>가 들어온다.</p>
<p align="center"><img src="https://velog.velcdn.com/images/hye_rin/post/00caafd1-bf2a-4673-9b6d-bc76a664c27f/image.png" width=60%></p>

<br>

<h3 id="스코프-체인-생성-및-초기화">스코프 체인 생성 및 초기화</h3>
<p>스코프 체인은 전역 객체를 참조하는 리스트가 된다.</p>
<p align="center"><img src="https://velog.velcdn.com/images/hye_rin/post/641d3bdf-de6c-4d83-a300-613acb25032b/image.png" width=60%></p>

<br>

<h3 id="변수-객체화variable-instntiation-실행">변수 객체화(Variable Instntiation) 실행</h3>
<p>변수 객체화란, 변수 객체(Variable Object)에 프로퍼티와 값을 추가하는 것을 의미한다.</p>
<p>변수 객체(Variable Object)에는 변수, 매개변수, 인수 정보, 함수 선언 추가하여 객체화한다. 아래의 이미지와 같이, 전역 컨텍스트가 가르키는 변수 객체는 전역 객체이다. 전역 객체에는 매개변수, 인수 정보(arguments) 등이 없다.</p>
<p align="center"><img src="https://velog.velcdn.com/images/hye_rin/post/1042d665-4571-48fa-b68f-6cad951a626d/image.png" width=80% /></p>

<p align="center"><img src="https://velog.velcdn.com/images/hye_rin/post/658e5ef8-af88-4ea8-84bb-a1ee499f0262/image.png" width=80% /></p>


<p>변수 객체화를 통해 생성된 함수 객체는 <code>[[scopes]]</code> 프로퍼티를 갖는다. 
이는 함수 객체만이 소유하는 내부 프로퍼티로, 함수 객체가 실행되는 환경이다. 생성된 함수 객체는 자신의 실행 환경(<strong>Lexical Enviroment</strong>)과 자신을 포함하는 외부 함수의 실행 환경과 전역 객체를 가리킨다.</p>
<p align="center"><img src="https://velog.velcdn.com/images/hye_rin/post/cdf0621e-68c7-41aa-8785-e97cc8d6dceb/image.png" width=50% /></p>

<blockquote>
<h4 id="💁🏻♀️-렉시컬-환경lexical-environment">💁🏻‍♀️ 렉시컬 환경(Lexical Environment)</h4>
</blockquote>
<ul>
<li>스크립트 전체, 실행중인 함수, 코드블록 등은 자신만의 렉시컬 환경을 갖는다.</li>
<li>렉시컬 환경은 환경레코드(Environment Record), 외부렉시컬 환경(Outer Environment)으로 구성된다.
<img src="https://velog.velcdn.com/images/hye_rin/post/fdef86af-2617-455d-aed3-cde340c08974/image.png" alt=""></li>
</ul>
<br>

<h3 id="this-value-결정">this value 결정</h3>
<p>이전까지 this는 전역 객체(window)를 카르키고 있었다.
하지만 this는 함수 호출 방식에 따라 바인딩되는 객체가 달라진다.
단, 전역 컨택스트의 경우 Variable Object, Scope Chain, this값은 항상 전역 객체(window)다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/ebda105b-f4b6-4241-b7a7-e3c19c28f69e/image.png" alt=""></p>
<p>지금까지 살펴본 전역 컨텍스트를 객체로 표현해보면 다음과 같다.</p>
<pre><code class="language-jsx">&#39;전역 컨텍스트&#39;: {
  전역변수객체: {
    arguments: null,
    variable: [{ x: &#39;xxx&#39; }, { foo: Function }],
  },
  scopeChain: [&#39;전역 변수객체&#39;],
  this: window,
}</code></pre>
<p><br><br></p>
<h3 id="전역-코드의-실행">전역 코드의 실행</h3>
<h3 id="변수-값의-할당">변수 값의 할당</h3>
<pre><code class="language-jsx">var x = &#39;xxx&#39;

function foo () { 
  var y = &#39;yyy&#39;;

  function bar () {
    var z = &#39;zzz&#39;;
    console.log(x + y + z);
  }
  bar();
}

foo();</code></pre>
<p>현재 실행 컨텍스트의 스코프 체인이 참조하고 있는 변수 객체(Variable Obejct)부터 검색한다. 전역 컨텍스트의 경우, 변수 객체(Variable Object)는 전역 객체(Global Object)이다.</p>
<p>변수명에 해당되는 프로퍼티가 발견되면 값(<code>xxx</code>)을 할당한다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/8366611f-9570-436b-87cf-8edf165a5b7f/image.png" alt=""></p>
<br>

<h3 id="함수-foo의-실행">함수 foo의 실행</h3>
<pre><code class="language-jsx">var x = &#39;xxx&#39;

function foo () { 
  var y = &#39;yyy&#39;;

  function bar () {
    var z = &#39;zzz&#39;;
    console.log(x + y + z);
  }
  bar();
}

foo();</code></pre>
<h3 id="새로운-함수-실행-컨텍스트-생성">새로운 함수 실행 컨텍스트 생성</h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/75e3c933-104f-4d73-b463-e925100ca2f8/image.png" alt=""></p>
<br>

<h3 id="스코프-체인-생성과-초기화">스코프 체인 생성과 초기화</h3>
<h4 id="1-활성-객체activation-object-생성-및-arguments-객체-초기화">(1) 활성 객체(Activation Object) 생성 및 arguments 객체 초기화</h4>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/b097a4ec-6b63-4448-a9eb-a0f695882a86/image.png" alt=""></p>
<br>

<h4 id="2-전역-컨텍스트의-scope-chain이-참조하고-있는-객체가-scope-chain에-push">(2) 전역 컨텍스트의 Scope Chain이 참조하고 있는 객체가 Scope Chain에 push</h4>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/def346f6-79be-4add-a51e-df05c627f941/image.png" alt=""></p>
<br>

<h4 id="3-변수-객체화variable-instantiation-실행">(3) 변수 객체화(Variable Instantiation) 실행</h4>
<p>활성 객체에 변수, 매개변수, 인수 정보(arguments), 함수 선언 추가하여 객체화한다.
<img src="https://velog.velcdn.com/images/hye_rin/post/ffc10a73-d71e-41cb-af69-746abca1d072/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/3cc611dd-4894-4ef9-9f92-289f920eeed0/image.png" alt=""></p>
<h4 id="4-this-value-결정">(4) this value 결정</h4>
<ul>
<li>this에 할당되는 값은 함수 호출 패턴에 의해 결정된다.</li>
<li>내부 함수의 경우, this의 value는 전역 객체이다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/29f412b4-a435-4024-ace8-054f45b7f7b5/image.png" alt=""></p>
<p><br><br></p>
<h3 id="foo-함수-코드의-실행">foo 함수 코드의 실행</h3>
<p>함수 foo의 코드 블록 내 구문이 실행된다.</p>
<pre><code class="language-jsx">var x = &#39;xxx&#39;

function foo () { 
  var y = &#39;yyy&#39;;

  function bar () {
    var z = &#39;zzz&#39;;
    console.log(x + y + z);
  }
  bar();
}

foo();</code></pre>
<ol>
<li>변수의 값을 할당한다.    <code>var y = &#39;yyy&#39;</code></li>
<li>함수 bar가 실행된다</li>
<li>함수 foo의 실행 과정과 동일한 (1) 스코프 체인 생성과 초기화, (2) 변수 객체화 실행, (3) this value 결정의 과정이 순차적으로 진행된다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/9c5fa923-c231-4edc-b961-3d2eef49093a/image.png" alt=""></p>
<br>

<h2 id="5-정리">5. 정리</h2>
<blockquote>
<ul>
<li>자바스크립트의 코드들이 실행되기 위환 환경이다.</li>
</ul>
</blockquote>
<ul>
<li>전역 컨텍스트와 함수 컨텍스트 2가지가 존재한다.</li>
<li>전역 컨텍스트 생성 후에 함수가 호출할 때마다 함수 컨텍스트가 생성된다.</li>
<li>컨텍스트 생성 시 <code>변수객체</code>, <code>스코프 체인</code>, <code>this</code>가 생성된다.</li>
<li>컨텍스트 생성 후 함수에 사용되는 변수들은 변수 객체 안에서 값을 찾고, 없다면 스코프 체인을 따라 올라가며 찾는다.</li>
<li>함수 실행이 마무리 되면 해당 컨텍스트는 사라지고, 페이지가 종료되면 전역 컨텍스트 사라진다.</li>
</ul>
<p><br><br></p>
<h2 id="📜-참고">📜 참고</h2>
<p>이 글은 아래의 글을 바탕으로 공부하며 개인적으로 정리한 글입니다. 
이미지에 대한 출처는 모두 아래에 있는 포스팅에 있습니다.</p>
<ul>
<li><a href="https://poiemaweb.com/js-execution-context">Execution Context | PoiemaWeb</a></li>
<li><a href="https://medium.com/sjk5766/call-stack%EA%B3%BC-execution-context-%EB%A5%BC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90-3c877072db79">Call Stack과 Execution Context 를 알아보자</a></li>
<li><a href="https://www.zerocho.com/category/JavaScript/post/5741d96d094da4986bc950a0">zerocho</a></li>
<li><a href="https://catsbi.oopy.io/c5a0a4fb-1084-4da4-b29f-be8d5137f629#bdff24c9-064d-4ebd-ac04-71062ad17a89">학습 목표와 범위</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[👩🏻‍🏫 클래스IOI 프로젝트 회고록]]></title>
            <link>https://velog.io/@hye_rin/%ED%81%B4%EB%9E%98%EC%8A%A4IOI-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@hye_rin/%ED%81%B4%EB%9E%98%EC%8A%A4IOI-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Tue, 29 Nov 2022 06:47:44 GMT</pubDate>
            <description><![CDATA[<h2 id="🚀-소개">🚀 소개</h2>
<p>2차 프로젝트는 <a href="https://class101.net/">클래스101</a>을 모티브로 진행했다. 클래스101은 내가 프로젝트 아이디어로 제시한 서비스였다. 다양한 정보를 제공함에도 UI가 직관적이고 깔끔해 가장 인상 깊었던 서비스였기에, 이런 서비스를 모티브로 프로젝트를 진행한다면 배울점 역시 많을 것이라는 생각이 컸다. </p>
<p>클래스101에서는 강의 수강 뿐만 아니라 스토어 상품을 구매할 수도 있고, 구독 시스템도 있다. 사용자가 크리에이터가 되어 강의를 등록할 수도 있다. 처음 생각했던 것보다도 하나하나 들여다보니 다양한 기능이 있어 처음 프로젝트를 기획해나갈 때 꽤 골치 아팠었다.</p>
<p>1차 프로젝트 때는 주로 상품을 담고 결제하는 흐름으로 프로젝트가 진행되었다. 그래서 2차 프로젝트에는 사용자가 상품(우리 프로젝트에서는 강의!)을 등록하고 수정할 수 있는 기능을 중점적으로 구현해내고자 했다.</p>
<blockquote>
<h4 id="📆-기간">📆 기간</h4>
<p>22.10.04 - 22.10.13</p>
</blockquote>
<blockquote>
<h4 id="👩🏻🔧-기술">👩🏻‍🔧 기술</h4>
<ul>
<li><strong>Front-end</strong>
<code>React</code> <code>styled-component</code>
  ◽ CRA(Create-React-App)을 통한 리액트 개발 환경 세팅
  ◽ 함수형 컴포넌트 사용
  ◽ ESLint, Prettier 설정<br>
</li>
</ul>
</blockquote>
<ul>
<li><strong>Back-end</strong>
<code>Node.js</code>, <code>Express.js</code>, <code>MySQL</code><br></li>
<li><strong>Business Tool</strong>
<code>Slack</code>, <code>Trello</code>, <code>Notion</code></li>
</ul>
<blockquote>
<h4 id="🔗-github-link">🔗 Github Link</h4>
</blockquote>
<ul>
<li><strong>기존</strong> : <a href="https://github.com/HyeRrin/37-2nd-IOI-frontend">Github Repository</a></li>
<li><strong>개인적인 리팩토링 후</strong> : <a href="https://github.com/HyeRrin/ClassIOI">Github Repository</a></li>
</ul>
<p><br><br></p>
<h2 id="📝-일정-관리">📝 일정 관리</h2>
<p>일정 관리는 1차 프로젝트 때와 마찬가지로 <code>Trello</code>(트렐로)를 사용했다. 가장 처음 했던 일은 각자 맡은 기능을 정리한 티켓들을 Backlog칸에 옮겨두는 것이었다. 프로젝트 시작 전, 빼곡한 Backlog칸을 보면 가슴이 웅장해진닷,,,</p>
<p>매일 10~11시 사이에 Daily StandUp Meeting을 빠짐없이 진행했다. 고정된 시간에 다 같이 모여 프로젝트 진행상황이나 예정된 상황을 공유하고 하루 일정을 시작해서인지 티켓 상태 업데이트가 비교적 잘 이루어졌던 것 같다.</p>
<p>티켓이 무지막지하게 많아지는 것을 방지하고자 세부 기능은 티켓 내부의 체크박스로 대신했다. 티켓을 한눈에 파악하기에 좋았던 것 같다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/b8bfe174-0bed-4142-98aa-ec133be2b924/image.png" alt=""></p>
<p><br><br></p>
<h2 id="✨-주요-구현-기능">✨ 주요 구현 기능</h2>
<blockquote>
<p>나는 메인페이지와 구독신청페이지를 담당했다.</p>
</blockquote>
<p><strong>1. 소셜 로그인</strong></p>
<ul>
<li>카카오톡 소셜 로그인</li>
</ul>
<p><strong><span style="color:#ff5600">2. 메인 페이지</span></strong> </p>
<ul>
<li><span style="color:#ff5600">nav, footer</span></span></li>
<li><span style="color:#ff5600">이미지 슬라이드</span></li>
<li><span style="color:#ff5600">다중모달</span></li>
<li><span style="color:#ff5600">카테고리 필터링 및 정렬</span></li>
<li><span style="color:#ff5600">페이지네이션</span></li>
<li><span style="color:#ff5600">찜하기</span></li>
</ul>
<p><strong>3. 상세 페이지</strong></p>
<ul>
<li>상세 이미지 미리보기</li>
<li>리뷰 등록, 삭제</li>
<li>링크 복사</li>
<li>찜하기</li>
</ul>
<p><strong>4. 크리에이터 센터 페이지</strong></p>
<ul>
<li>클래스 등록</li>
<li>강의 등록, 수정, 삭제</li>
</ul>
<p><strong>5. 강의 영상 페이지</strong></p>
<ul>
<li>비디오 재생 및 선택하기</li>
</ul>
<p><strong><span style="color:#ff5600">6. 구독 신청 페이지</span></strong></p>
<ul>
<li>레이아웃</li>
</ul>
<p><strong>7. 결제 페이지</strong></p>
<ul>
<li>레이아웃</li>
</ul>
<p><strong>8. 찜목록 페이지</strong></p>
<ul>
<li>찜목록 슬라이드</li>
</ul>
<p><br><br></p>
<h2 id="💁🏻♀️-내가-구현한-기능">💁🏻‍♀️ 내가 구현한 기능</h2>
<h3 id="span-stylecolorff56001-nav-footer-span"><span style="color:#ff5600">1. nav, footer </span></h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/111e4c05-99e3-4bb0-919c-dd5ba0fcda7c/image.gif" alt=""></p>
<p><strong><span style="color:#ff5600">[ react-icons의 편리함 ]</span></strong>
상단바에는 <code>검색</code>, <code>프로필</code>, <code>좋아요</code>와 같은 다양한 아이콘들이 있는 것을 볼 수 있다. 이전까지는 이미지 파일을 프로젝트 폴더 내부에 저장해 사용해왔었다. 하지만 프로젝트 내부에 여러 아이콘 파일들이 담기는 것이 불필요하다는 생각을 항상 해왔었다. 그래서 이번 프로젝트를 진행하며 처음 <code>react-icons</code>라는 리액트 라이브러리를 사용해보게 되었고 편리한 점이 많았다.</p>
<p><code>react-icons</code>를 설치하면 아이콘을 사용하고자 하는 파일에 <code>import</code>하여 손쉽게 적용해볼 수 있다. 또한, 다른 스타일(색상, 크기 등)을 적용하고 싶다면 className을 부여하여 지정해주면 된다, 색상을 내 마음대로 바꾸기 힘든 이미지 파일보다 그때그때 커스텀하기 좋았다.
<br /></p>
<p><strong><span style="color:#ff5600">[ 상수데이터의 분리 ]</span></strong>
Footer 속 회사와 관련된 정보를 상수 데이터로  만들어 따로 파일을 분리해주었다. 이를 통해 상수데이터가 너무 길어져 가독성을 해치거나, 해당 상수데이터가 재사용되는 경우 따로 파일을 분리하면 좋다는 것을 알 수 있었다. </p>
<p>상수 데이터를 여러개의 파일로 나눠 관리할 필요없이, <code>named Export</code>로 한 파일 내에서 여러개의 변수를 내보낼 수 있는 방법에 대해 배울 수 있었다.</p>
<pre><code class="language-jsx">// Footer.jsx
import { INFO_LIST, SOCIAL_LIST } from &#39;./infoData&#39;;</code></pre>
<pre><code class="language-jsx">// infoData.jsx
export const INFO_LIST = [
  {
    id: &#39;0&#39;,
    title: &#39;이용약관&#39;,
    url: &#39;#&#39;,
  }, 
  // 이후 생략
]
export const SOCIAL_LIST = [
  {
    id: &#39;0&#39;,
    title: &#39;IOI Korea&#39;,
    url: &#39;#&#39;,
  },
  // 이후 생략
]</code></pre>
<p><br><br></p>
<h3 id="span-stylecolorff56002-이미지-슬라이드-span"><span style="color:#ff5600">2. 이미지 슬라이드 </span></h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/500c6a94-e9ad-4a3f-ba99-f01cb2242c7f/image.gif" alt=""></p>
<p><strong><span style="color:#ff5600">[ react-slick을 사용한 캐러셀 구현 ]</span></strong>
이미지 슬라이더보다 캐러셀이라고 많이 불리는 것을 보고 캐러셀의 의미가 가장 먼저 궁금했었다. 캐러셀은 회전목마라는 뜻이 있다고 한다. 회전목마처럼 일련의 콘텐츠들이 순환하는 슬라이더를 말하는 것임을 알 수 있었다.</p>
<p>이미지 슬라이드는 <a href="https://velog.io/@hye_rin/%EB%82%98%EB%A7%8C%EC%9D%98-%EC%9E%90%EA%B8%B0%EC%86%8C%EA%B0%9C-%EC%9B%B9%ED%8E%98%EC%9D%B4%EC%A7%80">자기소개 웹페이지</a>를 만들 때, <code>Vanilla JavaScript</code>로 구현한 적이 있다. 여러개의 이미지를 가로로 쭉 붙여서 가로 이미지의 크기만큼 위치를 이동시켜주어야만 했다. 하지만, 라이브러리를 사용하니 정말 간단하게 구현할 수 있었다. <code>react-slick</code>으로부터 import해온 Slider 컴포넌트 안에 여러 장의 이미지 리스트를 <code>map</code>으로 반복시켜주기만 하면된다. </p>
<p><code>Vanilla JavaScript</code>만으로 구현해본 적이 없다면 라이브러리의 편리함을 이렇게 크게 느끼지 못했을 것이다. 그러나 버튼 모양이라든지 스타일적인 부분을 내 입맛대로 커스텀하기에는 라이브러리를 사용하는 것보다 직접 기능을 모두 구현하는 것이 더 편리했던 것 같다. 역시 모든 것에는 장단점이 있기 마련이구만!</p>
<pre><code class="language-jsx">import Slider from &#39;react-slick&#39;;

&lt;StyledSlider {...settings}&gt;
    {CarouselImgData.map(image =&gt; (
        &lt;ImageBox key={image.id}&gt;
            &lt;Image src={image.url} alt=&quot;이미지 슬라이드&quot; /&gt;
        &lt;/ImageBox&gt;
    ))}
&lt;/StyledSlider&gt;

const StyledSlider = styled(Slider)`
  /* 생략 */
`</code></pre>
<p><br><br></p>
<h3 id="span-stylecolorff56003-다중-모달-속-카테고리-필터링-및-정렬span"><span style="color:#ff5600">3. 다중 모달 속 카테고리 필터링 및 정렬</span></h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/6cdd6d4d-b9c2-4352-b660-5c5be490168a/image.gif" alt=""></p>
<p><strong><span style="color:#ff5600">[ 공통된 모달의 컴포넌트화 ]</span></strong>
메인페이지에는 강의목록을 필터링 및 정렬 할 수 있다. Selectbox를 선택하면 그 밑에 Dropdown으로 목록이 나오는 구조가 아니라, 모달에 목록을 띄운다. 메인 카테고리, 서브 카테고리, 정렬, 이렇게 3가지 종류가 있으며 모달의 UI는 동일하다. 따라서 이 모달을 하나의 컴포넌트로 만들어 재사용해주면 된다고 생각했다. </p>
<p>하지만, 메인 카테고리에서 어떤 카테고리를 선택하느냐에 따라 서브 카테고리의 목록이 바뀌므로 이것을 해결하는 것이 어려웠다. 그럼에도 불구하고! 이는 모달 컴포넌트에 props로 사용자가 어떤 카테고리를 선택했는지 그 리스트를 넘겨줌으로써 해결할 수 있었다. 부모 컴포넌트와 자식 컴포넌트간의 props를 넘겨주며 코드의 중복을 줄이는 것의 중요성을 깨달았다. 구조는 다음과 같다.</p>
<pre><code class="language-jsx">// *Main 컴포넌트*
&lt;Container&gt;
  &lt;FilterAndSortBox /&gt; // 메인 카테고리
  &lt;FilterAndSortBox /&gt; // 서브 카테고리
  &lt;FilterAndSortBox /&gt; // 정렬
&lt;/Container&gt;

// *FilterAndSortBox 컴포넌트*
&lt;FilterAndSortBox&gt;
    &lt;CategoryWrap/&gt; // SelectBox
    &lt;FilterAndSortModal/&gt; // 모달
&lt;/FilterAndSortBox&gt;</code></pre>
<br>

<p><strong><span style="color:#ff5600">[ 카테고리 필터링 및 정렬 ]</span></strong>
강의 목록을 카테고리에 따라 필터링하고, 가격순으로 정렬하는 것은 <code>filter</code>혹은 <code>sort</code>를 통해 프론트에서도 해결 가능하다. 하지만, 서비스를 하고 있는 다양한 웹페이지를 보면 필터링을 하거나 정렬을 할 때마다 서버에 요청을 보내는 모습을 개발자 도구 Network탭에서 확인할 수 있었다. 페이지의 URL에 <code>https://test.com/?category=0123456&amp;sort=recommendOrder</code>에서도 정렬에 대한 정보가 추가되는 것을 쉽게 확인 할 수 있다.</p>
<p>필터링 및 정렬할 때마다 <code>searchParams</code>메서드를 통해 URL에 정보를 추가해주었다. 그리고, <code>searchParams</code>가 바뀐다는 것은 새로운 데이터를 불러와야한다는 것이기 때문에 <code>useEffect</code>의 의존성 배열에 <code>searchParams</code>를 추가해주었다.</p>
<pre><code class="language-jsx">// *높은 가격순 정렬*
const sortByHighPrice = e =&gt; {
    setBoxName(e.target.innerText); // 선택한 정렬을 selectbox 이름으로 바꾸기
    searchParams.set(&#39;sort&#39;, &#39;costHigh&#39;); // searchParams를 통해 sort=costHigh 추가하기
    setSearchParams(searchParams);
    setMainModalOpen(prev =&gt; !prev); // 정렬 선택 후 모달 닫기
};

// *메인 페이지*
const fetchURL = searchParams.toString();

useEffect(() =&gt; {
  fetch(`${BASE_URL}/main?${fetchURL}`)
    .then(res =&gt; res.json())
    .then(data =&gt; {
    setClassList(data.getFilter);
    });
}, [searchParams]);</code></pre>
<p>아래의 이미지를 보면, 가격 높은 순 정렬을 클릭했을 시 페이지 URL에 <code>sort=costHigh</code>가 추가되는 것을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/hye_rin/post/7fc01661-e354-433a-8cc9-253d90294302/image.PNG" alt=""></p>
<p><br><br></p>
<h3 id="span-stylecolorff56004-페이지네이션span"><span style="color:#ff5600">4. 페이지네이션</span></h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/e851f3f4-88d5-4e3e-830a-a9aa4cb8e3d8/image.png" alt=""></p>
<p>페이지네이션 역시 앞선 카테고리 필터링과 정렬과 마찬가지로 <code>searchParams</code>를 사용했다. 사용자는 페이지를 이동하게 되면 URL의 <code>offset</code>값이 변하는 것을 확인할 수 있다. 강의목록을 12개씩 보이도록 <code>limit</code>을 설정한다면, 첫 페이지의 <code>offset</code>은 0이되고 그 다음 페이지의 <code>offset</code>은 12, 또 그다음 페이지의 <code>offset</code>은 24가 된다.</p>
<pre><code class="language-jsx">// Main 페이지의 컴포넌트
const LIMIT = 12;
const movePage = pageNumber =&gt; {
    searchParams.set(&#39;limit&#39;, LIMIT);
    searchParams.set(&#39;offset&#39;, (pageNumber - 1) * LIMIT);
    setSearchParams(searchParams);
};

return (
    &lt;&gt;
        &lt;BtnContainer&gt;
            &lt;PageBtn onClick={() =&gt; movePage(1)}&gt;1&lt;/PageBtn&gt;
            &lt;PageBtn onClick={() =&gt; movePage(2)}&gt;2&lt;/PageBtn&gt;
            &lt;PageBtn onClick={() =&gt; movePage(3)}&gt;3&lt;/PageBtn&gt;
        &lt;/BtnContainer&gt;
    &lt;/&gt;
)</code></pre>
<p>필터링, 정렬, 페이지네이션과 같은 내용을 전부 다른 URL에 요청해야했다면 반복되는 코드도 많아 가독성이 떨어지고 비효율적이었을 것이다. <code>searchParams</code>를 통해 URL의 구성요소를 바꾸고, 이를  토대로 서버에 데이터를 요청하는 방법에 대해 배울 수 있어 좋았다. </p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/22b93280-4661-4454-b6b9-736fc1f65e96/image.PNG" alt=""></p>
<p><br><br></p>
<h3 id="span-stylecolorff56005-찜하기span"><span style="color:#ff5600">5. 찜하기</span></h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/799e4426-8291-46ad-90f7-8958a73d42db/image.gif" alt=""></p>
<p>가장 처음 강의 목록을 불러올 때, <code>access token</code>이 <code>LocalStorage</code>에 저장되어있는 상태, 즉 로그인 상태라면 사용자가 찜한 강의 목록에 하트가 채워진 상태❤여야 했다. 이를 위해 사용자가 찜한 강의목록을 받아왔다. 그리고 찜하기를 누를 때마다 어떤 강의 목록을 찜하고, 찜을 삭제했는지 서버에 <code>POST</code> 및 <code>DELETE</code>요청을 보내 마이페이지 찜하기 목록에서 찜한 강의 목록을 확인할 수 있게 만들어주었다.</p>
<p><br><br></p>
<h2 id="📋-프로젝트-발표">📋 프로젝트 발표</h2>
<p>2차 프로젝트 발표날은 절대 잊을 수 없는 하루였기 때문에 꼭 기록으로 남겨두고 싶었다. </p>
<p>2차 프로젝트 발표 당일인 새벽 2시가 되어서야 프로젝트가 마무리됐다. 프로젝트를 마무리짓기 바빠서 발표는 생각할 겨를도 없었다. 그래서 발표 자료는 물론이고 발표 준비가 하나도 되어있지 않은 상황이었던 것. 그런데 그런 발표를 해야하는 발표자는 누구...? PM은 누구?</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/89c12548-bb89-4ddb-830b-07e7a7c5df17/image.png" alt=""></p>
<p>당장 오전 10시가 발표였다. 2주간 밤낮없이 달려온 마지막날이었기에 체력적으로 쉽지 않은 상황이었다. 하지만 절대 어영부영 대충하고 싶지 않았다. 어떤 일을 하든 유종의 미를 거두어야한다는 생각을 항상 가지고 있었기에 잠도 안왔다. 하루정도 안자도 괜찮다는 생각으로 <a href="https://drive.google.com/file/d/1kbkE_-foIdHYcaIoFai2KQTHwdEGLpTY/view?usp=sharing">발표 자료</a>를 만들고 발표 연습까지 끝마쳤다. 준비한게 있으니 두려울게 없었고, 그렇게 발표는 성황리에 마무리되었다.👏🏻👏🏻👏🏻
(<em><del>1차 때는 발표하는 사진 찍어주시던뎅..2차 때는 없당..괜시리 섭섭..</del></em>)</p>
<p>이 날의 경험은 내게 근거있는 자신감을 만들어주었다. 나는 어떤 상황이든 책임감 있게 내가 맡은 일을 해내는, 그것도 잘 해내는 사람이라는 근거를 만들어주었고 이로 인해 자신감이 생겼다. 그래서인지 짧다면 짧았고 길다면 긴 2주간의 2차 프로젝트는 내게 정말 뜻깊은 시간이었다.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/05d2dc39-ac86-427b-8f83-3edff73a3800/image.png" alt=""></p>
<p><br><br></p>
<h2 id="👏🏻-마치며">👏🏻 마치며</h2>
<p>다가오는 기업협업 일정으로 전체적인 분위기가 꽤 어수선했었다. 그럼에도 불구하고 우리 클래스IOI 팀은 분위기에 휩쓸리지 않고 끝까지 집중했고, 목표로 한 기능을 구현해낼 수 있었다. <code>행동의 가치는 그 행동을 끝까지 이루는데 있다</code>는 말이 있다. 처음에 누구나 열심히 한다. 문제집의 앞부분만 너덜너덜한 것처럼 말이다. 이번 프로젝트는 팀원 모두가 마지막까지 각자의 자리에서 최선을 다함으로써 그 가치를 증명해냈단 생각이 들어 뿌듯함이 크다. </p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/866e2e5a-291f-459f-942e-53f9ff799915/image.jpg" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Web] 브라우저 렌더링 과정]]></title>
            <link>https://velog.io/@hye_rin/Web-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%A0%8C%EB%8D%94%EB%A7%81-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@hye_rin/Web-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%A0%8C%EB%8D%94%EB%A7%81-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Wed, 23 Nov 2022 06:08:58 GMT</pubDate>
            <description><![CDATA[<h2 id="1-브라우저-렌더링">1. 브라우저 렌더링?</h2>
<hr>
<ul>
<li>브라우저 렌더링이란, 브라우저 주소창에 주소 입력 시 해당 페이지가 화면에 그려지는 과정을 이야기합니다.</li>
<li>브라우저는 유저가 선택한 자원(페이지, 이미지, 비디오)를 서버로 부터 받아와 렌더링 과정을 통해 유저에게 보여주죠.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/fdbebf85-74d3-440a-8baf-4a8467755840/image.png" alt=""></p>
<p><br /><br /></p>
<h2 id="2-브라우저-기본-구조">2. 브라우저 기본 구조</h2>
<hr>
<ul>
<li>브라우저는 아래와 같이 7개의 구성 요소로 이루어져 있습니다.</li>
<li>이 7개의 구성 요소 중에서도 <strong><span style="color:violet">렌더링 엔진</span></strong>이 HTML, CSS 문서를 브라우저가 이해할 수 있는 구조로 변환하여 화면에 그려주는 역할을 합니다.</li>
</ul>
<blockquote>
<ol>
<li>사용자 인터페이스</li>
<li>브라우저 엔진</li>
<li><strong><span style="color:violet">렌더링 엔진</span></strong> : 요청 받은 내용을 브라우저 화면에 표시 (HTML, XML문서, 이미지)<ul>
<li>Safari, Chrome : 웹킷(Webkit) 엔진</li>
<li>Firefox : 모질라의 게코(Gecko) 엔진</li>
</ul>
</li>
<li>통신</li>
<li>UI 백엔드</li>
<li>자바스크립트 해석기</li>
<li>자료 저장소</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/84ea293e-866a-4ef7-a9cd-46df8c4ebf59/image.png" alt=""></p>
<p style="color:gray;text-align:center">출처 | 네이버D2, 브라우저의 주요 구성 요소</p>


<p><br /><br /></p>
<h2 id="3-브라우저-렌더링-과정-⭐">3. 브라우저 렌더링 과정 ⭐</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/ab1fc921-63ea-45f6-af16-d210fbf98535/image.png" alt=""></p>
<blockquote>
<ol>
<li><strong><span style="color:violet"><code>파싱</code></span></strong> HTML 파일과 CSS 파일을 파싱해서 각각 Tree를 만든다. </li>
<li><strong><span style="color:violet"><code>결합</code></span></strong> 두 Tree를 결합하여 Rendering Tree를 만든다. </li>
<li><strong><span style="color:violet"><code>배치</code></span></strong> Rendering Tree에서 각 노드가 화면의 정확한 위치에 표시될 수 있도록 한다. </li>
<li><strong><span style="color:violet"><code>그리기</code></span></strong> 각 노드를 화면상의 실제 픽셀로 변환하고, 레이어를 만들고 합성하여 실제 화면에 나타낸다. </li>
</ol>
</blockquote>
<p><br /><br /></p>
<h2 id="4-파싱">4. 파싱</h2>
<hr>
<h3 id="1-파싱parsing이란">(1) 파싱(parsing)이란?</h3>
<p>앞서 HTML 문서와 CSS 문서가 HTML 파서와 CSS 파서를 통해 파싱되어 parse tree로 변환되는 과정이 있었죠. 여기서 파싱(parsing)이 무엇인지 궁금증이 생겨 알아본 결과!</p>
<blockquote>
<p>💁🏻‍♀️ <span style="backgroundColor:lightyellow;color:black">문서를 파싱한다</span>는 것은 <strong><span style="color:violet">브라우저가 코드를 이해하고 사용할 수 있는 구조로 변환</span></strong>하는 것을 뜻해요.</p>
</blockquote>
<br />

<h3 id="2-파싱-종류">(2) 파싱 종류</h3>
<p>파싱의 종류로는 크게 어휘 분석과 구문 분석이 있어요.</p>
<p>어휘 분석을 통해서는 자료를 토큰으로 분해하고, 구문 분석을 통해 언어의 구문 규칙에 따라 문서 구조를 분석함으로써 파싱 트리(parse tree)를 생성해요.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/bf6550f9-2de3-4a88-9881-77ab81082f0f/image.png" alt=""></p>
<p style="color:gray;text-align:center">출처 | 네이버D2, 문서 소스로부터 파싱 트리를 만드는 과정</p>

<br />

<h3 id="3-파싱-결과">(3) 파싱 결과</h3>
<p>파싱 결과는 파싱 트리, 즉 문서 구조를 나타내는 <strong><span style="color:violet">노드 트리(parse tree, syntax tree)</span></strong>에요.</p>
<p>HTML DOM을 예로 들자면, DOM은 노드(node)라고 불리는 계층적 단위에 정보를 저장하고 있죠. HTML DOM은 이러한 노드들을 정의하고, 그들 사이의 관계를 설명해 주는 역할을 합니다.</p>
<br />

<h3 id="4-dom">(4) DOM</h3>
<p>HTML 문서의 파싱을 통해 생성되는 DOM에 대해서 조금 더 알아볼게요.</p>
<p><strong><span style="color:violet">DOM이란</span></strong> <span style="backgroundColor:lightyellow;color:black">HTML 문서에 대한 인터페이스로, HTML 문서의 객체 기반 표현 방식</span>이에요. 🌳<span style="color:green">하나의 부모 줄기에 여러 개의 자식 나뭇가지, 또 각각의 나뭇가지는 잎들을 가질 수 있는 구조</span>🌳를 띄고 있죠.</p>
<p>주로 브라우저 뷰 포트(Viewport, 화면크기로 메뉴바나 탭영역을 제외한 순수 화면 영역)에 렌더링 시, 또는 JS에 의해 수정될 시에 사용돼요.</p>
<p>여기서 짚고 넘어갈 점! <span style="backgroundColor:lightyellow;color:black">DOM은 브라우저에서 보이는 것이 아니에요. 브라우저 뷰 포트에 보이는 것은 DOM과 CSSOM의 조합의 렌더 트리</span>랍니다.</p>
<br />


<h3 id="5-css-파싱">(5) CSS 파싱</h3>
<p>그렇다면 CSS 파싱은 어떻게 이루어지는걸까요?</p>
<p>CSS 파일은 <strong><span style="color:violet">스타일 시트 객체</span></strong>로 파싱됩니다. 각 객체는 <strong><span style="color:violet">CSS 규칙</span></strong>을 포함해요.
또한, CSS 규칙 객체는 <strong><span style="color:violet">선택자</span></strong>(div)와 <strong><span style="color:violet">선언 객체</span></strong>(margin, 10px) 그리고 CSS 문법과 일치하는 다른 객체를 포함해요.</p>
<pre><code class="language-css">div {
    margin: 10px;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/da1923e1-b383-4885-ba7a-1b8f9d099529/image.png" alt=""></p>
<p style="color:gray;text-align:center">출처 | 네이버D2, CSS 파싱</p>


<p><br /><br /></p>
<h2 id="참고">참고</h2>
<hr>
<p><a href="https://d2.naver.com/helloworld/59361">NAVER D2</a>
<a href="https://poiemaweb.com/js-browser">Javascript Environment | PoiemaWeb</a>
<a href="https://serzhul.io/JavaScript/38.%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EB%A0%8C%EB%8D%94%EB%A7%81-%EA%B3%BC%EC%A0%95/">38.브라우저의 렌더링 과정</a>
<a href="https://tecoble.techcourse.co.kr/post/2021-10-24-browser-rendering/">브라우저 렌더링 과정 이해하기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ 🍫 허쉬 프로젝트 회고록]]></title>
            <link>https://velog.io/@hye_rin/%ED%97%88%EC%89%AC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@hye_rin/%ED%97%88%EC%89%AC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Mon, 03 Oct 2022 12:06:09 GMT</pubDate>
            <description><![CDATA[<h2 id="🐾-들어가며">🐾 들어가며</h2>
<hr>
<p>지난주 금요일에 프로젝트 발표를 마친 🔥<strong>러쉬코리아 클론 프로젝트</strong>🔥에 대한 회고를 시작해보려고 해요. 저희 4팀은 <a href="https://www.lush.co.kr/?utm_source=google&amp;utm_medium=keyword_pc&amp;utm_campaign=main&amp;gclid=Cj0KCQjwyt-ZBhCNARIsAKH1177ujdhjXi5fLaAdhU9dGPO0cQwv82I0UtiFqV4sTqGn0VfAMQOBVAIaAtoxEALw_wcB">러쉬코리아</a>의 LUSH를 HUSH로 변경해 샤워용품이 아닌 디저트류를 판매하는 사이트를 만들었어요(저작권 절대 지켜👊🏻). 러쉬와 발음이 유사한 허쉬(Hershey)초콜릿에서 영감을 받았답니다! </p>
<p>이렇게 프론트와 백이 모여 제대로 프로젝트를 진행한 건 처음이었기에 여러 방면에서 제 자신에 대한 부족함을 많이 느꼈고 그래서 배울 점이 참 많았던 첫 프로젝트였어요. 협업 방식, 일정 관리, 리액트 렌더링, 통신 등.. 모든 면에서요! 이번 1차 프로젝트를 회고하며 개선해야할 부분에 대해 정리하고, 더 성장한 모습으로 2차 프로젝트를 시작해보려고 해요!</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/5cf134bf-694e-4f72-b2a3-c6ac4fb1c5a8/image.png" alt=""></p>
<br>

<h3 id="📆-작업-기간">📆 작업 기간</h3>
<p>2주가 이렇게 짧았던 적이 있었나 싶어요. 정말 눈깜짝할 사이에 2주가 지나있었어요. 레이아웃이나 기능 구현은 1주차에 거의 마무리가 됐었고, 그 이후로는 코드를 수정/개선하고 통신하는 데에 시간을 보냈어요.</p>
<blockquote>
<p>2주 (22년 09월 19일 ~ 22년 09월 29일)</p>
</blockquote>
<p><br><br></p>
<h3 id="🔨-기술-스택">🔨 기술 스택</h3>
<p>프론트엔드 4명(강루비, 김대호, 양석문, 주혜린), 백엔드 3명(김정훈, 정승렬, 정다영)이 함께 프로젝트를 진행했어요. </p>
<blockquote>
<h4 id="front-end">Front-end</h4>
<p><code>React</code>, <code>SASS</code>
    ◽ CRA(Create-React-App)을 통한 리액트 개발 환경 세팅
    ◽ 함수형 컴포넌트 사용
    ◽ ESLint, Prettier 설정</p>
</blockquote>
<h4 id="back-end">Back-end</h4>
<p><code>Node.js</code>, <code>Express.js</code>, <code>MySQL</code></p>
<h4 id="co-work">co-work</h4>
<p><a href="https://github.com/wecode-bootcamp-korea/37-1st-HUSH-frontend"><code>Github</code></a>, <code>Slack</code>(소통), <a href="https://trello.com/b/SqYg2cLN/hush"><code>Trello</code></a>(일정관리), <code>Notion</code>(회의록)</p>
<p><br><br></p>
<h3 id="✅-일정-관리">✅ 일정 관리</h3>
<p>일정 관리는 <code>Trello</code>를 사용했어요. <code>This sprint</code>에는 이번 주까지 해야할 일을, <code>In progress</code>는 지금 진행 중인 작업을, <code>In Review</code>는 PR을 올리고 리뷰를 받고 있는 작업을, <code>Done</code>은 리뷰까지 반영돼 merge완료된 작업을 올렸어요. 레이아웃 구현과 기능 구현은 다른 티켓으로 나누어 올려 구분지었답니다.</p>
<p>아쉬운 점이 있다면, 기능 구현하기에 급급해 업데이트된 내용을 반영하지 않은 날도 있다는 것이었어요. 지금이야 도착하면 팀원들이 가까이 모여 프로젝트를 진행하지만, 현업에 가면 재택을 하는 것과 같이 서로의 상황을 제대로 알 수 없을 수 있겠더라구요. 2차 프로젝트에는 매일 도착하자마자 <code>Trello</code>를 확인하고 업데이트/관리하는 것을 기본 중의 기본으로! 가져가고자 해요.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/f6173003-0796-4645-b655-6d04e6b37f64/image.png" alt=""></p>
<p><code>Trello</code>로 일정 관리를 하기는 하지만, 아날로그틱한 갬성으로 계획짜는 것을 좋아하는 저는 그 날 그 날 해아할 일이나 기억해야할 사항을 적어놓는데 플래너를 사용했어요. 하지만, 이런 플래너는 저만 알 수 있기 때문에 최대한 <code>Trello</code>에 더 디테일한 내용을 쓰고자 노력해야겠단 생각이 들어요. 
(노트에 떨어져 있는 자국은 코피 자국이었으면 좋았겠지만..커피 자국..☕코피 자국이 되는 그날까지..🏃🏻‍♀️)</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/92b4f3d4-8068-4b49-9404-b3ff989c0340/image.png" alt=""></p>
<p><br><br></p>
<h2 id="✨-주요-구현-기능">✨ 주요 구현 기능</h2>
<hr>
<blockquote>
<p>저희 팀 프론트는 페이지별로 나눠 담당했어요. 저는 <span style="color:rgb(18, 184, 134)">색으로 표시한 것</span>과 같이 회원가입, 로그인, 장바구니, 찜목록을 담당해 구현했답니다.</p>
</blockquote>
<p><strong><span style="color:rgb(18, 184, 134)">1. 회원가입, 로그인</span></strong></p>
<ul>
<li><span style="color:rgb(18, 184, 134)">이메일 중복 확인</span></li>
<li><span style="color:rgb(18, 184, 134)">비밀번호 유효성 검사</span></li>
</ul>
<p><strong>2. 메인 페이지</strong></p>
<ul>
<li>nav, footer</li>
<li>이미지 슬라이드</li>
<li>애니메이션 효과</li>
</ul>
<p><strong>3. 제품 페이지</strong></p>
<ul>
<li>카테고리탭 별 이동</li>
<li>페이지네이션</li>
<li>가격 필터링(높은 순, 낮은 순)</li>
</ul>
<p><strong>4. 상세 페이지</strong></p>
<ul>
<li>수량 조절</li>
<li>상품 후기 작성</li>
<li>메뉴탭 이동</li>
</ul>
<p><strong><span style="color:rgb(18, 184, 134)">5. 장바구니 페이지</span></strong></p>
<ul>
<li><span style="color:rgb(18, 184, 134)">장바구니 목록 불러오기</span></li>
<li><span style="color:rgb(18, 184, 134)">제품 단일 선택/전체 선택 주문</span></li>
<li><span style="color:rgb(18, 184, 134)">제품 단일 선택/전체 선택 삭제</span></li>
<li><span style="color:rgb(18, 184, 134)">수량 조절</span></li>
<li><span style="color:rgb(18, 184, 134)">제품 합계 금액</span></li>
</ul>
<p><strong><span style="color:rgb(18, 184, 134)">6. 찜 목록 페이지</strong></p>
<ul>
<li><span style="color:rgb(18, 184, 134)">찜 목록 불러오기</span></li>
<li><span style="color:rgb(18, 184, 134)">제품 단일 선택/전체 선택 삭제</span></li>
</ul>
<p><strong>7. 결제 페이지</strong></p>
<ul>
<li>결제 상품 불러오기</li>
<li>주문자 정보 불러오기</li>
<li>배송 메시지 저장</li>
</ul>
<p><br><br></p>
<h2 id="👩🏻-내가-맡은-기능">👩🏻 내가 맡은 기능</h2>
<hr>
<h3 id="1-회원가입">1. 회원가입</h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/cabfd541-1ae3-4785-9ff6-a2d1ebbebb22/image.gif" alt=""></p>
<p>회원가입 시, 이미 회원가입 된 이메일은 사용할 수 없도록 중복 확인 기능을 넣어주었어요. 중복 확인을 하지 않고 <code>회원가입</code> 버튼을 누르면 <code>중복 확인</code>을 하라는 alert창이 뜨도록 만들어주었답니다. </p>
<br>

<blockquote>
<h4 id="잠깐🖐🏻-기억에-남는-코드가-있다면">잠깐!🖐🏻 기억에 남는 코드가 있다면?</h4>
<p>중복확인을 했는지, 안했는지를 <code>isCheckEmail</code>이라는 state로 관리해주었어요. 그래서 중복 확인하는 API요청에서 성공 메시지를 받으면 <code>isCheckEmail</code>을 true로 바꿔주었고, 그렇지 않으면 false로 바꿔주었죠.</p>
</blockquote>
<pre><code class="language-jsx">const [isCheckEmail, setIsCheckEmail] = useState(false);</code></pre>
<p>그리고 최종적으로 회원가입 form을 제출할 때 <code>isCheckEmail</code>이 true일 때는 회원가입 데이터를 서버에 보냈고, 그렇지 않을 경우에는 alert를 띄웠어요. 아래와 같이 <code>if...else</code>문을 사용했죠.</p>
<pre><code class="language-jsx">const submitForm = e =&gt; {
  if (isCheckEmail) {
    fetch(&#39;http://000.000.000.000:3001/user/signup&#39;, {
        // 생략  
      });
  } else {
    alert(&#39;이메일 중복을 확인해주세요.&#39;);
  }
};</code></pre>
<p>코드 리뷰를 받으며 <code>if...else</code>문보다 직관적으로 작성할 수 있는 법을 알게 되었어요. 이메일 중복 확인에 실패하면 바로 alert를 실행하고 return함으로써 함수를 끝내버리는 방법이었죠! 이메일이 중복된 경우라면 쓸데없이 if문의 긴 코드를 읽어내려갈 필요가 없으니 미리 끝내버리는 효율적인 코드라고 생각했어요.</p>
<pre><code class="language-jsx">const submitForm = e =&gt; {
  if (!isCheckEmail) {
    alert(&#39;이메일 중복을 확인해주세요.&#39;);
    return;
  }
  fetch(&#39;http://000.000.000.000:3001/user/signup&#39;, {
      // 생략  
  });
};</code></pre>
<p><br><br></p>
<h3 id="2-로그인">2. 로그인</h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/b84f723e-2652-400c-b445-2ec3e98e0333/image.gif" alt=""></p>
<p>이메일이나 비밀번호를 다르게 작성했을 때, 그에 맞는 alert창을 띄워주었어요. </p>
<br>

<blockquote>
<h4 id="잠깐🖐🏻-기억에-남는-코드가-있다면-1">잠깐!🖐🏻 기억에 남는 코드가 있다면?</h4>
<p>요청에 대한 응답 메시지에 따라 access token을 저장하거나 alert창을 띄우게 만들고자 했어요.  <code>if...else if</code>로 나누어주면 되겠다고 생각해 아래와 같이 나누어주었죠.</p>
</blockquote>
<pre><code class="language-jsx">if (data.message === &#39;ACCESS_SUCCESS&#39;) {
  localStorage.setItem(&#39;accessToken&#39;, data.accessToken);
  alert(&#39;로그인 성공&#39;);
} else if (data.message === &#39;WRONG_EMAIL&#39;) {
  alert(&#39;이메일 다시&#39;);
} else if (data.message === &#39;WRONG_PASSWORD&#39;) {
  alert(&#39;비밀번호 다시&#39;);
}</code></pre>
<p>하지만, 아까 기억에 남는 코드 첫번째의 경우와 같이 <code>if...else if</code>로 코드를 쭉 나열할 필요가 없었어요. 만약 로그인 성공이라면 바로 <code>return</code>함으로써 쓸데없이 밑의 코드를 읽어갈 필요가 없게 할 수 있었죠.</p>
<pre><code class="language-jsx">if (data.message === &#39;ACCESS_SUCCESS&#39;) {
  localStorage.setItem(&#39;accessToken&#39;, data.accessToken);
  alert(&#39;로그인 성공!&#39;);
  navigate(&#39;/&#39;);
  return;
}
if (ERROR_MSG[data.message]) {
  alert(ERROR_MSG[data.message]);
  return;
}
alert(&#39;로그인 실패!&#39;);</code></pre>
<p>  또한, 에러 메시지 같은 경우는 아래와 같이 상수 데이터로 관리해줄 수 있어요. </p>
<pre><code class="language-jsx">const ERROR_MSG = {
  WRONG_EMAIL: &#39;이메일을 다시 작성해주세요.&#39;,
  WRONG_PASSWORD: &#39;비밀번호를 다시 작성해주세요.&#39;,
};</code></pre>
<p><br><br></p>
<h3 id="3-장바구니">3. 장바구니</h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/9a1c5717-5042-4d36-b151-a6cf9b231898/image.gif" alt=""></p>
<p>장바구니에 담긴 상품 목록을 불러와 수량을 조절하고 선택 주문 및 삭제가 가능한 장바구니 페이지를 만들었어요. 이 페이지를 만들며 정말 다양한 어려움이 있었고, 그래서 배운점 역시 많았어요. </p>
<br>

<blockquote>
<h4 id="⚡-어려움1-setstate는-비동기적으로-처리된다는-것">⚡ 어려움1. <code>setState()</code>는 비동기적으로 처리된다는 것</h4>
<p>첫 번째 어려움은 checkbox로 선택한 상품을 배열에 담는 데에서 생겼어요. 해당 배열을 state로 관리해주었었기 때문에, 선택 상품을 클릭하면 setState로 배열에 상품을 추가해주었죠. 이 때, 저는 setState가 실행되는 별도의 함수 안에서 console로 배열에 담긴 상품을 확인했어요. 그랬더니 한 박자씩 느리게 상품이 담기는 것을 확인할 수 있었죠.<br>
setState와 같은 state 변경함수는 비동기적으로 처리된다는 사실을 인지하고 있지 못해 엄청 헤맨 경우였죠. setState는 비동기적으로 처리되기 때문에 setState가 실행되자 마자 state가 바로 변경되는게 아닌데 말이에요. 해당 setState가 오래 걸리는 작업이면, 밑의 다른 코드부터 실행한다는 것 잊지 않기!<img src="https://velog.velcdn.com/images/hye_rin/post/2178e1c5-68ce-4f2a-9c80-b6f0c7d0d713/image.png" alt=""></p>
</blockquote>
<br>

<blockquote>
<h4 id="⚡-어려움2-데이터를-불러오기도-전에-화면이-그려지는-것">⚡ 어려움2. 데이터를 불러오기도 전에 화면이 그려지는 것</h4>
<p>이 문제는 통신을 하며 알게 됐어요. 제품 상세페이지에서 상품을 장바구니 페이지에 담으면, 바로 담기지 않는 문제였죠. 어떨 때는 바로 담기기도 했구요. 한 템포가 느렸어요. 장바구니에 담긴 데이터를 불러오는 것보다 화면이 먼저 그려지기 때문에 발생한 문제였어요.<br>
제품 상세페이지에서 상품을 장바구니에 담으면 <strong>alert창</strong>💥을 띄워주자 문제가 해결됐어요. alert창으로 인해 데이터를 불러오는 시간이 생겨 해결된거였죠. 다음 프로젝트 때는 데이터를 불러올 때 loading중이란 것을 알 수 있도록 UI를 보여주도록 구현해보고 싶어요. 
<img src="https://velog.velcdn.com/images/hye_rin/post/86cf079a-6c13-4817-a002-c2c8c670b1d1/image.png" alt=""></p>
</blockquote>
<p><br><br></p>
<h3 id="4-찜목록">4. 찜목록</h3>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/f450c86a-99de-44c2-8e6d-5361d18ad679/image.gif" alt=""></p>
<p>장바구니와 동일하게 단일 선택/전체 선택 삭제가 가능한 찜 페이지를 만들었어요. </p>
<br>

<blockquote>
<h4 id="잠깐🖐🏻-기억에-남는-코드가-있다면-2">잠깐!🖐🏻 기억에 남는 코드가 있다면?</h4>
<p>처음 찜목록을 받아올 때와, 품목을 삭제했을 때, 이렇게 2번 찜목록 데이터를 fetch요청을 받아와요. 그래서 각각의 경우에 모두 동일한 fetch 요청 코드를 작성했었답니다. 그런데 코드 리뷰를 통해 해당 fetch요청을 함수로 묶어 사용해주면 된다는 것을 알게됐어요. getData라는 함수로 묶어 재사용해주었답니다!</p>
</blockquote>
<pre><code class="language-jsx">const getData = () =&gt; {
  fetch(&#39;http://000.00.00.0:3000/user/like&#39;, {
    headers: {
      authorization: accessToken,
    },
  })
    .then(response =&gt; {
      // 생략
    })
    .then(data =&gt; {
      setProductData(data.likes);
    });
};</code></pre>
<p><br><br></p>
<h2 id="느낀점">느낀점</h2>
<hr>
<h3 id="👍🏻-잘한-점">👍🏻 잘한 점</h3>
<p><strong># 소통</strong>
통신을 하는 과정에서 변경사항이 있거나 맞추면 좋겠는 부분이 있으면 지체없이 <span style="background-color:lightyellow;color:black">대화해 조율</span>했다는 점이 잘한 점이라고 생각해요! 예를 들어, 장바구니에서 수량을 조절했을 때 서버에 조절한 수량 자체를 전달할 수도 있고, <code>+1</code>인지 <code>-1</code>인지만을 전달할 수도 있었어요. 어떻게 전달하고 받을것인지에 대해 맞춰보아야 했죠. 이런 부분에 있어서 서로 감정 상하는 일 없이 소통하고자 노력했고, 그 결과 통신까지 잘 이어질 수 있었단 생각이 들어요</p>
<p>그리고 소통의 연장선상에서 깨달은 점이 있다면, 설명의 중요성이에요. 제가 요청하고 싶은 데이터가 있다면 왜 필요하고 어떻게 사용할 것인지 대해 명확히 알고 백엔드분께도 <span style="background-color:lightyellow;color:black">충분히 납득할 수 있게 설명할 수 있어야함</span>을 느꼈어요. 누구나 알아들을 수 있게 설명할 수 있는 능력을 키우자는 다짐을 합니다🤗
<img src="https://velog.velcdn.com/images/hye_rin/post/e90bc0fd-0b91-4510-9a45-2db1a8d23563/image.png" alt=""></p>
<p><br><br></p>
<h3 id="🤔-아쉬운-점과-개선방법">🤔 아쉬운 점과 개선방법</h3>
<p><strong># 초기세팅</strong>
초기세팅을 성급하게 했다는 점이 아쉬워요. 공통으로 적용할 style들을 중간에 수정하고 추가하는 일도 생겼고, <span style="background-color:lightyellow;color:black">ESLint 경고메시지가 계속 뜨는 번거로움</span>도 있었어요. 팀원들이 clone 받아 작업을 진행할 때 이러한 이유로 작업이 지체되는 일이 없도록 초기세팅을 꼼꼼하게 체크할 생각이에요.</p>
<p>또, 저는 <span style="background-color:lightyellow;color:black">branch 속에 branch를 만들어 각 branch의 commit이 합쳐진채 PR이 올라간 현상</span>을 보기도 했답니다,,저 아래 이미지의 초록 가지가 보이시나요😖 결국 이렇게 branch에서 가지쳐진 branch들을 삭제하고 다시 master에서 branch를 만들고 push해서 해결할 수 있었어요. 깃허브 commit 이력이 꼬이지 않게 꼭 신경쓰기!
<img src="https://velog.velcdn.com/images/hye_rin/post/fe2a4b1a-6849-412f-9cce-1fc816ffda88/image.png" alt=""></p>
<br>

<p><strong># 스케줄 관리</strong>
<span style="background-color:lightyellow;color:black">코드 리뷰를 받고 merge되는 시간까지 고려</span>해서 스케줄을 짜지 못했어요. 기능 구현만 하면 된다고 생각했었죠. 2차 프로젝트 때는 코드 리뷰를 받고 수정해 merge되는 시간까지 고려할 생각이에요. 그러기 위해서 기능 구현을 최대한 빨리 마무리해 리뷰를 받고 수정/보완해나갈 생각입니다!</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/142fc252-f6f7-4005-b4df-39c16e736e7a/image.png" alt=""></p>
<br>

<p><strong># 렌더링</strong>
React 렌더링에 대한 부분을 꼼꼼하게 고려하지 않아서 막상 전체 통신을 했을 때 한 템포 느리게 데이터를 보여주는 일이 많았어요. 개별 통신때는 잘 구현되었기에 더 멘붕이었던 것 같아요. <span style="background-color:lightyellow;color:black">기능 하나하나에 집착하느라 큰 그림을 보지 못한거</span>라고 생각해요. 사전에 이에 대한 부분을 충분히 고려해 코드를 짜야겠다는 다짐을 해봅니다🤧</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/af6ed9da-42b0-4f9c-bb37-bd4bf92582b9/image.jpg" alt=""></p>
<br>

<p><strong># 나홀로 갇혀있지 말기</strong>
잘 구현되지 않는 기능이 있을 때, 혼자서 끙끙거리는 시간이 너무 길었던 점이 아쉬워요. 이걸로 기능 구현에 걸린 시간이 제 예상보다 좀 더뎠던 것 같아요. 프로젝트 기간이 짧았기 때문에 도저히 안되겠단 판단이 서면, 함께 고민해 빠르게 해결할 수 있었을텐데 말이에요. 뭔가 조금만 더 하면 구현될거같단 생각이 컸던 것 같아요😩 내가 맡은 파트는 도움 없이 내가 책임지고 해결해내야한단,, 그런 생각,,?</p>
<p>다음 프로젝트 때는 나홀로 갇히지 않으려구요! <span style="background-color:lightyellow;color:black">잘 해결되지 않는 부분이 있다면 어떻게 하면 해결할 수 있는 지에 대해 충분히 공유</span>하려고 해요.</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/0ddcef25-9474-403b-be0b-4dda5c2bbefd/image.jpg" alt=""></p>
<p><br><br></p>
<h2 id="마치며">마치며</h2>
<hr>
<p>팀원분들과 함께라서 마지막까지 힘내서 프로젝트를 잘 끝마칠 수 있었어요🎉 2주 동안 계속 달리니 2주차 막바지 가서는 체력적으로 쉽지 않더라구요ㅠㅠ 그런데 서로 잘 되지 않는 부분이 있으면 도와주기도 하고 도움받기도 하며 같이 으쌰으쌰한게 큰 힘이 됐던 것 같아요. 그리고 먹는거에 진심인 팀원분들을 만나 중간중간 맛난 식사하며 에너지 충전할 수 있어 넘 좋았습니당(◍ᐡ₃ᐡ◍) 역시 한국인은 밥심..!🍚</p>
<p>이제 내일부터는 2차 프로젝트 시작이에요. 기대가 되면서 어떤 어려움이 기다리고 있을지 무섭기도 하지만!!!!! 그러한 어려움이 절 더 강하게 만드리라 믿습니다<del>!</del>! 다 덤벼<del>!</del>!👊🏻 내일을 시작으로 2주 뒤의 저는 또 어떤 모습으로 성장해 있을지 둑흔둑흔 설레는 마음으로,,회고를 마칩니다💞</p>
<p><img src="https://velog.velcdn.com/images/hye_rin/post/9bc3d9b0-f3d8-44ff-aee6-b8a0b1bbc9d1/image.jpg" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Web] HTTP통신의 요청과 응답]]></title>
            <link>https://velog.io/@hye_rin/Web-HTTP%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%9A%94%EC%B2%AD%EA%B3%BC-%EC%9D%91%EB%8B%B5</link>
            <guid>https://velog.io/@hye_rin/Web-HTTP%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%9A%94%EC%B2%AD%EA%B3%BC-%EC%9D%91%EB%8B%B5</guid>
            <pubDate>Sun, 02 Oct 2022 08:12:09 GMT</pubDate>
            <description><![CDATA[<h2 id="http가-뭐죠">HTTP가 뭐죠?</h2>
<hr>
<p>HTTP는 Hyper Text Transfer Protocol의 약자예요. HTTP를 한 줄로 말하자면, <span style="backgroundColor:lightyellow;color:black">컴퓨터들끼리 HTML파일을 주고받을 수 있도록 하는 소통방식</span>이라고 할 수 있어요.</p>
<p>서버로 데이터를 전송해야하는 웹 프론트엔드 개발자를 꿈꾸는 저로서는 꼭 알고있어야할 개념이에요!</p>
<ul>
<li>*<em>Hyper Text *</em>
문서와 문서가 링크로 연결돼 접근 할 수 있는 텍스트</li>
<li>*<em>Transfer *</em>
HTML로 만든 웹페이지 문서를 전송 (보내는 주체🙋🏻‍♀️와 받는 주체🙋🏻‍♂️ 있음)</li>
<li>*<em>Protocol *</em>
컴퓨터끼리 어떻게 HTML파일(Hyper Text)을 주고 받을지에 대한 약속</li>
</ul>
<blockquote>
<p>📜 <strong>HTTP란?</strong>
HTTP(Hyper Text Transfer Protocol)은 웹 상에서 정보를 주고 받을 수 있는 프로토콜이며, 주로 HTML 문서를 주고받는 데에 쓰인다.
<a href="https://ko.wikipedia.org/wiki/HTTP">위키백과, HTTP</a></p>
</blockquote>
<p><br><br></p>
<h2 id="request요청">Request(요청)</h2>
<hr>
<p>HTTP의 특징 중 하나는 클라이언트와 서버 사이에 이루어지는 Request(요청)와 Response(응답)프로토콜이에요. 먼저 Request(요청)에 대해 알아볼게요.</p>
<p><span style="backgroundColor:lightyellow;color:black">서버에 요청을 보낼 때는 요청에 대한 정보를 담아줘야 해요.</span> 그래야 서버는 클라이언트에서 어떤 정보를 원하는 지를 알 수 있죠.</p>
<p>HTTP 메시지는 시작줄(Start Line), 헤더(Headers), 본문(Body)로 구성돼요. </p>
<blockquote>
<p>💬 <strong>HTTP 메시지 구성</strong></p>
</blockquote>
<ol>
<li>시작줄(Start Line)</li>
<li>헤더(Headers)</li>
<li>본문(Body)</li>
</ol>
<br>

<h3 id="1-시작줄-start-line">1. 시작줄 (Start Line)</h3>
<ul>
<li><p><strong>예시</strong>
<span style="color:red">POST</span>/<span style="color:blue">login HTTP</span>/<span style="color:hotpink">1.1</span></p>
</li>
<li><p><strong>구성</strong>
<span style="color:red">HTTP method</span>/<span style="color:blue">Request target</span>/<span style="color:hotpink">HTTP version</span></p>
</li>
<li><p><strong>상세</strong>
  <span style="color:red">HTTP method</span> : GET, POST, DELETE와 같은 액션을 정의
  <span style="color:blue">Request target</span> : 요청이 전송되는 목표 URL
  <span style="color:hotpink">HTTP version</span> : HTTP 버전으로, 주로 1.1버전이 많이 쓰임</p>
</li>
</ul>
<br>

<h3 id="2-헤더-headers">2. 헤더 (Headers)</h3>
<p>헤더는 요청에 대한 정보를 담고 있으며, 아래의 예시 말고도 그 종류가 다양해요.</p>
<ul>
<li><strong>예시</strong><pre><code>Headers : {
Host: : www.hyerin.co.kr,
User-Agent : chrome,
Content-Type : application/json,
Content-Length : 50,
}</code></pre></li>
</ul>
<br>

<h3 id="3-본문-body">3. 본문 (Body)</h3>
<p>본문(Body)에는 요청의 실제 내용이 들어가요.</p>
<pre><code>Body : {
    &quot;username&quot; : &quot;hyerin&quot;,
    &quot;password&quot; : &quot;hyerin123&quot;,
}</code></pre><p><br><br></p>
<h2 id="response응답">Response(응답)</h2>
<hr>
<p>클라이언트가 서버에 보낸 요청에 대해 서버는 응답을 보내줘요. 응답도 요청과 마찬가지로 메시지인데요, 이 또한 크게 세 부분으로 구성돼요. </p>
<blockquote>
<p>💬 <strong>HTTP 메시지 구성</strong></p>
</blockquote>
<ol>
<li>시작줄(Start Line)</li>
<li>헤더(Headers)</li>
<li>본문(Body)</li>
</ol>
<br>

<h3 id="1-시작줄-start-line-1">1. 시작줄 (Start Line)</h3>
<ul>
<li><p><strong>구성</strong>
<span style="color:hotpink">HTTP version</span> <span style="color:brown">Status Code</span> <span style="color:skyblue">Status Text</span></p>
</li>
<li><p><strong>상세</strong>
<span style="color:hotpink">HTTP version</span> : HTTP 버전
<span style="color:brown">Status Code</span> : 응답 상태 코드
<span style="color:skyblue">Status Text</span> : 응답의 상태를 간략히 설명하는 텍스트</p>
</li>
<li><p><strong>예시</strong>
<span style="color:hotpink">HTTP/1.1</span> <span style="color:brown">404</span> <span style="color:skyblue">Not Found</span></p>
</li>
</ul>
<br>

<h4 id="2-헤더-headers-1">2. 헤더 (Headers)</h4>
<p>요청의 헤더와 동일해요. 헤더는 응답에 대한 정보를 담고 있으며, 요청의 헤더와 마찬가지로 그 종류가 굉장히 다양해요.</p>
<pre><code>Headers : {
    Host: : www.hyerin.co.kr,
    User-Agent : chrome,
    Content-Type : application/json,
    Content-Length : 50,
}</code></pre><br>

<h4 id="3-본문-body-1">3. 본문 (Body)</h4>
<p>본문(Body)에는 응답해줄 데이터를 넣어줘요. 로그인 요청에 대해 성공했을 경우, 아래와 같이 성공 메시지와 토큰을 전달해줄 수 있죠!</p>
<pre><code>Body : {
    &quot;message&quot; : &quot;success&quot;,
    &quot;token&quot; : &quot;dasldkfjowiejrfasdf&quot;,
}</code></pre><p><br><br></p>
<h2 id="참고">참고</h2>
<hr>
<p><a href="https://www.zerocho.com/category/HTTP/post/5b344f3af94472001b17f2da">HTTP란 무엇인가</a>
<a href="https://ko.wikipedia.org/wiki/HTTP">HTTP</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 쿼리 스트링 ]]></title>
            <link>https://velog.io/@hye_rin/React-%EC%BF%BC%EB%A6%AC-%EC%8A%A4%ED%8A%B8%EB%A7%81</link>
            <guid>https://velog.io/@hye_rin/React-%EC%BF%BC%EB%A6%AC-%EC%8A%A4%ED%8A%B8%EB%A7%81</guid>
            <pubDate>Sun, 02 Oct 2022 08:03:36 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가며">들어가며</h2>
<hr>
<blockquote>
<p>🤗 1차 프로젝트를 진행하며 쿼리 스트링을 알게됐어요. URL에도 부가적인 정보를 담을 수 있다는게 정말 신기했답니다. 하지만 아직 제대로 사용하고 있단 생각이 들진 않아서 차차 살을 덧붙여가며 공부를 해볼 생각이에요.</p>
</blockquote>
<p><br><br></p>
<h2 id="쿼리-스트링query-string">쿼리 스트링(Query String)</h2>
<hr>
<pre><code>https://www.hyerin.com/cart?productId=1&amp;productId=2&amp;productId=3</code></pre><blockquote>
<p>💁🏻‍♀️ 쿼리스트링은 URL의 한 부분입니다. 요청하고자 하는 URL에 추가 정보를 포함하고 싶을 때 사용하죠. <strong><code>key=value</code></strong>의 형태의 문자열로 표현하는데, URL에서 쿼리 스트링이 시작된다는 표시는 <strong><code>?</code></strong>를 통해 표현할 수 있습니다. URL내의 <strong>여러개의 <code>key=value</code>쌍</strong>을 구분하고자 할 때는 <strong><code>&amp;</code></strong>를 통해 구분할 수 있어요.</p>
</blockquote>
<p><br><br></p>
<h2 id="삭제-요청-보내기">삭제 요청 보내기</h2>
<hr>
<p>쿼리 스트링을 사용해 삭제할 품목들의 상품ID를 URL을 담아 서버에 <code>DELETE</code> 요청을 하고자 했어요. 삭제할 품목들은 checkbox로 선택할 수 있었고, 사용자가 상품을 체크하면 <code>checkedList</code>라는 배열에 상품ID를 담았죠.
<img src="https://velog.velcdn.com/images/hye_rin/post/19dde6a3-5c68-46db-9530-360144288184/image.png" alt=""></p>
<br>

<p>삭제할 제품을 체크하면 URL에 <code>productId=선택한상품ID&amp;</code>를 붙여줘야 했어요. 여러개를 선택했을 경우 해당 상품들을 모두 URL에 쭉 붙여줘야 했으므로 반복문을 사용해 URL에 함수를 넣어줬어요.  </p>
<p>아래의 코드는 반복문을 사용해 삭제할 상품ID를 쿼리스트링 형태에 맞게 붙이도록 한 함수입니다. 마지막의 <code>&amp;</code>은 제거해줘야하기 때문에 <code>slice()</code>를 사용해 마지막 <code>&amp;</code>을 제거해주는 작업 필수-!</p>
<pre><code class="language-jsx">// 선택 삭제 클릭 시 선택한 상품ID 반복해 붙이기
const checkedQueryString = () =&gt; {
    let checkedProducts = &#39;&#39;;
    for (let i = 0; i &lt; checkedList.length; i++) {
      checkedProducts += `productId=${checkedList[i]}&amp;`;
    }
    return checkedProducts.slice(0, -1);
};</code></pre>
<br>

<p>아래의 <code>deleteChecked</code>는 선택 삭제 버튼을 클릭하면 <code>fetch</code>로 <code>DELETE</code>요청을 보내는 함수입니다. 선택한 상품이 있을 경우에는 요청을 보내도록 했고, 그렇지 않은 경우에는 <code>alert</code>창을 띄우게 했어요. </p>
<pre><code class="language-jsx">// 선택 삭제 클릭 시 선택한 상품ID를 쿼리 스트링 형태로 요청
const deleteChecked = () =&gt; {
    if (checkedList.length &gt; 0) {
      fetch(`http://172.20.10.6:3000/cart?${checkedQueryString()}`, {
        method: &#39;DELETE&#39;,
        headers: {
          authorization: accessToken,
        },
      })
    } else {
      alert(&#39;삭제할 상품을 선택해주세요!&#39;);
    }
};</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 컴포넌트 재사용하기]]></title>
            <link>https://velog.io/@hye_rin/React-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%9E%AC%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@hye_rin/React-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%9E%AC%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 25 Sep 2022 14:26:43 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>🎀 분리되어 있지 않은 컴포넌트를 분리해서 재사용하는 실습을 했어요. 실습을 하며 되도록 컴포넌트를 재사용할 수 있는 방법에 대해 고민할 수 있었습니다! :)</p>
</blockquote>
<br>

<h2 id="span-stylecolorrgb18-184-134-1-ui-구성-요소-파악span"><span style="color:rgb(18, 184, 134)"> 1. UI 구성 요소 파악</span></h2>
<hr>
<p>첫번째, 두번째, 세번째 카드 중에서 비슷한 요소들을 색깔로 구분지어 봤어요. <span style="color:red"><strong>이미지</strong></span>, <span style="color:blue"><strong>태그</strong></span>, <span style="color:green"><strong>제목</strong></span>, <span style="color:purple"><strong>설명</strong></span>은 텍스트의 내용만 다르고 화면에 그려지는 모양은 같은 것을 알 수 있었어요.
<img src="https://velog.velcdn.com/images/hye_rin/post/41553187-98c5-4235-9f0a-9523f92af8cf/image.png" alt=""></p>
<p><br><br></p>
<h2 id="span-stylecolorrgb18-184-134-2-mock-data-span"><span style="color:rgb(18, 184, 134)"> 2. Mock Data </span></h2>
<hr>
<p>UI가 어떻게 구성되어 있는지 파악했으니, Mock Data를 만들었어요. <span style="color:red"><strong>이미지</strong></span>, <span style="color:blue"><strong>태그</strong></span>, <span style="color:green"><strong>제목</strong></span>, <span style="color:purple"><strong>설명</strong></span>을 각각 키로 생성했죠! 그리고, 해당 카드가 카드 형태인지, 리스트가 들어있는 카드 형태인지, 그리고 리스트가 앨범형식으로 되어있는 카드 형태인지를 구분지어주기 위해 카테고리를 다르게 설정해줬어요. </p>
<br>

<p><strong>CardData.json</strong></p>
<pre><code class="language-json">[
  {
    &quot;category&quot;: &quot;card&quot;,
    &quot;img&quot;: &quot;https://t1.kakaocdn.net/friends/prod/main_tab/home/home_20201103134054_kr.jpg?type=thumb&amp;opt=R329x247@2xa&quot;,
    &quot;tag&quot;: &quot;new&quot;,
    &quot;title&quot;: &quot;촉촉함을 원해요&quot;,
    &quot;content&quot;: &quot;재채기는 콜록 콜록 눈,코,입 모두 간질 간질. 이게 다 건조함 때문이라구! 건조함을 해결하러 온 꿀꿀꿀귀탱 가습기들, 구경해볼까요?&quot;
  },
  {
    &quot;category&quot;: &quot;list&quot;,
    &quot;img&quot;: &quot;https://t1.kakaocdn.net/friends/prod/main_tab/home/home_20201106164745_kr.jpg?type=thumb&amp;opt=R329x247@2xa&quot;,
    &quot;tag&quot;: &quot;good&quot;,
    &quot;title&quot;: &quot;통통미 폭발 구름 폭신 필로우&quot;,
    &quot;content&quot;: &quot;통통하고 말랑 말랑한 너희에게 내 하루 시작과 끝에서 힐링을 부탁해!&quot;
  },
  {
    &quot;category&quot;: &quot;list-card&quot;,
    &quot;img&quot;: &quot;https://t1.kakaocdn.net/friends/prod/main_tab/home/home_20201111183631_kr.jpg?type=thumb&amp;opt=R335x187@2xa&quot;,
    &quot;tag&quot;: &quot;theme&quot;,
    &quot;title&quot;: &quot;올 겨울엔 프렌즈랑 메리 화이트 크리스마스!&quot;,
    &quot;content&quot;: &quot;올해 크리스마스엔 눈이 올까요? 안오면 어때요. 이미 프렌즈들이 내 마음에 하얀 눈을 내려주고 있는걸!&quot;
  }
]
</code></pre>
<br>

<p>그리고 해당 json파일을 부모 컴포넌트에서 <code>cardData</code>라는 <code>state</code>에 저장해줍니다.</p>
<pre><code class="language-jsx">const [cardData, setCardData] = useState([]);
  useEffect(() =&gt; {
    fetch(&quot;/data/CardData.json&quot;)
      .then((res) =&gt; res.json())
      .then((data) =&gt; setCardData(data));
}, []);</code></pre>
<p><br><br></p>
<h2 id="span-stylecolorrgb18-184-134-3-부모-컴포넌트와-자식-컴포넌트span"><span style="color:rgb(18, 184, 134)"> 3. 부모 컴포넌트와 자식 컴포넌트</span></h2>
<hr>
<p>앞서, 데이터를 부모 컴포넌트에 저장했다고 했는데요. 저는 반복될 카드들을 자식 컴포넌트로 분리시켰어요. <code>CardList</code>는 부모 컴포넌트, 그리고 <code>Card</code>는 자식 컴포넌트로 관리해줬답니다.</p>
<pre><code class="language-jsx">// CardList.js (부모 컴포넌트)
const CardList = () =&gt; {
  // Mock Data 불러와 저장
  const [cardData, setCardData] = useState([]);
  useEffect(() =&gt; {
    fetch(&quot;/data/CardData.json&quot;)
      .then((res) =&gt; res.json())
      .then((data) =&gt; setCardData(data));
  }, []);

  return (
    &lt;div&gt;
      {cardData.map((data) =&gt; (
        &lt;Card
          category={data.category}
          img={data.img}
          tag={data.tag}
          title={data.title}
          content={data.content}
        /&gt;
      ))}
    &lt;/div&gt;
  );
};</code></pre>
<p><br><br></p>
<h2 id="span-stylecolorrgb18-184-134-5-리스트가-포함된-카드라면span"><span style="color:rgb(18, 184, 134)"> 5. 리스트가 포함된 카드라면?</span></h2>
<hr>
<h4 id="-리스트와-앨범형-리스트"># 리스트와 앨범형 리스트</h4>
<p>리스트가 포함된 카드는 리스트를 보여줘야하고, 앨범형 리스트가 포함된 카드는 앨범형 리스트를 보여줘야해요. 쓰일 내용을 부모 컴포넌트로부터 props로 받아와서 사용했어요. 태그 스타일같은 경우 class이름도 태그 이름에 따라 변경될 수 있도록 해줬죠!</p>
<p>리스트도 두 가지 종류였기 때문에 category가 list인 경우에는 리스트 형태를 보여주고, category가 앨범형 리스트인 list-card인 경우에는 앨범형 리스트를 보여주도록 해줬어요. </p>
<h4 id="-개선해볼-수-있는-부분"># 개선해볼 수 있는 부분</h4>
<p>하지만 list와 list-card의 경우도 class명만 다르기 때문에 아래 코드도 그리 효율적이지 않아 보여요. Mock Data에 리스트인지 앨범형 리스트인지도 구분할 수 있는 키를 만들면, class명을 해당 키로 구분할 수 있을거란 생각이 들어요!</p>
<pre><code class="language-jsx">// Card.js (자식 컴포넌트)
const Card = ({ category, img, tag, title, content }) =&gt; {
  return (
    &lt;&gt;
      &lt;article&gt;
        &lt;div&gt;
          &lt;img alt=&quot;cardImg&quot; src={img} /&gt; // 이미지 url 변경
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;span className={tag}&gt;{tag}&lt;/span&gt; // 태그 스타일과 태그 내용 변경
          &lt;/div&gt;
          &lt;h3&gt;{title}&lt;/h3&gt; // 제목 변경
          &lt;div&gt;
            &lt;p&gt;{content}&lt;/p&gt; // 내용 변경
          &lt;/div&gt;
          {category === &quot;list&quot; &amp;&amp; ( // 리스트인 경우
            &lt;ul&gt;
              &lt;li&gt;&lt;/li&gt; 
              &lt;li&gt;&lt;/li&gt; 
              &lt;li&gt;&lt;/li&gt;
            &lt;/ul&gt;
          )}
          {category === &quot;list-card&quot; &amp;&amp; ( // 앨범형 리스트인 경우
            &lt;ul&gt;
              &lt;li&gt;&lt;/li&gt; 
              &lt;li&gt;&lt;/li&gt;
              &lt;li&gt;&lt;/li&gt; 
            &lt;/ul&gt;
          )}
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/&gt;
  );
};</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] state로 만들 필요 없을 때]]></title>
            <link>https://velog.io/@hye_rin/React-state%EB%A1%9C-%EB%A7%8C%EB%93%A4-%ED%95%84%EC%9A%94-%EC%97%86%EC%9D%84-%EB%95%8C</link>
            <guid>https://velog.io/@hye_rin/React-state%EB%A1%9C-%EB%A7%8C%EB%93%A4-%ED%95%84%EC%9A%94-%EC%97%86%EC%9D%84-%EB%95%8C</guid>
            <pubDate>Sun, 25 Sep 2022 06:59:55 GMT</pubDate>
            <description><![CDATA[<h3 id="✅-span-stylecolorrgb18-184-134들어가며span">✅ <span style="color:rgb(18, 184, 134)">들어가며</span></h3>
<blockquote>
<p>로그인 시, 사용자가 input에 값을 입력했을 때 아이디란에는 @가 꼭 포함되도록 하고, 비밀번호의 길이는 5자 이상이 되도록 하고 싶었어요. 둘 다 제대로 입력했을 때 로그인 버튼이 활성화되도록 만들고자 했죠.<br>
그래서 처음에 생각한 방식은 사용자가 input에 값을 입력할 때마다 <code>onKeyUp</code>이벤트 핸들러로 사용자가 조건에 맞게 작성했는지 확인하는거였어요. </p>
</blockquote>
<p><br><br></p>
<h3 id="✅-span-stylecolorrgb18-184-134리팩토링-전span">✅ <span style="color:rgb(18, 184, 134)">리팩토링 전</span></h3>
<blockquote>
<p>💥 <strong>문제점</strong></p>
</blockquote>
<ol>
<li><code>disabled</code>속성을 state로 관리
 : boolean인 <code>disabled</code>속성을 state로 선언해 따로 관리하고 있어요.<br></li>
<li><code>onKeyUp</code> 이벤트 핸들러
 : 사용자가 입력할 때마다 값을 확인해서 setState로 <code>disabled</code>속성을 조정해줍니다. </li>
</ol>
<pre><code class="language-jsx">// Login 컴포넌트
const Login = () =&gt; {
  const [disabled, setDisabled] = useState(true);
  const handleDisabled = () =&gt; {
      let validation = userId.includes(&quot;@&quot;) &amp;&amp; userPw.length &gt; 4;
      return validation ? setDisabled(false) : setDisabled(true);
  };

  return (
    &lt;form&gt;
       &lt;input onKeyUp={handleDisabled} /&gt;
       &lt;button
      style={
        disabled === true
          ? { backgroundColor: &quot;rgb(0, 149, 246, 0.3)&quot; }
          : { backgroundColor: &quot;rgb(0, 149, 246, 1)&quot; }
      }
      disabled={disabled}
      &gt;
      로그인
      &lt;/button&gt;
    &lt;/form&gt;
  )
}
</code></pre>
<p><br><br></p>
<h3 id="✅-span-stylecolorrgb18-184-134리팩토링-후span">✅ <span style="color:rgb(18, 184, 134)">리팩토링 후</span></h3>
<blockquote>
<p>🎉 <strong>해결</strong>
유효성 검사는 <code>true</code> or <code>false</code>로 판별한다는 것!<br>
    :  아이디나 비밀번호가 조건에 따라 제대로 쓰였는지에 대한 결과는 <code>boolean</code>값인 <code>true</code>나 <code>false</code>죠! 따라서, 이 조건을 바로 <code>disabled</code>속성에 적용시키면 돼요. 조건에 맞으면 <code>true</code>니까 버튼이 활성화될 것이고, 조건에 맞지 않으면 <code>false</code>가 돼 버튼이 비활성화 되겠죠!</p>
</blockquote>
<pre><code class="language-jsx">// Login 컴포넌트
const Login = () =&gt; {
  const isInputValid =
  userId.includes(&quot;@&quot;) &amp;&amp;
  userPw.length &gt; 4 &amp;&amp;;

  return (
    &lt;form&gt;
       &lt;input /&gt;
       &lt;button
        style={
          isInputValid
            ? { backgroundColor: &quot;rgb(0, 149, 246, 1)&quot; }
            : { backgroundColor: &quot;rgb(0, 149, 246, 0.3)&quot; }
        }
        disabled={!isInputValid}
       &gt;
        로그인
       &lt;/button&gt;
    &lt;/form&gt;
  )
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>