<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>daeun-react.log</title>
        <link>https://velog.io/</link>
        <description>단단_프로트엔드개발자!</description>
        <lastBuildDate>Sun, 12 Sep 2021 12:44:50 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>daeun-react.log</title>
            <url>https://images.velog.io/images/daeun-react/profile/403296c7-0652-4f11-9ba9-55395f31e860/KakaoTalk_20210727_101544138.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. daeun-react.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/daeun-react" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Assignment 10 회고록] 콜로세움 - 프로젝트 설계와 테크 스펙]]></title>
            <link>https://velog.io/@daeun-react/Assignment-10-%EC%BD%9C%EB%A1%9C%EC%84%B8%EC%9B%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%84%A4%EA%B3%84%EC%99%80-%ED%85%8C%ED%81%AC-%EC%8A%A4%ED%8E%99</link>
            <guid>https://velog.io/@daeun-react/Assignment-10-%EC%BD%9C%EB%A1%9C%EC%84%B8%EC%9B%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%84%A4%EA%B3%84%EC%99%80-%ED%85%8C%ED%81%AC-%EC%8A%A4%ED%8E%99</guid>
            <pubDate>Sun, 12 Sep 2021 12:44:50 GMT</pubDate>
            <description><![CDATA[<h3 id="🔗-과제-링크---노션">🔗 <a href="https://darkened-date-9ab.notion.site/8-600606223207419b99b714ed4749c0ff">과제 링크 - 노션</a></h3>
<hr>
<h3 id="과제-내용">과제 내용</h3>
<p>콜로세움에서는 CS처리를 위해 카카오톡과 유선의 방식을 사용하고 있습니다. 
해당 매체들을 통해 셀러 또는 창고 작업자들과 협업을 하고 있습니다. 하지만 셀러와 창고주의 수가 늘어남에 따라 모니터에 띄워야 하는 메신저의 수는 많아지고 있어 이를 해결하기 위해 여러 곳에서 들어오는 톡을 한곳에서 읽고 내용을 기록하고 처리하고자 합니다.</p>
<p><strong>착안사항은 다음과 같습니다.</strong></p>
<ul>
<li>여러명의 인원이 한 화면을 보고 처리 가능해야 한다.</li>
<li>1명 이상의 인원이 동일한 카톡의 내용을 보고 기록해 놓을 수 있어야 한다.</li>
<li>전체 대화의 내용은 DB에 기록이 되어야 한다.</li>
<li>카카오톡은 수신 뿐 아니라 응대가 가능하도록 송신의 기능도 가능해야 한다.</li>
</ul>
<hr>
<h2 id="🔰-테크-스펙-이란">🔰 테크 스펙 이란?</h2>
<p><a href="https://docs.google.com/document/d/1nhozeUvJYKytE_b_9-YP4Fyw0wtykl9haCG4Wwjb9Ws/edit">&gt; 뱅크샐러드 테크 스펙 템플릿</a></p>
<ul>
<li>테크 스펙은 뱅크샐러드 회사에서 나온 용어로, <strong>기술(tech) 설명서(spec)</strong>를 말한다.</li>
<li><strong>기능을 구현하기 전에 이 기능을 어떻게 구현할 것인지 기술적으로 풀어 설명하고, 제안하는 글</strong>이다.</li>
<li>테크 스펙은 실제 개발에 바로 들어갈 수 있을 것 처럼 자세하게 적어서 실제 플랫폼 코드가 포함되는 경우도 많다.</li>
</ul>
<hr>
<h2 id="🔰-작성한-5가지-사항">🔰 작성한 5가지 사항</h2>
<ul>
<li><h3 id="요약-summary"><code>요약 (Summary)</code></h3>
<p>➡ 테크 스펙을 대략적으로 정리
➡ 누가/무엇을/언제/어디서/왜를 간략하면서도 명확하게 작성</p>
</li>
<li><h3 id="배경-background"><code>배경 (Background)</code></h3>
<p>➡ 프로젝트의 Context 작성
➡ 왜 이걸 만드나? 동기는 무엇인가? 어떤 사용자 문제를 해결하려 하는가? 
  &nbsp;&nbsp;&nbsp; 이전에 이런 시도가 있었는가? 있었다면, 해결이 되었었나?</p>
</li>
<li><h3 id="목표-goals"><code>목표 (Goals)</code></h3>
<p>➡ 얻을 예상 결과들을 Bullet Point 형태로 나열
➡ 이 목표들와 측정가능한 임팩트들을 이용해 이 프로젝트의 성공 여부를 평가하게 된다.
  &nbsp;&nbsp;&nbsp; “우리는 우리의 의도한 목표와 임팩트들을 이뤄 냈는가?”</p>
</li>
<li><h3 id="목표가-아닌-것-non-goals"><code>목표가 아닌 것 (Non-goals)</code></h3>
<p>➡ 프로젝트에 연관되어 있으나 의도적으로 하지 않거나 해결하지 않으려 하는 것 작성.
➡ 독자가 직관적으로 이해할 수 있도록 Bullet Point 형태로 읽기 쉽게 작성
➡ 목표가 아닌 것을 정하게 되면 프로젝트 범위를 더 명확하게 할 수 있고, 
  &nbsp;&nbsp;&nbsp; 이 기능도 붙이자, 저 기능도 붙이자 하는 것을 막을 수 있다.</p>
</li>
<li><h3 id="✨-계획-plan"><strong><code>✨ 계획 (Plan)</code></strong></h3>
<p>➡ 테크 문서에서 가장 긴 파트
➡ <strong>어떻게 기술적, 엔지니어링적으로 접근할지 상세히 묘사</strong>
➡ 어떻게 할지 확실히 결정하지 못한 상태라면, 어떤 것들을 고려하고 있는지 다 목록화해서 작성</p>
</li>
</ul>
<hr>
<h2 id="🔰-계획-부분-설명">🔰 계획 부분 설명</h2>
<ul>
<li><p>&quot;테크 스펙은 실제 개발에 바로 들어갈 수 있을 것 처럼 자세하게 적어서 실제 플랫폼 코드가 포함되는 경우도 많다.&quot; 라는 부분을 보고 최대한 자세하게 작성하기 위해 노력했습니다.</p>
</li>
<li><p>팀원들과 함께 아래의 1~5까지의 과정을 함께 토론하고 작성했습니다.</p>
<hr>
<h3 id="1-유저-스토리--시나리오----작성-링크">1. 유저 스토리 &amp; 시나리오   <a href="https://darkened-date-9ab.notion.site/69809e396fe347d5bf08c6e05118deee">&gt; 작성 링크</a></h3>
<ul>
<li>웹 사이트를 이용할 콜로세움 CS 직원 입장에서 어떠한 기능이 필요하고, 
어떠한 순서로 작업이 이루워져야 하는지 생각해보고 작성을 진행하였습니다. </li>
</ul>
<hr>
</li>
</ul>
<h3 id="2-피그마를-통한-시각화--피그마-링크">2. 피그마를 통한 시각화 <a href="https://www.figma.com/file/fZwOc8RvWGiIriPLeiLX8D/%EC%BD%9C%EB%A1%9C%EC%84%B8%EC%9B%80?node-id=0%3A1">&gt; 피그마 링크</a></h3>
<ul>
<li><p>작성한 유저 스토리 및 시나리오를 바탕으로 실제 CS 직원이 사용한다면, 어떠한 UI로 설계되면 좋을지 의논했습니다.</p>
</li>
<li><p>크게 3개의 <code>상담목록</code>, <code>고객상담</code>, <code>고객정보</code> section으로 나누어, 각각 필요한 기능을 만들어 보았습니다.
<img src="https://images.velog.io/images/daeun-react/post/86c2fab0-79b3-40fd-96b2-4b50e136a3a5/figma.png" alt=""></p>
</li>
</ul>
<hr>
<h3 id="3-컴포넌트-설계--작성-링크">3. 컴포넌트 설계 <a href="https://darkened-date-9ab.notion.site/7ab6c0fec2014b1787dca98d25a3b6c7">&gt; 작성 링크</a></h3>
<ul>
<li>구현되어야 할 이미지를 첨부하고, 각각의 컴포넌트가 어떻게 개발되어야 할지에 대해 작성하여 글로 작성하는 것보다 설계자의 의도를 정확하게 전달하고자 하였습니다.</li>
<li>크게 3개의 <code>상담목록</code>, <code>고객상담</code>, <code>고객정보</code> section과 그 하위에 필요한 컴포넌트들을 모두 작성하여 계층 구조로 표현하였습니다.
<img src="https://images.velog.io/images/daeun-react/post/f90e1c24-7bbb-4a4a-8f03-765449952b47/image.png" alt="컴포넌트 구조"></li>
</ul>
<hr>
<h3 id="4-db-테이블-설계--작성-링크">4. DB 테이블 설계 <a href="https://darkened-date-9ab.notion.site/DB-f1222649bf73475891cd053f2722273b">&gt; 작성 링크</a></h3>
<ul>
<li>피그마 및 컴포넌트 설계 내용을 바탕으로 DB에 저장되어야 할 목록을 작성했고, 생성해야 할 DB 테이블 간 관계에 대해 생각하며 작성하였습니다.</li>
</ul>
<hr>
<h3 id="5-api-및-웹소켓-설계--api-링크--웹소켓-링크">5. API 및 웹소켓 설계 <a href="https://darkened-date-9ab.notion.site/API-065895b45e554428b3383f9e3d342ce5">&gt; API 링크</a> <a href="https://darkened-date-9ab.notion.site/Websocket-3f3a410df43a4341bb0288fd399cecf6">&gt; 웹소켓 링크</a></h3>
<ul>
<li><p>&quot;카카오톡에 고객의 문의내용을 남기면, CS팀에서 바로 응대가 가능해야한다&quot;라는 전제 조건에 대해 생각하고 방법에 대해 논의하였습니다.</p>
</li>
<li><p>그러나, 카카오톡 개발자 API 명세를 찾아보니 CS팀➡고객에게 카톡 메세지를 송신할 수 있는 방법에 대해서는 찾았지만, 고객➡CS팀에 문의한 수신 내용을 실시간으로 확인할 수 있는 API는 현재 없는 것으로 보입니다.</p>
</li>
<li><p>카카오톡 비즈니스 &quot;상담톡&quot;을 이용하면, 유료이긴 하지만 고객의 문의 내용을 실시간으로 확인할 수 있는 API를 제공받을 수 있습니다. 따라서 해당 프로젝트 설계의 전제는 콜로세움에서 <strong>&quot;카카오톡 상담톡을 통해 고객의 CS 문의내용을 입력받고, 백엔드 팀에서 해당 API를 활용하여 고객의 문의내용을 관리해준다.&quot;</strong> 라고 설계하였습니다.</p>
</li>
<li><p>프론트엔드 개발자는 백엔드 팀에서 만들어준 API를 사용하여, 전체 CS 문의 내용 및 특정 CS 문의 내용, 고객 정보등을 사용하여 기능을 구현할 수 있습니다.</p>
</li>
<li><p>또한 CS 상담 직원이 메세지를 보내거나, 진행 상태를 변경할 때 서버와 클라이언트 간 양방향 소통을 할 수 있도록 웹소켓 사용에 대한 내용도 고려하였습니다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Assignment 9 회고록] 페이워크 - TS 기반 전역상태 관리]]></title>
            <link>https://velog.io/@daeun-react/Assignment-9-%ED%8E%98%EC%9D%B4%EC%9B%8C%ED%81%AC-Redux-Saga</link>
            <guid>https://velog.io/@daeun-react/Assignment-9-%ED%8E%98%EC%9D%B4%EC%9B%8C%ED%81%AC-Redux-Saga</guid>
            <pubDate>Sun, 12 Sep 2021 12:30:16 GMT</pubDate>
            <description><![CDATA[<h3 id="🔗-github"><a href="https://github.com/daeun-react/wanted-paywork-todolist">🔗 Github</a></h3>
<h3 id="🔗-배포-링크"><a href="https://daeun-react.github.io/wanted-paywork-todolist/">🔗 배포 링크</a></h3>
<hr>
<h3 id="과제를-끝내고-회고-내용">과제를 끝내고 회고 내용</h3>
<h3 id="🔰-json을-배포하고-싶다면">🔰 json을 배포하고 싶다면?</h3>
<ul>
<li><code>json-server</code>을 설치하고, <code>scripts</code>에 명령어를 추가하여 개발을 진행했다.</li>
<li>그런데, 배포를 하려고 보니 <code>netlify</code>에서 동작하지 않는 문제가 생겼다. </li>
</ul>
<pre><code class="language-jsx">// package.json
&quot;scripts&quot;: {
    ...
    &quot;server&quot;: &quot;npx json-server ./server/data.json --port 4000&quot;,
    &quot;dev&quot; :&quot;concurrently \&quot;npm run server\&quot; \&quot;npm run start\&quot;&quot;
 },</code></pre>
<pre><code class="language-jsx">// server/data.json
{
    &quot;todos&quot;: [{
            &quot;id&quot;: 1,
            &quot;content&quot;: &quot;타입스크립트 공부하기&quot;,
            &quot;isCheck&quot;: true,
            &quot;createdAt&quot;:&quot;2012-04-30T02:15:12.356Z&quot;,
            &quot;color&quot;: &quot;red&quot;
        },
        {
            &quot;id&quot;: 2,
            &quot;content&quot;: &quot;Redux-Saga 공부하기&quot;,
            &quot;isCheck&quot;: false,
            &quot;createdAt&quot;: &quot;2012-04-30T02:15:12.356Z&quot;,
            &quot;color&quot;: &quot;orange&quot;
        }
        ...
    ]
}</code></pre>
<ul>
<li>(해결) <strong><code>heroku</code>에서 <code>json-server</code> 부분만 따로 배포하여 진행하였다.</strong> <a href="https://redux-advanced.vlpt.us/3/09.html">&gt; Heroku 참고 링크</a><pre><code class="language-jsx">// utils/constants.js
export const BASE_URL = &#39;http://paywork-todo.herokuapp.com/&#39;;</code></pre>
</li>
</ul>
<h3 id="🔰-redux-saga-비동기-액션-처리">🔰 Redux-Saga 비동기 액션 처리</h3>
<ul>
<li><p><a href="https://velog.io/@daeun-react/2021.08.30-Redux-saga-Client-%EC%8B%A4%EB%AC%B4-%EA%B0%9C%EB%B0%9C">&gt; Redux-Saga 수업내용 정리 &lt; </a></p>
</li>
<li><p>Redux-Saga 관련해서는 수업에도 들었고, 몇 번 사용해서 개발을 진행해봐서 비동기 처리나 generate문법을 알고 있었다. 그런데 TS 환경에서는 처음 사용해봐서 타입을 지정하는게 꽤나 어려웠다.</p>
</li>
</ul>
<h3 id="🔰-keyframes를-통한-애니메이션">🔰 @keyframes를 통한 애니메이션</h3>
<ul>
<li><a href="https://webclub.tistory.com/621">&gt; @keyframes 참고 링크 &lt;</a></li>
<li>투두리스트를 추가하거나 상태가 변경된 경우 바로 확인할 수 있도록 @keyframes 이벤트를 만들었다.
<img src="https://images.velog.io/images/daeun-react/post/e684b93b-6514-4d7c-999d-f58a93684f84/%EC%B5%9C%EC%A2%85.gif" alt=""></li>
<li><strong>(참고) <code>transition</code> VS <code>animation</code> 차이</strong><ul>
<li><code>transition</code>: 요소의 상태가 변해야 애니메이션을 실행한다.</li>
<li><code>animation</code>:  요소의 모양과 동작을 키프레임 단위로 변경할 수 있다. 
키프레임 동작은 재생 횟수, 재생 방향등 여러 애니메이션 속성으로 제어할 수 있다.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="과제-내용">과제 내용</h3>
<ul>
<li>다지인 자유 &amp; TodoList 구현<ul>
<li>TypeScript 기반 </li>
<li>Redux + Redux-Saga를 통한 전역 상태 관리 및 비동기 처리</li>
</ul>
</li>
<li>실제 API 서버는 없으므로 서버 URL이 있다는 가정하에 진행</li>
</ul>
<hr>
<h3 id="구현-내용">구현 내용</h3>
<h3 id="🔰-redux-saga--typescript">🔰 Redux-Saga + TypeScript</h3>
<ul>
<li>saga 함수를 axios Async 함수마다 따로 만들다 보니, 파일이 전체적으로 너무 길어졌다.
➡ 호출하는 API만 다를뿐, 같은 기능을 수행하므로 하나의 함수로 만들어서 관리하고 싶어졌다.</li>
<li>아래의 함수처럼 <code>sagaAsyncTodo</code> 함수를 생성했다.
➡ props로 <code>type</code>, <code>ApiFunc</code>, <code>action</code>을 받는다.
➡ <code>ApiFunc</code>를 <code>any</code> 타입에서 적절한 타입으로 수정이 필요하다.</li>
</ul>
<pre><code class="language-jsx">/* saga 실행 시, api 함수 비동기 호출 함수 */
function* sagaAsyncTodo(type: string, ApiFunc: any, action?: TodosAction) {
  const [SUCCESS, FAILURE] = [`${type}_SUCCESS`, `${type}_FAILURE`];
  try {
    const response: {
      msg: string;
      result: TodoType[] | number;
      content?: string;
    } =
      action &amp;&amp; action.payload
        ? yield call(ApiFunc, action.payload)
        : yield call(ApiFunc);

    yield put({ type: SUCCESS, payload: response });
  } catch (error) {
    yield put({
      type: FAILURE,
      payload: ERROR_MESSAGE[type],
    });
  }
}

/* Saga 액션 감지 */
export function* watchTodos() {
  yield takeEvery(GET_TODOS, () =&gt; sagaAsyncTodo(GET_TODOS, api.getTodoAll));
  yield takeEvery(ADD_TODO, (action: TodosAction) =&gt;
    sagaAsyncTodo(ADD_TODO, api.addTodoAPI, action),
  );
  yield takeEvery(TOGGLE_TODO, (action: TodosAction) =&gt;
    sagaAsyncTodo(TOGGLE_TODO, api.toggleTodoAPI, action),
  );
  yield takeEvery(DELETE_TODO, (action: TodosAction) =&gt;
    sagaAsyncTodo(DELETE_TODO, api.deleteTodoAPI, action),
  );
  yield takeEvery(UPDATE_TODO, (action: TodosAction) =&gt;
    sagaAsyncTodo(UPDATE_TODO, api.updateTodoAPI, action),
  );
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2021.09.06] SPA, CSR, SSR]]></title>
            <link>https://velog.io/@daeun-react/2021.09.06-SPA-CSR-SSR</link>
            <guid>https://velog.io/@daeun-react/2021.09.06-SPA-CSR-SSR</guid>
            <pubDate>Fri, 10 Sep 2021 08:07:53 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-검색-크롤러">📌 검색 크롤러</h2>
<ol>
<li>웹페이지를 방문하여 모든 링크를 찾은 다음, 이 링크를 목록화 한다.</li>
<li>그 다음 이 링크들을 이전에 방문한 적이 있는지 확인하고, 방문해본 적이 없으면 그 링크를 타고 웹페이지를 방문한다. </li>
<li>그 페이지에서 앞에서 진행한 과정을 반복한다.</li>
</ol>
<h3 id="💡-현재의-검색-알고리즘">💡 현재의 검색 알고리즘</h3>
<ul>
<li><p>모든 웹페이지와 수십억 가지의 검색어, 모든 링크를 다 합친 것이 페이지랭크
➡ 하나가 아닌 <strong>여러 개의 알고리즘</strong>으로 구성되어있다.</p>
</li>
<li><p>실제로 링크를 누가 얼마나 클릭하는지</p>
</li>
<li><p>크롤러가 웹페이지를 찾으면 Google 시스템에서는 브라우저와 마찬가지로 해당 페이지의 콘텐츠를 렌더링한다. 이때 키워드 및 웹사이트 최신 정보에 이르는 주요 신호를 기록하며 검색 색인에서 모든 주요 신호를 추적한다.</p>
</li>
<li><p>키워드 검색과 웹 페이지에 담긴 텍스트 비교, 반복성, 서체크기, 대문자, 키워드의 위치 등 여러가지 전통적인 정보검색기술과 결합한다.
  →  전통적인 판단 요소를 시그널(signal) 이라고 한다. 검색품질에 대단히 중요한 역할을 한다.</p>
</li>
</ul>
<hr>
<h2 id="📌-seosearch-engine-optimization-검색-최적화">📌 SEO(Search Engine Optimization, 검색 최적화)</h2>
<blockquote>
<p>구글에서 말하길...
검색엔진 최적화의 효과를 보려면 시간이 다소 걸립니다.
변경을 시작해서 성과가 나타날 때까지 <strong>✨ 보통 4개월에서 1년 정도 소요</strong>됩니다.</p>
</blockquote>
<h3 id="💡-seo를-잘하려면">💡 SEO를 잘하려면?</h3>
<h3 id="✅-잘-노출-되게-한다"><strong>✅ 잘 노출 되게 한다.</strong></h3>
<ol>
<li><p><strong>사이트 주소가 여기저기서 링크 되고 있어야 한다.</strong></p>
<ul>
<li>youtube도 올리고 페이스북도 올리고 인스타도 올리고 블로그도 쓰고 서로 링크하고
(너무 recursive하면 광고로 판단하고 blocking)</li>
</ul>
<ol start="2">
<li>각 사이트(유투브, 페이스북 등)의 제목과 내용의 단어 선택을 잘 해야한다!</li>
</ol>
</li>
<li><p><strong><code>&lt;head&gt;</code> 에 페이지 정보를 잘 작성한다.</strong></p>
<ul>
<li>meta 태그에 잘 작성해야한다.<ul>
<li><img src="https://images.velog.io/images/daeun-react/post/23198b87-c61f-416e-8162-ae4519de0587/meta.png" alt="meta-tag"></li>
</ul>
</li>
</ul>
</li>
<li><p><strong><code>robots.txt</code> 크롤러와 사이트의 약속</strong></p>
<ul>
<li><code>robots.txt</code>는 검색의 크롤링 로봇이 웹에 접근할 때 로봇이 지켜야하는 규칙과 사이트맵(sitemap.xml) 파일의 위치를 알려주는 역할을 하는 파일이다. <ul>
<li><code>allow</code> 할지, <code>disallow</code> 할지 작성한다.</li>
<li><img src="https://images.velog.io/images/daeun-react/post/4773604c-6f3b-47f1-bc51-dc0a231ad2fc/robots.png" alt="robots.txt"></li>
</ul>
</li>
</ul>
</li>
<li><p><strong><code>sitemap.xml</code> : (사이트 맵)</strong></p>
<ul>
<li><code>sitemap.xml</code> 파일은 검색 엔진 크롤링 로봇에게 웹 사이트에서 크롤링 해야 할 URL 을 전달한다. <ul>
<li>해당 사이트의 URL 모두를 XML 파일 형식으로 포함하는데 웹 사이트 운영자는 각 URL과 추가 정보로서 이 URL 콘텐츠의 최종 업데이트 시점 및 업데이트 빈도, 그리고 다른 URL 대비 상대적인 중요도 정보를 여기에 담을 수 있다. </li>
<li>사이트 맵을 지원하는 검색 엔진은 이 정보를 사용하여 웹 사이트 크롤링을 보다 효율적으로 할 수 있게된다. </li>
</ul>
</li>
<li><img src="https://images.velog.io/images/daeun-react/post/248ca664-6cb1-42f4-ac5e-67a93e0a501c/sitemap.png" alt="sitemap"></li>
</ul>
</li>
</ol>
<h3 id="✅-사이트를-컴퓨터가-이해할-수-있도록-만든다"><strong>✅ 사이트를 컴퓨터가 이해할 수 있도록 만든다.</strong></h3>
<p><strong>HTML5 Semantic Elements로 작성하기</strong></p>
<ul>
<li>페이지 이동 시 검색되길 바란다면 무조건 a 태그를 쓸 것!!!</li>
<li>&lt;h1~h6&gt; 태그 잘 활용하기!</li>
<li>img 태그 alt 설명 잘 달기</li>
<li>img 태그 사진 이름부터 잘 짓기</li>
<li>img 태그 위에 figure 추가</li>
<li>header, main, footer, nav, section, aside 등등 태그 잘 활용하기</li>
<li>caption 태그 활용해서 table 설명쓰기</li>
</ul>
<p><a href="https://developers.google.com/search/docs/beginner/seo-starter-guide?hl=ko&amp;visit_id=637664932657806093-2379697166&amp;rd=1">&gt; 자세한 SEO 가이드 링크</a></p>
<hr>
<h2 id="📌-웹의-역사와-발전">📌 웹의 역사와 발전</h2>
<ul>
<li>1세대 웹 - 전통적인 Web System Architecture. <strong>정적 웹.</strong></li>
<li>2세대 웹 - User Interaction 의 증가. <strong>동적 웹(자바스크립트)</strong></li>
<li>3세대 웹 - <strong>SPA</strong>(Single Page Application) - <strong>구별되기 시작하는 Frontend와 Backend</strong></li>
</ul>
<hr>
<h2 id="📌-spasingle-page-application">📌 SPA(Single Page Application)</h2>
<ul>
<li>하나의 파일로 전체 사이트를 구현 ➡ 하나의 html 페이지에서 전체 웹 사이트/서비스를 구현</li>
<li>HTML 태그 자체를 자바스크립트가 동적으로 생성</li>
</ul>
<p><strong>SPA in React...</strong></p>
<ul>
<li><code>npm run build</code> ➡ html 파일 하나 생김 (ex. AWS 배포할 때)</li>
<li>페이지를 이동하려고 하면  <code>&lt;div id=&quot;root&quot; /&gt;</code> 의 내용을 싹 교체하는 것. 
➡ 서버로부터 html 자체를 받아서 페이지를 바꾸는게 아니다.</li>
<li>페이지 이동 시 화면 깜빡임 X</li>
</ul>
<hr>
<h2 id="📌-csrclient-side-rendering">📌 CSR(Client Side Rendering)</h2>
<blockquote>
<p>** 🤔: 우리 사이트가 검색에 너무 안 걸리는걸? **
 ➡ Create React App(CRA)로 build한 프로젝트는 Only CSR(Client Side Render)로 실행되기 때문.</p>
</blockquote>
<ul>
<li><p><strong>웹 페이지의 렌더링이 클라이언트(브라우저) 측에서 일어나는 것을 의미</strong>.</p>
</li>
<li><p>브라우저는 최초 요청에서 html, js, css 확장자의 파일을 차례로 다운로드.
➡ 최초로 불러온 html의 내용은 비어있음. (html, body 태그만 존재)
➡ js 파일의 다운로드가 완료된 다음, 해당 js 파일이 dom을 빈 html 위에 그리기 시작.</p>
</li>
<li><p><strong>백엔드 호출을 최소화 할 수 있음</strong>
➡ 최초 호출 때만 html, js, css를 요청
➡ 이후에는 화면에서 변화가 일어나야 하는 만큼의 데이터만 요청 (ex. JSON)</p>
</li>
<li><p>라우팅(새로운 페이지로 이동)을 하더라도 html 자체가 바뀌는 것이 아니라 </p>
</li>
<li><p><em>JavaScript 차원에서 새로운 화면을 그려내는 것!*</em></p>
</li>
</ul>
<h3 id="💡-cra에서의-seo">💡 CRA에서의 SEO</h3>
<p><a href="https://github.com/nfl/react-helmet">&gt; react-helmet을 이용해서 meta 태그 수정</a></p>
<hr>
<h2 id="📌-ssr-server-side-rendering">📌 SSR (Server Side Rendering)</h2>
<blockquote>
<p><strong>🤔 : SPA의 장점을 살리면서 SEO도 같이 챙길 수는 없을까?</strong>
 ➡ SSR (Server Side Rendering)</p>
</blockquote>
<ul>
<li><p>SSR은 서버에서 <strong>첫 페이지의 렌더링을 클라이언트 측이 아닌 서버 측에서 처리해주는 방식</strong>.</p>
</li>
<li><p>CSR과 비교하면,</p>
<ul>
<li><p><strong>SEO 측면에서 유리</strong></p>
<ul>
<li>서버에서 사용자에게 보여줄 페이지를 모두 구성하여 사용자에게 보여주는 방식이기 때문에 CSR의 단점인 &quot;첫 페이지 깡통&quot; 상태를 극복할 수 있음.</li>
</ul>
</li>
<li><p><strong>UX 측면에서 유리</strong></p>
<ul>
<li>CSR에 비해 페이지를 구성하는 속도는 늦어지지만, 전체적으로 사용자에게 보여주는 콘텐츠 구성이 완료되는 시점은 빨라진다.</li>
</ul>
</li>
<li><p><strong>주의)</strong> 
페이지를 잘못 구성할 경우 <strong>CSR에 비해 서버 부하가 커지거나 / 첫 로딩이 매우 느려질 수 있음</strong></p>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="💡-csr-vs-ssr">💡 CSR vs SSR</h3>
<table>
<thead>
<tr>
<th align="center">CSR</th>
<th align="center">SSR</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><img src="https://images.velog.io/images/daeun-react/post/4aa74321-7b27-4b7e-b4ef-c1a923eb06dc/csr.png" alt="csr"></td>
<td align="center"><img src="https://images.velog.io/images/daeun-react/post/556ccaab-4ce6-45ec-9db1-7da3d8fe67eb/ssr.png" alt="ssr"></td>
</tr>
</tbody></table>
<hr>
<h2 id="📌-csr--ssr-➡-nextjs">📌 CSR + SSR? ➡ Next.js</h2>
<ul>
<li><p>그렇다면 SSR과 CSR을 섞어 쓸 수 있는 <code>Next.js</code>! </p>
</li>
<li><p>SSR의 CRA, 간단히 구성 가능</p>
</li>
<li><p><strong>SSR</strong>은 다음과 같은 <strong>요소로 구성된다</strong></p>
<ul>
<li>node.js로 구성된 FE 서버</li>
<li>pyhton, django로 되어 있는 BE 서버</li>
</ul>
</li>
<li><p><strong>다음과 같은 과정을 거쳐 SSR이 진행된다 (<a href="https://blueshw.github.io/2018/04/15/why-nextjs/">링크</a>)</strong></p>
<ol>
<li>유저가 브라우저에 <strong><code>/</code></strong>를 입력.</li>
<li>미리 실행되고 있는 FE 서버가 요청을 받고 서버사이드 렌더링.</li>
<li>만들어진 html 을 브라우저에게 보냄.</li>
<li>브라우저가 응답받은 html 을 그림.</li>
<li>html 에 기능을 부여할 <code>**index.js**</code>파일을 다운로드 받음. (hydration)</li>
<li>다운로드가 완료된 이후, <strong><code>go to second</code></strong> 링크를 클릭.</li>
<li><strong><code>/second</code></strong>로 라우팅하고 second 페이지 코드를 생성.</li>
</ol>
</li>
<li><p><strong>Next.js 장점</strong></p>
<ol>
<li>페이지 기반 라우팅 시스템 (동적 라우팅 지원)</li>
<li>pre-rendering , 페이지별 정적파일 생성과 서버사이드 렌더링 지원</li>
<li>코드 스플리팅</li>
<li>CSS, Sass 기본 지원 및 다른 CSS-in-JS 라이브러리 지원</li>
</ol>
</li>
</ul>
<hr>
<h2 id="📌-user-interaction-tracking-tools">📌 User Interaction Tracking Tools</h2>
<blockquote>
<p>그로스 해킹(Growth hacking) : <strong>성장(growth) + 해킹(hacking)</strong>이 결합된 단어
➡ 고객의 반응에 따라 제품 및 서비스를 수정해 제품과 시장의 궁합을 높이는 것을 의미
➡  온라인 행동 데이터를 분석하며 이를 바탕으로 <strong>사용자 경험을 최적화 하는 작업</strong></p>
</blockquote>
<p>그로스해킹은 </p>
<ul>
<li>고객의 웹사이트 방문 기록</li>
<li>머무른 시간</li>
<li>회원 가입으로 전환되는 비율 등 </li>
</ul>
<p>다양한 데이터를 기반으로 더 나은 서비스와 제품을 제공하기 위해 시도된다.</p>
<h3 id="💡-1-google-analytics">💡 1. Google Analytics</h3>
<p><img src="https://images.velog.io/images/daeun-react/post/7cf448f5-3b79-416e-b16c-b0ca16ef2a2e/google.png" alt="Google Analytics"></p>
<ul>
<li><p>GA는 구글에서 제공하는 <strong>무료 웹 분석 도구</strong></p>
</li>
<li><p>구글의 고유한 통계 및 머신러닝 기술로 사이트 및 모바일 어플리케이션 방문자들의 행동 데이터를 분석하고, 마케팅의 실적이나 웹사이트의 경험을 개선할 수 있도록 도와주는 도구</p>
</li>
<li><p>쉽게 말하면, 어떤 사용자가 우리 웹사이트를 방문하는지, 어떤 경로를 통해 방문했는지, 웹사이트에서 어떤 행동을 보이는지에 대한 흔적을 분석한 데이터를 뜻한다.</p>
</li>
</ul>
<h4 id="장점">장점</h4>
<ol>
<li>압도적인 점유율 ➡ 전 세계 로그 분석 도구 중 70%이상의 점유율을 차지하고 있다.</li>
<li>저렴한 서비스 비용 ➡ 구글 계정이 있다면 무료로 이용할 수 있다. </li>
<li>체계적인 분석 시스템 ➡ 웹사이트를 방문하는 고객 데이터를 100가지가 넘는 보고서를 이용해 제공하고 있다. 각종 유입 매체를 분석하고, 이벤트를 생성하여 상황에 맞게 데이터를 수집할 수 있다.</li>
</ol>
<h3 id="💡-2-mix-panel">💡 2. Mix Panel</h3>
<p><img src="https://images.velog.io/images/daeun-react/post/74c6da4f-e384-4325-b862-e199997919d3/mixpanel.png" alt="Mix-Panel"></p>
<ul>
<li><p>Mix Panel은 구글 애널리틱스의 &#39;개인 정보 보호 정책&#39; 때문에 제공되지 않는 <strong>사용자의 추적을 제공하는 분석 툴</strong></p>
</li>
<li><p>원하는 사용자를 지정하면 
해당 유저의 클릭스트림(한 사람이 인터넷에서 보내는 시간 동안 수행한 모든 클릭 정보) 데이터를 실시간으로 조회할 수 있는 기능을 제공</p>
</li>
<li><p>Mix Panel의 첫번째 목표는 사용자 고객들을 정의하는 것이고 
둘째는 웹사이트에서 고객들의 관여도를 측정(어떤 경로를 가지고, 어떤 행동을 했는지 추적)하는 것</p>
</li>
<li><p>참고로 믹스패널은 데이터 타입으로 과금이 되니 
모든 데이터를 트래킹 하는 것 보다 어떤 데이터를 우리가 어떻게 수집할 것인지 
설계를 해서 개발에 반영하는게 좋다.</p>
</li>
</ul>
<h3 id="💡-3-full-story">💡 3. Full Story</h3>
<ul>
<li><p>Full Story는 다른 도구들과 달리 <strong>사용자가 하는 행동에 대해 레코딩한다.</strong>
즉, 사용자가 버튼을 누르고, 다음 페이지로 이동하는 행동 <strong>모두 영상으로 저장</strong>된다. </p>
</li>
<li><p><code>dead click</code>(웹사이트에서 아무런 이벤트가 일어나지 않은 클릭)과 
<code>rage click</code>(빠르게 연속으로 행해진 클릭)을 정확히 찾아내면 사용자 인터페이스에 대한 잠재적인 개선 사항을 식별하는 데 도움이 될 수 있다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2021.09.02] Webpack & Babel]]></title>
            <link>https://velog.io/@daeun-react/2021.09.02-Webpack-Babel</link>
            <guid>https://velog.io/@daeun-react/2021.09.02-Webpack-Babel</guid>
            <pubDate>Fri, 10 Sep 2021 08:05:57 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-module">📌 module</h2>
<blockquote>
<p>✨ 웹팩은 <strong>모듈 번들러</strong>다!
➡ <strong>모듈</strong>에 대해 알아보자!</p>
</blockquote>
<h3 id="💡-모듈-정의">💡 모듈 정의</h3>
<p>자바스크립트에서의 모듈이란 기능 단위의 &quot;자바스크립트 개별 파일&quot;다.</p>
<ul>
<li>프로그램을 구성하는 단위</li>
<li>자신만의 독립적인 실행 영역</li>
<li>보통 파일 단위로 나뉨</li>
</ul>
<h3 id="💡-모듈패턴과-필요성">💡 모듈패턴과 필요성</h3>
<ul>
<li>자바스크립트의 소스를 모듈 단위로 관리하거나 라이브러리 등을 만들 때 사용</li>
<li>전역 변수의 사용을 최소화 하기 위함</li>
<li>변수 scope을 지정해서 사용하기 위함</li>
<li>Reusablility, Isolation, Organization</li>
<li>모듈 단위로 개발하면, 각 모듈 간의 의존성을 최소화하거나, 의존성 파악이 쉬움.</li>
</ul>
<h3 id="💡-라이브러리cra-없이-모듈-패턴-구현할-때는-어떻게-했나">💡 라이브러리(CRA) 없이 모듈 패턴 구현할 때는 어떻게 했나?</h3>
<pre><code class="language-jsx">// 이렇게 감싸서 하나의 모듈을 만들 수 있었다.
(function () {
  // scope가 막혀있기 때문에 전역변수가 생성되지 않는다.
  // 즉시 실행함수는 보통 일회용 코드
})();

// 모듈 또 하나
(function () {
    window.myLibrary = /* */;
}());

// 모듈 또 하나
(function () {
    var math = {
        add: function () {}
    }

    window.math = math;
}());</code></pre>
<h3 id="💡-모듈-시스템-라이브러리모듈-기능-표준화">💡 모듈 시스템 라이브러리(모듈 기능 표준화)</h3>
<h4 id="✅-commonjs">✅ CommonJS</h4>
<ul>
<li>실행구문 : module.export, require</li>
<li>Node.js에서 사용</li>
</ul>
<h4 id="✅-es6-module">✅ ES6 Module</h4>
<p>자바스크립트를 이용하는 웹페이지의 코드가 복잡해지기 시작하면서,
효율적인 소스 관리가 필요해져서 이제는 모듈을 정의하는 것 또한 표준으로 정의되었다.</p>
<ul>
<li>실행구문 : export, import </li>
<li>CRA에서 사용</li>
</ul>
<p>❗ 아직 IE지원이 안되므로, 모듈을 사용하려면 babel, webpack이 필요하다.
 <code>babel</code>은 ES6 → 브라우저에서 사용할 수 있도록 모듈을 commonjs로 바꿔주고,
 <code>webpack</code>은 모듈간의 의존성을 파악하여 자바스크립트 코드를 bundle(합쳐) 해준다.</p>
<hr>
<h2 id="📌-webpack">📌 webpack</h2>
<blockquote>
<p>✨ 웹팩은 <strong>모듈 번들러</strong>다!
➡ 모듈을 알아봤으니 <strong>번들러</strong>에 대해 알아보자!</p>
</blockquote>
<h3 id="💡-번들러bundler">💡 번들러(bundler)</h3>
<ul>
<li>번들이란, 여러 파일 여러 구성을 합치는 것을 말한다.</li>
<li>모듈화된 파일들을 하나로 묶어 관리해야하기 때문에, 번들러의 역할이 중요해졌다.</li>
<li>모듈 간의 의존성을 파악하여 하나의 파일로 만들어 준다.</li>
<li><code>npm run build</code> 후에 하나의 자바스크립트 파일로 나온 결과물이 번들러의 결과물!</li>
<li>ex) webpack, RequireJS, Rollup, Parcel</li>
</ul>
<p><img src="https://images.velog.io/images/daeun-react/post/738f91f0-93aa-4f29-bf52-cf33f3c7cdc1/webpack.png" alt="bundler"></p>
<p>➡ 왼쪽의 서로 종속 관계인 파일들을 웹팩을 통해 하나로 깔끔하게 모아준다!!</p>
<h3 id="💡-만약에-번들러가-없었다면">💡 만약에 번들러가 없었다면?</h3>
<ol>
<li><p>파일 하나하나 HTTP 통신을 통해 서버에 요청이 생긴다.
 ➡ js 파일이 올 때까지 기다리기 때문에 화면 로딩시간이 오래 걸린다.
 ➡ one by one으로 파일을 요청하고 응답받기 때문에 파일 개수가 많아질수록 요청이 많아진다.</p>
</li>
<li><p>파일이 서로 종속 관계를 가지고 있는 경우, 파일의 로드 순서가 중요해진다.
➡ 웹팩이 모듈의 종속(dependecy) 관계를 파악하고 알아서! 잘 하나의 파일로 만들어준다.</p>
</li>
</ol>
<h3 id="💡-결론-웹팩의-역할">💡 결론, 웹팩의 역할!</h3>
<ul>
<li>웹팩은 js 파일 뿐만 아니라, img, css, mp4 등 다양한 리소스를 모두 모듈로 관리하여 서로의 의존성을 관리해준다.</li>
<li>또 웹팩은 개발 단계에서 사용하는 <code>dev server</code>, 
필요할 때 import하는 <code>dynamic import</code>, 
모듈을 하나의 파일로 만들지 않고 의존성을 따져 나눠서 빌드하는 <code>code spliting</code> 등을 지원한다.</li>
</ul>
<p><img src="https://images.velog.io/images/daeun-react/post/22ae56f8-e459-4508-b7ff-5f452a0ae5b7/webpack_.jpg" alt="webpack"></p>
<hr>
<h3 id="💡-webpack---entry--output">💡 webpack - entry &amp; output</h3>
<pre><code class="language-bash">yarn add webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react -D
yarn add react react-dom</code></pre>
<pre><code class="language-jsx">// webpack.config.js
const path = require(&#39;path&#39;);

const config = {
  entry: &#39;./src/index.js&#39;,
  output: {
    path: path.resolve(__dirname, &#39;build&#39;),
    filename: &#39;bundle.js&#39;
  }
};

module.exports = config;</code></pre>
<ul>
<li><p><strong><code>entry</code></strong>: 이 프로젝트가 어느 파일에서 시작할지 entry 프로퍼티에 경로를 지정</p>
</li>
<li><p><strong><code>output</code></strong>: webpack이 적용된 결과파일을 어느 위치에, 어떤 파일이름으로 생성할지 지정</p>
</li>
</ul>
<hr>
<h3 id="💡-webpack---loader">💡 webpack - loader</h3>
<ul>
<li><strong><code>loader</code></strong>: 파일을 전처리(preprocess) 해주는 것인데, 이 때 파일은 모듈을 뜻하며 js 파일 뿐만 아니라 img, css, csv 등 모든 정적 리소스를 포함한다. loader는 모듈을 입력 받아서, 새로운 모듈로 출력하고 번들링 할 수 있다.</li>
</ul>
<h4 id="✅-babel-loader">✅ <strong>babel-loader</strong></h4>
<ul>
<li>자바스크립트 파일을 처리한다. 예를 들어 jsx 문법으로 작성된 리액트 코드를 처리할 때도 필요하다.</li>
<li>js 확장자를 갖는 모듈은 babel-loader가 처리하도록 설정한다.<pre><code class="language-jsx">// webpack.config.js
module: {
rules: [
 {
   test: /\.js$/,
   exclude: /node_modules/,
   use: [&#39;babel-loader&#39;]
 }
]
}
</code></pre>
</li>
</ul>
<p>//babel.config.js
//babel 세팅도 해야한다. @babel/preset-react 프리셋을 사용하도록 설정
const presets = {
  presets: [&quot;@babel/preset-react&quot;]
};</p>
<p>module.exports = presets;</p>
<pre><code>

#### ✅ **css-loader**
  - css 파일을 모듈로 사용할 수 있도록 해준다.
```bash
yarn add sass-loader css-loader mini-css-extract-plugin sass -D</code></pre><pre><code class="language-jsx">{
  test: /\.(sa|sc)ss$/,
  use: [
    MiniCssExtractPlugin.loader,
    &#39;css-loader&#39;,
    &#39;sass-loader&#39;
  ]
}</code></pre>
<h4 id="✅-file-loader">✅ <strong>file-loader</strong></h4>
<ul>
<li>file-loader를 사용하지 않으면 root 경로에 모든 파일이 번들된다.</li>
<li>개발모드에서 사용한 경로대로 그대로 파일이 번들되길 바라면 file-loader를 사용하자. </li>
<li>name설정을 하지 않으면 파일 이름에 해시값이 포함되며 브라우저 캐싱효과를 활용할 수 있다. </li>
</ul>
<pre><code class="language-jsx">{
    test: /\.(png|jpe?g|gif|svg)$/i,
    use: [
      {
        loader: &#39;file-loader&#39;,
        options: {
          name: &#39;[path][name].[ext]&#39;
        }
      }
    ]
}</code></pre>
<hr>
<h3 id="💡-webpack---plugin">💡 webpack - plugin</h3>
<ul>
<li>plugin은 로더보다 강력한 기능을 갖는다. </li>
<li>loader는 특정 모듈에 대한 처리만 담당하지만, plugin은 웹팩이 실행되는 전체 과정에 개입할 수 있다.</li>
</ul>
<pre><code class="language-jsx"> plugins: [
    new MiniCssExtractPlugin({
      filename: &#39;[name].css&#39;,
      chunkFilename: &#39;[id].css&#39;
    }),
    new HtmlWebpackPlugin({
      template: &#39;./public/index.html&#39;,
            output: &#39;index.html&#39;
    }),
]</code></pre>
<ul>
<li><code>HtmlWebpackPlugin</code>는 html 파일에 script 태그를 추가하여 번들된 js 파일을 주입한다.</li>
</ul>
<hr>
<h3 id="💡-webpack---mode">💡 webpack - mode</h3>
<h4 id="✅-development">✅ development</h4>
<ul>
<li>개발 단계</li>
<li>소스맵 제공</li>
</ul>
<h4 id="✅-production">✅ production</h4>
<ul>
<li>배포용</li>
<li>코드 minify, uglify</li>
<li>최적화(tree shaking)로 번들된 파일 크기를 작게</li>
</ul>
<pre><code class="language-jsx">//package.json
&quot;scripts&quot;: {
    &quot;start&quot;: &quot;react-scripts start&quot;,
    &quot;start:dev&quot;: &quot;REACT_APP_ENV=dev react-scripts start&quot;,
    &quot;start:staging&quot;: &quot;REACT_APP_ENV=staging react-scripts start&quot;,
    &quot;test-start&quot;: &quot;yarn test --watchAll=false &amp;&amp; react-scripts start&quot;,
    &quot;build&quot;: &quot;react-scripts build&quot;,
    &quot;build:dev&quot;: &quot;REACT_APP_ENV=dev react-scripts build&quot;,
    &quot;build:staging&quot;: &quot;REACT_APP_ENV=staging react-scripts build&quot;,
    &quot;build:production&quot;: &quot;REACT_APP_ENV=production react-scripts build&quot;,
    &quot;test&quot;: &quot;react-scripts test&quot;,
    &quot;test-all&quot;: &quot;react-scripts test --watchAll=false&quot;,
    &quot;eject&quot;: &quot;react-scripts eject&quot;,
    &quot;storybook&quot;: &quot;start-storybook -p 6006 -s public&quot;,
    &quot;build-storybook&quot;: &quot;build-storybook -s public&quot;
  },


// 사용 예제
const PRODUCTION_URL = &#39;https://api.co.kr&#39;;
const STAGING_URL = &#39;https://staging.api.co.kr&#39;;
const DEV_URL = &#39;https://dev.api.co.kr&#39;;
const LOCAL_URL = &#39;http://100.28.2.17:3000&#39;;

let uri;

switch (process.env.REACT_APP_ENV) { // REACT_APP_ENV
  case &#39;production&#39;:
    uri = PRODUCTION_URL;
    break;
  case &#39;staging&#39;:
    uri = STAGING_URL;
    break;
  case &#39;dev&#39;:
    uri = DEV_URL;
    break;
  default:
    uri = LOCAL_URL;
}

const httpLink = createHttpLink({
  uri,
});

export default httpLink;    </code></pre>
<hr>
<h2 id="📌-babel">📌 Babel</h2>
<blockquote>
<p>Babel은 <strong>JavaScript 컴파일러</strong>입니다.</p>
</blockquote>
<h3 id="💡-컴파일러">💡 컴파일러</h3>
<p>➡ 사람이 읽기 편한 프로그래밍 언어에서 컴퓨터가 읽기 편한 코드로 바꿔주는 것</p>
<h3 id="💡-바벨이-필요한-이유">💡 바벨이 필요한 이유</h3>
<ul>
<li>바벨을 새로운 자바스크립트 버전을 어느 브라우저에서나 사용할 수 있도록 ES5 버전으로 변환해 준다.</li>
<li>브라우저는 아직 새로운 자바스크립트 버전을 맞이할 준비가 안되어 있는데, 개발자가 새로운 버전으로 효율적으로 문법을 미리 사용할 때, 바벨이 변환해 줘서 동작하는 것!</li>
<li>create react app으로 개발할 때 아직 브라우저가 받아드리지 못하는 최신 메서드들이 있는데 이미 CRA에서 바벨 설정이 되어있었기 때문에 마음껏 최신 문법을 사용할 수 있었다.</li>
<li>(+JavaScript나 Python은 컴파일 언어가 아니며, 사람이 쓴 대로 컴퓨터가 해석하는 &quot;인터프리터 언어&quot;라고 부른다. 그럼 왜 컴파일 언어가 아닌데 왜 컴파일러라고 부르는지? )
  ➡ 자바스크립트에서 자바스크립트로 변환하는거고, 높은 버전에서 낮은 버전으로만 바벨이 변환을 시켜주는 것이기 때문에 정확한 표현은 아니지만 의미상 컴파일러라고 사용한다. 트랜스 파일러라고 말하는 사람도 있다.</li>
</ul>
<h3 id="💡-바벨과-관련된-필수-module">💡 바벨과 관련된 필수 module</h3>
<ul>
<li><code>babel-loader</code>: 바벨과 웹펙이 어떻게 동작하는지</li>
<li><code>@babel/core</code>: babel로 컴파일해서 결과물 파일이 나오도록 babel 관련한 핵심 모듈</li>
<li><code>@babel/preset-env</code>: ES2015?6?7 등 어떤 버전을 쓸지에 관한 모듈</li>
<li><code>@babel/preset-react</code>: jsx를 js로!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2021.08.30] Redux-saga, Context API, Responsive Web, Cross Browsing]]></title>
            <link>https://velog.io/@daeun-react/2021.08.30-Redux-saga-Client-%EC%8B%A4%EB%AC%B4-%EA%B0%9C%EB%B0%9C</link>
            <guid>https://velog.io/@daeun-react/2021.08.30-Redux-saga-Client-%EC%8B%A4%EB%AC%B4-%EA%B0%9C%EB%B0%9C</guid>
            <pubDate>Fri, 10 Sep 2021 05:41:22 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-redux-saga">📌 Redux-saga</h2>
<p>➡ Redux에서 action을 dispatch하면 바로 state가 변경되어, 비동기 처리가 불가능하다.
➡ <strong>비동기 처리를 위해 Redux-thunk, Redux-saga 등장!</strong></p>
<p><img src="https://images.velog.io/images/daeun-react/post/b60a1c81-ed05-46dd-8226-4d26dc698844/redux-saga.png" alt="Redux-saga"></p>
<p>➡ Redux-saga는 비동기의 다양한 상황을 처리하기 좋고, 
&nbsp;&nbsp;&nbsp;&nbsp; 테스트나 디버깅이 쉽기 때문에 많이 이용되는 추세</p>
<h3 id="💡-middleware">💡 middleware</h3>
<ul>
<li>Redux에서 미들웨어는 <strong>action을 dispatch하고, reducer에서 state가 변경 되기 전!!</strong>
이 사이에서 여러 작업을 할 수 있다. (로그 남기기, 비동기 처리 등)</li>
</ul>
<h3 id="💡-generator-es6">💡 generator (ES6)</h3>
<ul>
<li>generator함수를 만들 때는 <code>function*</code> 키워드를 사용한다<pre><code class="language-jsx">function* generateNumber() {
yield 1;
yield 2;
return 3;
}
</code></pre>
</li>
</ul>
<p>const generator = generateNumber();</p>
<p>console.log(generator.next().value) // 1
console.log(generator.next().value) // 2
console.log(generator.next().value) // 3
console.log(generator.next().value) // undefined</p>
<pre><code>
- redux-saga에서의 **`saga`**가 generator 함수를 의미함
- generator 기반으로 비동기 작업을 관리함
- generator 함수에서 action에 따른 작업을 yield

### 💡 Redux-saga &gt; side effect
- side effect는 (부정적인 의미의) 부작용이 아니라, 부수효과를 의미한다.
- 다양한 기능들이 있기 때문에 구현하고 싶은 기능에 따라 사용하면 된다.
![redux-saga](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F824737e0-aa59-42ec-963e-7390db66c01d%2FUntitled.png?table=block&amp;id=c0518f2e-9326-40ed-b4c7-951ac8a58230&amp;spaceId=4b97eaca-7938-4c43-b27c-a0c55795a841&amp;width=670&amp;userId=c2939493-d597-43bd-b1dd-7e1eab005a87&amp;cache=v2)
- `takeEvery`: 모든 액션을 유효하게 인정
- `takeLatest`: 마지막 액션 하나만 유효하게 인정

---

## 📌 Context API
&gt; **React에서 공식적으로 전역상태를 관리할 수 있는 Context API를 제공**
React 자체 전역상태 관리 API이기 때문에 최근 새로운 프로젝트에 굉장히 많이 도입되고 있다.
Redux, react-router, styled-components 오픈소스를 보면 Context API를 사용하고 있다!

### ✅ Provider : 전역 상태 정의 및 전역 상태를 update하는 로직이 존재
- Provider는 context를 구독(Consumer)하는 컴포넌트들에게 **context의 변화를 알린다.**

- Provider 하위에 있는 컴포넌트 중에 context를 구독(Consumer)하는 부분이 Provider의 value가 바뀔때마다 다시 렌더링 된다.
➡ Provider 하위에 있다고 value가 업데이트 될 때마다 모든 컴포넌트가 다시 렌더링 되는게 아니다! 
➡ context를 구독이 포함되어 있는 컴포넌트도 다시 렌더링 되는게 아니다! 
➡ 오직 context.Consumer 부분만 rerender 된다.

- 당연히!! Provider 컴포넌트 외부에 있는 컴포넌트에는 변화를 감지하지 못한다.


### ✅ Consumer : 전역 상태 사용
- `useContext`를 사용하면 훨씬 편하게 사용 가능하다.

---

### 💡 Context API 예시

- context에 로그인 여부를 저장하는 `auth`와 상태를 변경하는 함수인 `setAuth`를 추가
- 로그인 페이지에서 정상적으로 로그인되면 `setAuth` 함수를 사용하여 `auth` 값을 true로 바꿔줌

```jsx
//AuthContext.js
import { createContext, useEffect, useState } from &#39;react&#39;;
import { login } from &#39;./AuthService&#39;;

const AuthContext = createContext({}); // 1️⃣

export const AuthProvider = ({ children }) =&gt; {   // 4️⃣
  const [auth, setAuth] = useState(false);

  useEffect(() =&gt; {
    setAuth(login());  // 3️⃣
  }, []);

  return (
    &lt;AuthContext.Provider value={{ auth, setAuth }}&gt;  // 2️⃣
      {children}
    &lt;/AuthContext.Provider&gt;;
};

export const AuthConsumer = AuthContext.Consumer;  // 4️⃣
export default AuthContext;  // 4️⃣</code></pre><p><strong>코드설명</strong></p>
<ol>
<li><p><code>createContext</code>는 초기 값을 매개변수로 받는데 필수는 아니다.
➡ 작성해도 2. provider를 정의하는 곳에서 덮어 씌워지기 때문에 작성하지 않았다.</p>
</li>
<li><p>Provider에서 사용할 <code>auth</code>(로그인 여부)와 로그인 여부를 업데이트 해주는 <code>setAuth</code> 함수를 넣는다.</p>
</li>
<li><p>최초(현재) 로그인 여부 파악</p>
</li>
<li><p><code>AuthContext</code>, <code>AuthProvider</code>, <code>AuthConsumer</code>를 나누어서 export하였다. (context/provider/consumer를 한 파일에서 관리하고, 아래와 같이 사용하기 위해서)</p>
<pre><code class="language-jsx">import AuthContext, { AuthProvider, AuthConsumer } from &#39;./AuthContext&#39;;</code></pre>
</li>
</ol>
<hr>
<h2 id="📌-responsive-web">📌 Responsive Web</h2>
<blockquote>
<p>반응형 웹이란, 하나의 웹사이트에서 PC, 스마트폰, 태블릿 PC 등 접속하는 <strong>디스플레이의 종류에 따라 화면의 크기가 자동으로 변하는 웹 페이지</strong>를 의미.
IT 기기의 종류가 더욱 다양해짐에 따라 디스플레이의 크기에 맞게 유동적으로 반응하는 반응형 웹을 구현하는 것이 더욱 중요해졌다.</p>
</blockquote>
<h3 id="💡-breakpoint">💡 Breakpoint</h3>
<p><img src="https://images.velog.io/images/daeun-react/post/78170de1-6d35-47a1-aa5e-45537982bc38/responsive-web.png" alt="Breakpoint"></p>
<ul>
<li>보통 2개 - 1024 / 768</li>
<li>관리 편하게 하려면 1개 - 768</li>
</ul>
<h3 id="💡-media-query">💡 Media Query</h3>
<pre><code class="language-css">@media only screen and (max-width: 480px) {
    body {
        font-size: 12px;
    }
}</code></pre>
<ul>
<li><code>@media</code> : media 쿼리 시작</li>
<li><code>only screen</code> : 어떤 디바이스에서 적용하는지 알려준다. <ul>
<li><code>only screen</code> : 어떤 디바이스이던지 상관없이, 화면에 보이는 스크린이기만 하면 전부 적용</li>
<li><code>only print</code> : 프린트를 하고싶을 때 적용</li>
</ul>
</li>
<li><code>and (max-width : 480px)</code> : media feature라고 불리는 부분, 조건 작성하기</li>
</ul>
<h3 id="💡-scss에서-관리-쉽게-하기">💡 SCSS에서 관리 쉽게 하기</h3>
<pre><code class="language-scss">/* mediaQuery.scss */
$phone: &quot;only screen and (max-width: 768px)&quot;;
$desktop: &quot;screen and (min-width: 769px)&quot;;

@import &#39;./mediaQuery.scss&#39;;
.big-box {
    @media #{$phone} {
        display: none;
    }

    @media #{$desktop} {
        display: block;
    }
}</code></pre>
<hr>
<h2 id="📌-cross-browsing">📌 Cross Browsing</h2>
<blockquote>
<p><strong>웹사이트가 어느 버전의 브라우저에서나, 어느 디바이스에서도 원하는 결과물이 나오도록 확인하고 수정하는 단계</strong>
➡ <strong>ie, chrome, safari</strong>는 기본이고, 모바일에서 <strong>카카오톡 웹뷰</strong>, <strong>네이버 웹뷰</strong>에서도 잘 뜨는지 직접 꼭 확인해야 한다!</p>
</blockquote>
<h3 id="💡-css-확인하기">💡 CSS 확인하기</h3>
<ul>
<li>ie에서 생각보다 많은 CSS property를 지원하지 않는다.</li>
<li><a href="https://caniuse.com/">can i use</a> 에서 확인해보거나, 
  해당 property 이름 + ie 조합으로 검색해서 답변을 바로 찾기!</li>
<li>한번에 지원해주는 라이브러리가 있긴 하지만, 웬만하면 직접 수정하는 것이 좋다.</li>
</ul>
<h3 id="💡-ie-polyfill-적용하기">💡 IE polyfill 적용하기</h3>
<ul>
<li><p><strong>step1. <code>react-app-polyfill</code> 설치</strong></p>
<pre><code class="language-bash">yarn add react-app-polyfill</code></pre>
</li>
<li><p><strong>step2. polyfill import</strong></p>
<pre><code class="language-jsx">// These must be the first lines in src/index.js
import &#39;react-app-polyfill/ie11&#39;;
import &#39;react-app-polyfill/stable&#39;;</code></pre>
</li>
<li><p><strong>step3. <code>node_modules/.cache</code> 삭제</strong></p>
</li>
</ul>
<ul>
<li><strong>step4. package.json <code>browserslist</code>에 ie 11 추가</strong><pre><code class="language-bash">&quot;browserslist&quot;: {
    &quot;development&quot;: [
      &quot;last 1 chrome version&quot;,
      &quot;last 1 firefox version&quot;,
      &quot;last 1 safari version&quot;,
      &quot;ie 11&quot;
    ]
  }</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Assignment 8 회고록] 모두 컴퍼니 
- TS 기반 투두리스트와 animation]]></title>
            <link>https://velog.io/@daeun-react/Assignment-8-%EB%AA%A8%EB%91%90-%EC%BB%B4%ED%8D%BC%EB%8B%88-typescript-TodoListDrag-and-Drop</link>
            <guid>https://velog.io/@daeun-react/Assignment-8-%EB%AA%A8%EB%91%90-%EC%BB%B4%ED%8D%BC%EB%8B%88-typescript-TodoListDrag-and-Drop</guid>
            <pubDate>Sun, 29 Aug 2021 16:17:30 GMT</pubDate>
            <description><![CDATA[<h3 id="🔗-github">🔗 <a href="https://github.com/TEAM-8ight/modu-todo">Github</a></h3>
<h3 id="🔗-배포-링크">🔗 <a href="https://modu-8ight.netlify.app/">배포 링크</a></h3>
<h3 id="🔗-피그마-링크">🔗 <a href="https://www.figma.com/file/6QwW9HSCuVP9FySUV9O0vJ/modu-todo">피그마 링크</a></h3>
<hr>
<ul>
<li><p>이번 과제는 4명의 팀원이 <strong>각자 브랜치 생성 ➡ PR 생성 ➡ 코드리뷰 ➡ 수정 ➡ 머지</strong>의 과정을 거쳐 협업하여 진행했습니다.😊</p>
</li>
<li><p>과제를 마치고, 총 16개의 조 중에 <strong>제일 우수한 프로젝트로 평가</strong> 받아서 기분이 매우 좋습니다.🎉 </p>
</li>
<li><p><strong>코드 리뷰 또한 좋은 예시로 선정</strong>되었습니다.🎉</p>
</li>
</ul>
<p><img src="https://images.velog.io/images/daeun-react/post/4141f2c7-502d-4620-ae19-0061c01240d7/code_review.png" alt=""></p>
<hr>
<h3 id="과제를-끝내고-회고-내용">과제를 끝내고 회고 내용</h3>
<h3 id="🔰-git--코드-리뷰와-브랜치-관리">🔰 <code>Git</code> &gt; 코드 리뷰와 브랜치 관리</h3>
<ul>
<li><p>프리온보딩 과정을 하면서 Live Share를 통한 협업을 여러번 진행했는데, 이번 과제는 Live Share 기능을 사용하지 않고, 각자 분담된 기능을 브랜치로 만들고 PR을 올리면 모든 팀원이 코드 리뷰 하는 방식으로 진행되었다.</p>
</li>
<li><p>한 달 넘게 같이한 팀원들과 익숙해졌는데, 새로 조가 바뀌면서 상혁님, 이슬님, 준희님과 git 컨벤션이라던지, 이슈 관리, 브랜치 및 PR 관리 등 어떻게 해야할지 처음부터 다시 정하는 시간을 가졌다.</p>
</li>
<li><p>*<em>코드 리뷰! *</em>
➡ Git에  팀원분들이 PR을 올리면, 꼼꼼하게 코드를 보려고 노력했다. 이해가 안되면 서로 설명을 해주고 피드백을 주고 받았다. 코드 리뷰가 너무 좋았던게 내가 미쳐 생각하지 못했던 부분을 말씀해주셔서 생각해보고 더 좋은 방향으로 리팩토링을 진행할 수 있었다. (물론 구현해야 할 남은 기능도 있는데, 현재 기능을 리팩토링 한다고 밤을 새웠지만...그래도 팀원분들이 더 쉽게 이해하고 사용하시는 걸 보니 뿌듯했다!)</p>
</li>
</ul>
<h3 id="🔰-애니메이션-기능칸반보드-형태의-drag-and-drop">🔰 애니메이션 기능(칸반보드 형태의 Drag and Drop)</h3>
<ul>
<li><p>Drag and Drop 기능은 처음 사용해봤다. 사실 이벤트 리스너를 통해서 기능을 구현할 수 있다는 것 조차 몰랐었다..</p>
</li>
<li><p>기능을 구현하기 전, 구글링을 통해 예시 코드를 참고하고 상하로 리스트를 움직이는 법에 대해서 공부했다. 
그러나! <strong>우리의 투두리스트는 칸반보드 형태로 상태에 따라 좌우로도 움직여야 했다.</strong> 기존 코드에서 보다 더 복잡해졌지만 다들 해본 적 없는 기능에 도전정신을 가지며 즐겁게 과제를 진행하였다. </p>
</li>
</ul>
<p><img src="https://images.velog.io/images/daeun-react/post/331d7484-4f56-4b60-b82c-66792dd19768/image.png" alt="칸반보드형태"></p>
<h3 id="🔰-전역상태에서-관리하는-모달창">🔰 전역상태에서 관리하는 모달창</h3>
<ul>
<li><p>위에서 말한, 코드리뷰를 통해 리팩토링한 기능이다. <code>Portal</code>을 사용해서 모달창 기능을 구현했고, 투두리스트 수정 버튼을 클릭하면 모달창이 생성되는 구조라서, 처음에는 수정 버튼이 있는 곳에 모달 관련 컴포넌트를 넣었다.</p>
</li>
<li><p>그런데 투두리스트를 생성할 때, 입력 validation을 만족하지 못하면 모달창을 재사용 했으면 좋겠다는 의견을 받았다.</p>
</li>
<li><p><code>Context API</code>를 활용하여 <code>dispatch(nodal(&quot;띄울 모달명&quot;))</code>으로 띄울 모달명을 셋팅하면, <code>App.tsx</code> 에서 모달명에 맞는 화면을 보여줄 수 있도록 변경했다. 
리팩토링 한 결과 팀원분들이 머지 후 쉽게 모달창을 띄울 수 있게 되었다!</p>
</li>
</ul>
<h3 id="🔰-사용자를-위한-디자인-설계">🔰 사용자를 위한 디자인 설계</h3>
<ul>
<li><p>과제를 처음 받고 내용을 읽어보니, 글로만 읽고 구현하면 서로 다르게 이해한 부분이 생길 수 있겠다 하는 생각이 들었다. 또 새로운 조편성으로 팀원들이 바뀌다보니 말로만 의견을 전달하면 서로 잘못 이해하는 기능이 생기지 않을까 염려되었다.</p>
</li>
<li><p>그래서 모두가 피그마에 접속해, 우리가 구현하고자 하는 칸반보드 형태의 투두리스트를 만들어 보았다. 사실 피그마를 전문적으로 사용하지는 못하는데, 팀원분 중에 디자이너로 일하셨던 분이 계셔서 많은 도움을 받았다.</p>
</li>
<li><p>PR을 올리고 머지하면서 느낀점은, 모든 팀원분들이 정말 피그마와 동일하게 만들어주셨다!😊</p>
</li>
<li><p>과제를 제출하기 전, 4명이서 모두 Live Share로 같은 코드를 보면서 수정해야할 부분에 대해 의논하고 리팩토링을 진행하였는데, 특히 디자인 관련해서 &quot;사용성을 위해 svg 버튼에 패딩주기 또는 색상 선정을 위한 팁&quot; 등 디테일 한 부분까지 말씀해주셔서 많은 도움이 되었다.</p>
</li>
</ul>
<hr>
<h3 id="과제-내용">과제 내용</h3>
<p><strong>[공통]</strong></p>
<ul>
<li>TypeScript 사용</li>
<li>데이터는 로컬의 dummy data 로 자유롭게 구성할 것 (format: <strong><code>json</code></strong>)</li>
<li>UI 라이브러리 사용하지 않을 것을 권장</li>
</ul>
<p><strong>[상세기능]</strong></p>
<ul>
<li>스크롤 시 Header 고정</li>
<li>투두리스트에 적합한 타입 구성</li>
<li>Task 목록 조회, 새로운 Task 추가, Task 삭제, Task 수정</li>
<li>Task 상태 변경(시작전,진행중,완료)</li>
<li>Task 필터링(상태, 생성일, 생성자, 중요도) : 최소 두가지 이상 조건으로 필터링</li>
<li>투두리스트에 적절한 애니메이션을 추가
➡ Drag &amp; Drop 애니메이션 구현</li>
</ul>
<hr>
<h3 id="구현-내용">구현 내용</h3>
<h3 id="🔰-drag--drop-기능">🔰 Drag &amp; Drop 기능</h3>
<p>➡ 기존에 진행했던 투두리스트와 다른 점인 애니메이션(Drag &amp; Drop) 부분 구현한 내용을 작성</p>
<p>** 📌 1. Drag &amp; Drop 기능을 커스텀 훅으로 생성해서 관리하고자 했다. **</p>
<ul>
<li><code>handleDragStart</code> : 사용자가 요소를 끌어 시작할 때 발생</li>
<li><code>handleDragEnter</code> : 드롭 타겟 들어가면 이벤트가 발생</li>
<li><code>handleDragOver</code> : 드롭 타겟 위에 드래그되는 경우에 이벤트가 발생</li>
<li><code>handleDragLeave</code> : 드래그 요소가 드롭 대상을 떠날 때 발생</li>
</ul>
<pre><code class="language-jsx">// utils/hooks/useTodoItemDnD.ts 파일 생성

import { useState } from &#39;react&#39;;

export const useTodoItemDnD = (id: number) =&gt; {
  const [isDragging, setisDragging] = useState(false);
  const [isDragOver, setIsDragOver] = useState(false);

  const handleDragStart = (e: React.DragEvent&lt;HTMLDivElement&gt;) =&gt; {
    setisDragging(true);
    e.dataTransfer.effectAllowed = &#39;move&#39;;
    e.dataTransfer.setData(&#39;text/plain&#39;, `${id}`);
  };

  const handleDragEnter = () =&gt; {
    setIsDragOver(true);
  };

  const handleDragOver = (e: React.DragEvent&lt;HTMLDivElement&gt;) =&gt; {
    e.preventDefault();
    setIsDragOver(true);
  };

  const handleDragLeave = () =&gt; {
    setIsDragOver(false);
  };

  return {
    isDragging,
    isDragOver,
    handleDragStart,
    handleDragEnter,
    handleDragOver,
    handleDragLeave,
    setIsDragOver,
  };
};
</code></pre>
<p>** 📌 2. <code>TodoItem</code> 컴포넌트를 감싸는 최상단에 <code>useTodoItemDnD</code> 관련 이벤트 리스너를 등록한다.**</p>
<pre><code class="language-jsx">// TodoItem.ts

import { useTodoItemDnD } from &#39;utils/hooks&#39;;
...

const {
    isDragOver,
    handleDragStart,
    handleDragOver,
    handleDragEnter,
    handleDragLeave,
    setIsDragOver,
} = useTodoItemDnD(todo.id);

  ...


const handleDrop = (e: React.DragEvent&lt;HTMLDivElement&gt;) =&gt; {
    setIsDragOver(false);
    const movingTarget = e.dataTransfer.getData(&#39;text/plain&#39;);
    dispatch(swap({first: +movingTarget, second: todo.id})); // ✅
};
  ...

&lt;ItemContainer
        draggable
        isDragOver={isDragOver}
        onDragStart={handleDragStart}
        onDragOver={handleDragOver}
        onDragEnter={handleDragEnter}
        onDragLeave={handleDragLeave}
        onDrop={handleDrop}
&gt;
       ...
&lt;/ItemContainer&gt;</code></pre>
<p>** 📌 3. reducer에서 <code>dispatch(swap())</code> 액션이 실행될 경우, Todo의 상태에 따라 순서를 변경하거나 state를 변경한다.**</p>
<pre><code class="language-jsx">// context/TodoContext/reducer.ts

export default function reducer(state: IState, action: Action): IState {
  const { type, payload } = action;
  switch (type) {
    ...
    case SWAP:
      return { ...state, todos: swapTodos(state.todos, payload) }; // ✔
    ...
    default:
      return state;
  }
}

...

const swapTodos = (prevTodos: ITodos, payload: ISwap): ITodos =&gt; { // ✔
  const { first: firstId, second: secondId } = payload;
  if (firstId === secondId) return prevTodos;

  const firstTodo = prevTodos.find((todo) =&gt; todo.id === firstId);
  const secondTodo = prevTodos.find((todo) =&gt; todo.id === secondId);
  if (!firstTodo || !secondTodo) return prevTodos;

  if (firstTodo.status === secondTodo.status) { 
    // ✅ Todo의 상태가 동일하여 상하로 움직인 경우
    const firstIndex = prevTodos.findIndex((todo) =&gt; todo.id === firstId);
    const secondIndex = prevTodos.findIndex((todo) =&gt; todo.id === secondId);
    if (firstIndex === -1 || secondIndex === -1) return prevTodos;
    const newTodos = [...prevTodos];
    [newTodos[firstIndex], newTodos[secondIndex]] = 
      [newTodos[secondIndex], newTodos[firstIndex]];
    return newTodos;
  } 
  else {
    // ✅ Todo의 상태가 달라서, Todos의 상태도 업데이트 해야하는 경우.
    const newTodos = [...prevTodos];
    const firstIndex = prevTodos.findIndex((todo) =&gt; todo.id === firstId);
    const firstTodo = newTodos.splice(firstIndex, 1)[0];
    const secondIndex = newTodos.findIndex((todo) =&gt; todo.id === secondId);
    firstTodo.status = newTodos[secondIndex].status;
    newTodos.splice(secondIndex, 0, firstTodo);
    return newTodos;
  }
};
</code></pre>
<p>** 📌 4. <code>TodoBox</code> 에 <code>TodoItem</code>을 Drag&amp;Drop 할 수도 있다. <code>TodoBox</code> 도 <code>useTodoItemDnD</code> 관련 이벤트 리스너를 등록한다. **</p>
<pre><code class="language-jsx">// TodoBox.ts

import { useTodoItemDnD } from &#39;utils/hooks&#39;;
...

 const { 
     isDragOver, 
     setIsDragOver, 
     handleDragStart, 
     handleDragOver, 
     handleDragLeave 
 } = useTodoBoxDnD(ref);

...


const handleDrop = (e: React.DragEvent&lt;HTMLDivElement&gt;) =&gt; {
  if (!ref || !ref.current) return;
  if (!ref.current.isSameNode(e.target as Node)) return;
  const id = +e.dataTransfer.getData(&#39;text/plain&#39;);
  console.log(&#39;TodoBox&#39;, id, status);
  dispatch(update({ id, status })); // ✅ update 액션을 통해 state를 변경한다.
  setIsDragOver(false);
};

...

&lt;TodoSectionWrapper
      ref={ref}
      draggable
      isDragOver={isDragOver}
      onDragStart={handleDragStart}
      onDragOver={handleDragOver}
      onDragLeave={handleDragLeave}
      onDrop={handleDrop}
&gt;
       ...
&lt;/TodoSectionWrapper&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2021.08.26] Redux]]></title>
            <link>https://velog.io/@daeun-react/2021.08.26-Redux</link>
            <guid>https://velog.io/@daeun-react/2021.08.26-Redux</guid>
            <pubDate>Sun, 29 Aug 2021 16:16:00 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-data-binding">📌 Data Binding</h2>
<ul>
<li>뷰(화면)과 모델(데이터)을 연결하는 것을 의미</li>
<li>리액트는 단방향 Data Binding : 값이 바뀔때마다 모델에서 뷰로 가는 흐름</li>
</ul>
<hr>
<h2 id="📌-mvc-pattern">📌 MVC Pattern</h2>
<p><img src="https://images.velog.io/images/daeun-react/post/d536499d-a694-4eec-8f12-fd27a9bb6d80/image.png" alt="MVC 패턴"></p>
<ul>
<li>관심사의 분리(separation of concern, SoC)에서부터 나온 패턴
➡ 관심사 분리로 코드의 단순화 및 유지보수의 더 높은 수준의 자유가 생긴다. 
➡ 관심사가 잘 분리될 때 독립적인 개발과 업그레이드 외에도 모듈 재사용을 위한 더 높은 정도의 자유가 있다.</li>
</ul>
<h3 id="💡-model">💡 <code>Model</code></h3>
<ul>
<li>데이터</li>
<li>.json 또는 데이터 모델 정의</li>
<li>일반적으로 데이터를 처리하는 로직과 함께!<h3 id="💡-view">💡 <code>View</code></h3>
</li>
<li>화면, html, 레아아웃<h3 id="💡-controller">💡 <code>Controller</code></h3>
</li>
<li>이벤트 핸들러와 이벤트를 처리하는 로직이 있는 곳</li>
<li>데이터랑 뷰를 이어주는 역할</li>
<li>이벤트가 발생(요청)하면 모델에 적정한 로직을 실행하도록 한다.</li>
</ul>
<p><strong>[MVC 패턴 단점]</strong>
<img src="https://images.velog.io/images/daeun-react/post/0693e727-2585-4bfc-8255-b1f5bc729bc9/image.png" alt="MVC 패턴 단점"></p>
<ul>
<li>프로젝트 규모가 커질수록 빠르게 복잡해진다.</li>
<li>feature 추가될 때마다 모델과 뷰를 연결하는 복잡성이 증가한다. </li>
<li>데이터 간의 의존성과 연쇄적인 갱신은 뒤얽힌 데이터 흐름을 만들고 예측할 수 없는 결과로 이끌게 된다.</li>
<li>새로온 개발자가 합류하면, 너무 복잡해서 코드만 보고 해석조차 불가능. (유지비용 증가)</li>
<li>복잡성이 증가할 수록 예측 불가능해지고 안정성이 떨어진다. 
➡ 어디서 버그가 터져나올지 테스트도 어렵다.</li>
</ul>
<hr>
<h2 id="📌-flux-pattern">📌 Flux Pattern</h2>
<ul>
<li>Flux는 Facebook에서 소개한 아키텍쳐</li>
<li>전통적인 MVC 패턴을 버리고, 개발이 오래되고 커져도 유지보수가 쉽고 reliable하고 high performance를 유지하는 새로운 패턴</li>
<li>Redux는 Flux 패턴에 기반한 라이브러리!</li>
</ul>
<p><img src="https://images.velog.io/images/daeun-react/post/e9745347-b5cf-400c-b550-38a0bb38349e/flux.png" alt="flux pattern"></p>
<ul>
<li><strong>단방향 데이터 흐름(unidirectional data flow)이 핵심</strong></li>
<li>사용자에 의해 Action이 발행 ➡ 해당 Action에 영향이 있는 모든 View가 갱신(rerender)</li>
<li>어디에서 어떤 일이 일어날지 알 수 있다(=예상가능하다. 복잡하지 않다). 흐름은 하나니까!!</li>
<li>Flux는 세 가지 부분으로 구성 되어 있다.<ol>
<li>Dispatcher</li>
<li>Stores</li>
<li>Views(리액트 컴포넌트)</li>
</ol>
</li>
</ul>
<h3 id="💡-dispatcher">💡 Dispatcher</h3>
<ul>
<li>dispatcher를 통해 action을 발행한다.</li>
<li>모든 데이터는 중앙 허브인 dispatcher를 통해 흐른다.</li>
</ul>
<h3 id="💡-store">💡 Store</h3>
<ul>
<li>어플리케이션의 데이터와 비지니스 로직을 가지고 있는 store</li>
</ul>
<h3 id="💡-views">💡 Views</h3>
<ul>
<li>action이 발행되면 이 action에 영향이 있는 모든 view가 갱신됨</li>
</ul>
<hr>
<h2 id="📌-redux-intro">📌 Redux Intro</h2>
<p>➡ Redux는 Flux 패턴을 근본으로한 라이브러리이다.</p>
<h3 id="💡-왜-리덕스를-사용하는가">💡 왜 리덕스를 사용하는가?</h3>
<ul>
<li><p><strong>앱에서 전체적으로 사용할 데이터 관리가 필요</strong></p>
<ul>
<li>React.js는 단순 UI 라이브러리라서, 데이터 관리를 고려하고 있지 않음</li>
<li>로컬스토리지에 데이터를 저장하고 불러오는 로직 대신 Redux를 사용!</li>
<li>props drilling을 피할 수 있다.</li>
</ul>
</li>
<li><p><strong>하나의 state(데이터)를 여러 컴포넌트에서 필요</strong>한 경우가 있다.</p>
</li>
<li><p>페이지의 레이아웃에 영향 받지 않는 <strong><code>modal, toast, alert</code> 같은 전역 UI 컴포넌트의 상태 관리도 필요</strong>하다.</p>
</li>
</ul>
<hr>
<h3 id="💡-리덕스-구조">💡 리덕스 구조</h3>
<p><img src="https://images.velog.io/images/daeun-react/post/d797d41a-8f5d-4f05-b807-4e034ac6ec1a/redux.png" alt="Redux구조"></p>
<ol>
<li><p>*<em><code>store</code> *</em>: Application 전체 state는 store에서 관리된다.</p>
<pre><code>         ➡ store는 redux의 상태값(state)를 갖는 객체다</code></pre></li>
<li><p><strong><code>action</code></strong> : action은 state 변화를 일으킬 수 있는 행동 정보        </p>
</li>
<li><p><strong><code>dispatcher</code></strong> : action이 일어나면 Dispatcher를 통해서 store의 state가 업데이트 된다.</p>
</li>
<li><p><strong><code>view</code></strong> : state가 변경되면 view에서 감지하고, 화면에 반영(rerender)된다.</p>
</li>
</ol>
<hr>
<h3 id="💡-리덕스의-세-가지-원칙">💡 리덕스의 세 가지 원칙</h3>
<ol>
<li><p>*<em>전체 상태값이 하나의 객체로 표현된다. *</em>
➡ store는 하나다!</p>
</li>
<li><p><strong>상태값(state)은 읽기 전용이다.</strong>
➡  useState처럼 state값을 직접 바꾸는게 아니고, setState 함수를 사용해서 변경한다.</p>
</li>
<li><p><strong>상태값(state)은 순수 함수에 의해서만 변경되어야 한다.</strong>
➡  상태값을 변경시키려면 상태값을 변경하는 함수가 필요하다. (➡ 이 함수가 reducer!)
reducer는 항상 같은 input은 같은 output을 반환하는 순수함수여야 한다.</p>
</li>
</ol>
<hr>
<h2 id="📌-redux-사용--reducer-store-action">📌 Redux 사용 | Reducer Store Action</h2>
<h3 id="💡-redux-구성-요소---action">💡 Redux 구성 요소 - Action</h3>
<blockquote>
<p>사용자의 입력이나 UI 조작, 웹 요청 완료같이 어떠한 상태 변화를 일으킬 수 있는 현상. 
즉, <strong>어떤 조작인지 정보를 갖고 있는 자바스크립트 객체</strong>이다. </p>
</blockquote>
<h4 id="-action의-생김새--자바스크립트-객체다">* Action의 생김새 =&gt; 자바스크립트 객체다!</h4>
<pre><code class="language-jsx">{
    type: &#39;SHOW_MODAL&#39;
}</code></pre>
<h4 id="-action의-특징">* Action의 특징</h4>
<ul>
<li>action은 객체다!</li>
<li>action은 반드시 type 프로퍼티가 있어야 한다.</li>
<li>type 이외의 다른 프로퍼티를 가져도 된다.(부가적인 데이터 전달하고 싶을 때)</li>
</ul>
<h4 id="-action-정의">* Action 정의</h4>
<ul>
<li>action은 객체 리터럴로 바로 정의하는게 아니라, Action Creator를 통해 만든다</li>
</ul>
<pre><code class="language-jsx">function showModal({ title }) {
    return { type: &#39;SHOW_MODAL&#39;, title }
}

showModal({ title: &#39;로그인&#39; });</code></pre>
<hr>
<h3 id="💡-redux-구성-요소---reducer">💡 Redux 구성 요소 - Reducer</h3>
<blockquote>
<p>reducer는 action이 발생했을 때, <strong>state를 변화시키기 위한 함수</strong>다.</p>
</blockquote>
<h4 id="-reducer의-생김새">* Reducer의 생김새</h4>
<p>reducer는 현재의 state와 action을 인자로 받고, 
이 action의 내용(type)에 따라 state를 변화시킨다.</p>
<pre><code class="language-jsx">function modal(state, action) {

  switch(action.type) {
    case &#39;SHOW_MODAL&#39;:
      return {
        ...state,
        showModal: true
      };
    case &#39;CLOSE_MODAL&#39;:
      return {
        ...state,
        showModal: false
      };
    default:
      return state;
  }
}</code></pre>
<hr>
<h3 id="💡-redux-구성-요소---store">💡 Redux 구성 요소 - Store</h3>
<blockquote>
<p>store는 앱에 오직 하나만 있고, 이 <strong>유일한 store를 사용하여 app의 전체 상태를 관리</strong> 한다.</p>
</blockquote>
<pre><code class="language-jsx">import { createStore } from &#39;redux&#39;
import modalReducer from &#39;./ModalReducer&#39;;

const store = createStore(modalReducer);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2021.08.23] TypeScript]]></title>
            <link>https://velog.io/@daeun-react/2021.08.23-TypeScript</link>
            <guid>https://velog.io/@daeun-react/2021.08.23-TypeScript</guid>
            <pubDate>Sun, 29 Aug 2021 16:14:43 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-함수">📌 함수</h2>
<ul>
<li>매개변수의 우측에 <strong>콜론(:)</strong>과 매개변수의 타입을 정의</li>
<li>return 값의 타입은 <strong>소괄호()우측</strong>에 타입을 정의
➡ formatDate의 매개변수 d는 Date 객체 타입을 받아야하고, return 값은 문자열이어야 한다</li>
</ul>
<pre><code class="language-tsx">const formatDate = (d: Date): string =&gt; { // ✅
    const year = d.getFullYear();
    const month = d.getMonth() + 1;
    const day = d.getDate();

    return `${year}년 ${month}월 ${day}일`;
};

const today = formatDate(new Date());
console.log(today);</code></pre>
<pre><code class="language-tsx">// lang의 경우 인자를 전달하지 않으면 &quot;ko&quot;라는 문자열 값이 할당
// delimiter는 물음표를 사용하여 선택적으로 인자 전달
let formatDate = (d: Date | number, lang = &quot;ko&quot;, delimiter?: string): string =&gt; {
};</code></pre>
<hr>
<h2 id="📌-새로운-타입---기본">📌 새로운 타입 - 기본</h2>
<h3 id="💡-1-any">💡 1. Any</h3>
<ul>
<li>어떤 타입이라도 모두 지정 가능하다</li>
<li>JS로 컴파일된 코드를 보면 아무 타입도 지정되지 않은 원래의 JS 코드와 똑같다.
  ➡ any 타입을 쓰면? 타입스크립트 안 쓴 거와 같다 (<strong>any는 쓰지말자</strong>)<h3 id="💡-2-void">💡 2. void</h3>
</li>
<li>void는 any와는 반대로 어떤 타입도 없다는 뜻</li>
<li>보통 함수에서 반환값이 없는 경우 사용<h3 id="💡-3-enum">💡 3. Enum</h3>
</li>
<li>언제 사용 ? <strong>상수로된 세트 값이 필요할 때</strong><pre><code class="language-tsx">// Category라는 이름의 enum 타입을 정의한다
// Category의 enum 값에 Past, Pizza, Dessert 가 있다.
enum Category {
  Pasta,
  Pizza,
  Dessert
}
let menuCategory: Category = Category.Pasta; // 0
</code></pre>
</li>
</ul>
<p>// enum에 값 부여
enum Category {
    Pasta = &#39;pasta&#39;,
    Pizza = &#39;pizza&#39;,
    Dessert = &#39;dessert&#39;
}
let menuCategory: Category = Category.Pasta; // pasta</p>
<pre><code>
### 💡 4. union
- union타입은 여러 타입이 올 수 있을 때 사용
```tsx
function formatDate(date: string | number | Date): string {
    // 로직 생략

    return `${year}년 ${month}월 ${day}일`
}

formatDate(20201028);
formatDate(new Date());
formatDate(&#39;20201028&#39;);</code></pre><ul>
<li>배열에 여러 타입의 값을 사용하고 싶을 때, 튜플을 쓸 때와 union을 쓸 때의 차이점<pre><code class="language-tsx">// union
let starNumberArr: (number | string)[] = [1, 2];
starNumberArr.push(&quot;3점&quot;);
</code></pre>
</li>
</ul>
<p>// tuple
let starArr: [number, string] = [1, &quot;1점&quot;];</p>
<pre><code>
- union은 사용하고자 하는 타입 중에 하나만 있어도 가능.
튜플을 사용하면 배열의 요소에 정의한 타입이 모두 존재해야 한다.

### 💡 5. Type Alias
- 타입을 재사용하거나, 객체를 위한 타입을 정의할 때 많이 사용
```tsx
// 방법은 아래처럼 type으로 정의하거나, interface로 타입을 정의하거나.
type ID = number | string;

//checkInfo 함수의 매개변수 info 객체를 위해 Info라는 타입을 만들기.
type Info = {
  id: ID;
  pw: string;
};

function checkInfo(info: Info) {

}

let id: ID = &quot;1010&quot;;
checkInfo({ id, pw: &quot;password&quot; });</code></pre><hr>
<h2 id="📌-타입추론-type-inference">📌 타입추론 (Type Inference)</h2>
<ul>
<li>타입스크립트에서는 타입을 표기하지 않아도 타입스크립트 컴파일러가 변수에 할당된 값을 보고 타입을 추측<pre><code class="language-tsx">// ts 파일에서
let starArr = [1, 2, 3];
starArr.push(&#39;4점&#39;);  
// 에러: Argument of type &#39;string&#39; is not assignable to parameter of type &#39;number&#39;.
// starArr는 숫자로만 이루어진 배열이 할당되어, number[] 타입으로 추론됨 =&gt; 에러 발생!</code></pre>
</li>
</ul>
<hr>
<h2 id="📌-인터페이스-interface">📌 인터페이스 (Interface)</h2>
<ul>
<li><p><strong>state와 props의 타입을 정의하는데 주로 사용</strong></p>
</li>
<li><p>** <code>readonly</code>, <code>?</code> **키워드 사용</p>
<pre><code class="language-tsx">// readonly는 읽기만 가능한 프로퍼티로, 값을 수정할 수 없습니다.
// 프로퍼티명 다음에 물음표(?)를 사용하면 해당프로퍼티를 추가해도 되고 안해도 됩니다.
interface Restaurant {
  readonly name: string;
  star: number;
  address?: string;
}
</code></pre>
</li>
</ul>
<p>const chroad3: Restaurant = {
    name: &quot;취향로3가&quot;,
    star: 5,
};</p>
<p>chroad3.name = &quot;chroad3&quot;;  // 에러: Cannot assign to &#39;name&#39; because it is a read-only property.
chroad3.star = 4;</p>
<p>const sipboon: Restaurant = {
    name: &quot;십분의일&quot;,
    star: 5,
    address: &quot;을지로3가&quot;,
};</p>
<pre><code>
- **`extends` 사용 **: 기존에 정의된 인터페이스를 확장
```tsx
interface BasicInfo {
    name: string;
    star: number;
}
const sipboon: BasicInfo = {
    name: &quot;십분의일&quot;,
    star: 5,
};

// extends
interface DetailInfo extends BasicInfo {
    address: string;
    phone: string;
    position: number[];
}
const chroad3: DetailInfo = {
    name: &quot;취향로3가&quot;,
    star: 5,
    address: &quot;을지로3가&quot;,
    phone: &quot;123-456-7890&quot;,
    position: [37.565496, 126.99142],
};</code></pre><ul>
<li>*<em>교차타입 : <code>type</code> 사용 *</em>
➡ 합쳐서 새로운 인터페이스를 만드는 것은 아니고, <code>&amp; 기호</code>를 사용하여 기존에 정의했던 인터페이스를 합쳐서 새로운 타입을 만드는 것<pre><code class="language-tsx">interface BasicInfo {
  name: string;
  star: number;
}
</code></pre>
</li>
</ul>
<p>interface DetailInfo {
    position: number[];
}</p>
<p>type Info = BasicInfo &amp; DetailInfo;</p>
<pre><code>
---
## 📌 타입호환성 (Type Compatibility)

&gt; **Q.  v1, v2 둘 중에 어떤 라인이 에러가 날까?**

```tsx
function getStar(score: number | string, scoreNum: number) {
  const v1: number = score;
  const v2: number | string = scoreNum;
}</code></pre><ul>
<li>(정답) v1  </li>
<li>만약 score가 문자열로 전달됐다면 string 타입이 되기 때문에 v1 타입인 number에 포함되지 않는다.</li>
<li>scoreNum 매개변수는 숫자타입이기 때문에 v2타입인 number, string 둘 중에 하나 포함되므로 타입이 호환된다.</li>
</ul>
<hr>
<h2 id="📌-제네릭-generic">📌 제네릭 (Generic)</h2>
<ul>
<li>타입을 정의할 때 특정 타입으로 고정된 것이 아니라, </li>
<li><em>내가 원하는 타입을 자유롭게 지정해서 계속 사용하고 싶을 때*</em> 제네릭을 사용</li>
<li>제네릭은 <strong>타입을 마치 재사용할 수 있는 변수처럼 취급해서 여러 군데에서 사용하고 싶을 때</strong> 사용</li>
<li>제네릭은 함수명 우측에 화살표괄호(<strong>&lt;&gt;</strong>)로 감싼다.</li>
<li>T는 특별한 의미가 없는 변수명 같다고 생각하면 되는데, 
제네릭을 사용할 때 보통 대문자 T를 자주 사용한다. 
(내가 원하는 이름으로 자유롭게 작성할 수 있다)</li>
</ul>
<pre><code class="language-tsx">function makeArr&lt;T&gt;(el: T): T[] {
    return [el];
}

makeArr&lt;number&gt;(1);      // 1 number[]
makeArr&lt;string&gt;(&quot;1점&quot;);  // 2 string[]
makeArr&lt;boolean&gt;(true);  // 3 boolean[]</code></pre>
<ul>
<li>제네릭 타입을 명시하지 않아도 컴파일러는 전달되는 인자값을 통해 타입을 추론하여 T의 타입을 결정</li>
<li>아래 코드는 훨씬 간결하고 가독성이 높아졌지만, 추후 유지보수를 위해서나 더 복잡한 예제의 예상치 못한 오류를 위해 제네릭 타입을 정확히 써주는게 좋을 때도 있다.<pre><code class="language-tsx">makeArr(1);
makeArr(&quot;1점&quot;);
makeArr(true);</code></pre>
</li>
</ul>
<hr>
<h2 id="📌-리액트를-위한-타입스크립트">📌 리액트를 위한 타입스크립트</h2>
<h3 id="💡-객체-타입을-정의하는-방법은-object-interface-type-alias-세-가지">💡 객체 타입을 정의하는 방법은 <code>object</code>, <code>interface</code>, <code>type alias</code> 세 가지!</h3>
<ul>
<li>object 타입 → 타입을 재사용할 수 없으며, 프로퍼티가 많을 수록 가독성이 좋지 않다</li>
<li>state나 props를 정의할 때** interface나 type을 사용하는 것이 좋다.**</li>
<li>type과 interface는 확장, 병합 가능성이라던지 선언 등의 차이점이 있어서 상황에 따라 적절하게 사용하면 되지만, 타입스크립트 공식 문서에는 type보다 <strong>interface를 사용</strong>하라고 되어있다.</li>
</ul>
<h3 id="💡-함수형-컴포넌트의-타입을-선언하는-두-가지-방법">💡 함수형 컴포넌트의 타입을 선언하는 두 가지 방법</h3>
<p><strong>1. 리액트의 FC 타입 사용</strong></p>
<pre><code class="language-tsx">interface StarsProps {  // prop 타입 정의
  star: number;
}

const Stars: React.FC&lt;StarsProps&gt; = ({ star }) =&gt; {   //
  return ( 
    &lt;div&gt;
      {makeStars(star)}
    &lt;/div&gt;
  )
}</code></pre>
<p><strong>2. 일반적인 함수정의 방식</strong></p>
<pre><code class="language-tsx">interface StarsProps {   // prop 타입 정의
  star: number;
}

const Stars = ({ star }: StarsProps): JSX.Element =&gt; { // 
  return ( 
    &lt;div&gt;
      {makeStars(star)}
    &lt;/div&gt;
  )
}</code></pre>
<h3 id="💡-hooks">💡 Hooks</h3>
<h3 id="-usestate"><strong>* useState</strong></h3>
<ul>
<li>특별히 타입을 명시하지 않더라도 타입추론을 통하여 타입이 지정된다.<pre><code class="language-tsx">const [like, setLike] = useState(false);
</code></pre>
</li>
</ul>
<p>useState<boolean>(initialState: boolean | (() =&gt; boolean))
: [boolean, Dispatch&lt;SetStateAction<boolean>&gt;]</p>
<pre><code>

- state의 초기값을 설정할 때 null을 사용하면? 유니온 타입을 사용하여 타입을 명시
```tsx
// 유니온 타입으로 전달
const [like, setLike] = useState&lt;boolean | null&gt;(null);</code></pre><ul>
<li>state에 객체가 포함된 경우, 자세한 프로퍼티 타입을 알 수 있도록 아래와 같이 정의<pre><code class="language-tsx">// state 타입 정의
interface Comment {
  comment: string;
  username: string;
  date: string;
  star: number;
}
const [comments, setComments] = useState&lt;Comment[]&gt;([]);</code></pre>
</li>
</ul>
<h3 id="-useref"><strong>* useRef</strong></h3>
<ul>
<li>useState처럼 타입을 명시하지 않아도 된다.</li>
<li>만약 코드의 명확성을 위해서 타입을 정의하고 싶은 경우, 아래와 같이 ref의 태그에 맞는 제네릭을 넘겨주면 된다.<pre><code class="language-tsx">const reviewRef = useRef&lt;HTMLDivElement&gt;(null); 
//로직 생략
</code></pre>
</li>
</ul>
<p>return (
  &lt;&gt;
    <Review reviewTextRef={reviewRef} /> 
    <div ref={reviewRef}> 
      리뷰
    </div>
    &lt;/&gt;
)</p>
<pre><code>
### 💡 Event Handler
- 이벤트 핸들러 함수의 이벤트 매개변수에는 특별한 타입이 필요하다
- 물론 매개변수에 타입을 명시하지 않아도 오류는 나지 않지만, 정확히 어떤 종류의 이벤트이고, 어느 태그에서 발생하는 것인지 써주는 것이 좋다.
- 일반적으로 타입 이름은 &quot;이벤트타입Event&quot;으로 ChangeEvent, FormEvent, TouchEvent, FocusEvent, KeyboardEvent, MouseEvent, DragEvent 등이 있다.

### 💡 전역 변수
- window에 외부 라이브러리 변수를 추가하려면 아래와 같이 해당 라이브러리에서 사용하는 전역 변수명을 추가하면 된다.
```tsx
declare global {
  interface Window {
    kakao: any;
  }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[2021.08.19] 자료구조와 알고리즘]]></title>
            <link>https://velog.io/@daeun-react/2021.08.19-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@daeun-react/2021.08.19-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Sun, 22 Aug 2021 13:13:09 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-프론트-날짜-관련-상식">📌 프론트 날짜 관련 상식</h2>
<ul>
<li>현재 날짜 시간 및 포맷은 js코드가 실행된 시스템에 의해 결정된다.</li>
</ul>
<h3 id="💡-utc-coordinated-universal-time">💡 <code>UTC (Coordinated Universal Time)</code></h3>
<ul>
<li>국제표준시</li>
</ul>
<h3 id="💡-kst-korea-standard-time">💡 <code>KST (Korea Standard Time)</code></h3>
<ul>
<li>UTC +9시간 더한 시간</li>
<li>UTC가 밤 9시면, KST는 아침 9시가 된다.</li>
</ul>
<h3 id="💡-iso-8601">💡 <code>ISO 8601</code></h3>
<ul>
<li>날짜와 시간과 관련된 데이터 교환을 다루는 국제표준
  ➡  예시: &quot;2021-08-01T09:54:33.894Z&quot;</li>
<li>특정 의미를 제공하는 (&quot;-&quot;, &quot;:&quot;, &quot;T&quot;, 그리고 &quot;Z&quot;와 같은) 어떤 문자들로 작성되어야 한다
  ➡  시간이 UTC인 경우, 시간 뒤에 빈칸없이 Z를 직접 추가해야 한다</li>
</ul>
<h4 id="결론-백엔드와-iso-형식으로-utc로-주고-받고-한국-시간으로-바꿔서-사용해야-한다">(결론) 백엔드와 ISO 형식으로 UTC로 주고 받고, 한국 시간으로 바꿔서 사용해야 한다!</h4>
<hr>
<h2 id="📌-stack--queue">📌 Stack &amp; Queue</h2>
<h3 id="💡-stack">💡 Stack</h3>
<p><img src="https://images.velog.io/images/daeun-react/post/229d6e51-6ef7-4d41-96bd-b7aa79fa46c8/stack.png" alt="stack"></p>
<ul>
<li>리스트의 한쪽 끝에서 수행 되는 선형 리스트 형태로서 스택의 작업에는 삽입(push), 삭제(pop)</li>
<li><strong><code>LIFO(Last In Frist Out)</code> : 스택에 마지막으로 입력된 자료가 제일 먼저 삭제 하는 방식</strong><ul>
<li>브라우저의 History</li>
<li>터미널 cd(Change Directory), pwd(현재경로) 명령어<ul>
<li>함수 실행 콜스택</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="💡-queue">💡 Queue</h3>
<p><img src="https://images.velog.io/images/daeun-react/post/472990d1-2263-48d6-bf30-67a2b58a3031/queue.png" alt="queue"></p>
<ul>
<li>큐는 여려개의 데이터 항목을 일정한 순서대로 나열 하는 형태로 push(입력), pop(삭제) 작동</li>
<li><strong><code>FIFO(Frist In Frist OUT)</code>: 선입선출 방법으로 가장 먼저 데이터에 대해서 삭제 하는 방법</strong><ul>
<li>프린터 작업 스케줄러</li>
<li>Javascript 비동기 처리 관련 <ul>
<li>DOM Event</li>
<li>setTimeout</li>
<li>HTTP 통신을 하는 fetch 함수</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="📌-linked-list">📌 Linked List</h2>
<p><a href="https://velog.io/@daeun-react/Linked-List">&gt; Linked List 블로그 작성(미완성)</a></p>
<hr>
<h2 id="📌-sort-algorithm">📌 Sort Algorithm</h2>
<p><a href="https://velog.io/@daeun-react/Sorting-Algorithm">&gt; 정렬 알고리즘 블로그 작성(미완성)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linked List]]></title>
            <link>https://velog.io/@daeun-react/Linked-List</link>
            <guid>https://velog.io/@daeun-react/Linked-List</guid>
            <pubDate>Sun, 22 Aug 2021 13:12:22 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Sorting Algorithm]]></title>
            <link>https://velog.io/@daeun-react/Sorting-Algorithm</link>
            <guid>https://velog.io/@daeun-react/Sorting-Algorithm</guid>
            <pubDate>Sun, 22 Aug 2021 13:11:35 GMT</pubDate>
            <description><![CDATA[<ul>
<li>Quick Sort</li>
<li>Selection Sort</li>
<li>Bubble Sort</li>
<li>Merge Sort</li>
<li>Heap Sort</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Assignment 7 회고록] 솔라커넥트 - TS 기반 프로젝트의 코드 리팩토링]]></title>
            <link>https://velog.io/@daeun-react/Assignment-7-%EC%86%94%EB%9D%BC%EC%BB%A4%EB%84%A5%ED%8A%B8-TodoList</link>
            <guid>https://velog.io/@daeun-react/Assignment-7-%EC%86%94%EB%9D%BC%EC%BB%A4%EB%84%A5%ED%8A%B8-TodoList</guid>
            <pubDate>Sun, 22 Aug 2021 13:10:14 GMT</pubDate>
            <description><![CDATA[<h3 id="🔗-배포링크">🔗 <a href="https://solar-connect-ts-todolist.netlify.app/">배포링크</a></h3>
<h3 id="🔗-github">🔗 <a href="https://github.com/daeun-react/wanted-solar-connect-todolist">Github</a></h3>
<h3 id="🔗-베이스코드-개선되어야-할-사항을-노션에-작성하기"><a href="https://www.notion.so/TodoList-57bbaa44ab714d79b773a8bd8aa5fbc2">🔗 베이스코드 개선되어야 할 사항을 노션에 작성하기</a></h3>
<hr>
<h3 id="과제-내용">과제 내용</h3>
<ul>
<li>간단한 베이스 코드가 주어집니다. (<a href="https://codesandbox.io/s/long-haze-9v8jt?file=/src/components/todo/TodoService.tsx">베이스 코드 링크</a>)</li>
<li>베이스 코드는 ReactJS 기반으로 만들어져 있으며, 몇개의 버그가 포함되어 있습니다.</li>
<li>요구사항을 잘 읽고, 버그 수정과 필요한 기능을 추가합니다.</li>
</ul>
<p><strong>[구현 중 지켜야할 사항]</strong></p>
<ul>
<li><code>TypeScript</code> 사용</li>
<li><code>antd</code> 라이브러리 사용( <code>modal</code>, <code>datepicker</code> 필수)</li>
<li>인터넷이 안되는 환경 ➡ 추가 라이브러리 설치 안됨</li>
</ul>
<hr>
<h3 id="과제를-끝내고-회고-내용">과제를 끝내고 회고 내용</h3>
<h3 id="🔰-1-typescript">🔰 <strong>1. Typescript</strong></h3>
<ul>
<li>프리온보딩 코스를 하면서 처음으로 타입스크립트를 적용한 프로젝트!<ul>
<li>초반에 codesandbox에 있는 걸 zip 파일로 다운받아서 실행 했는데, 이래저래 안되서 구글링 후 ts 버전을 바꾸어 설치하니 동작이 되었다.</li>
</ul>
</li>
<li>ts 적용 후 개발하다 보면 아무래도 type 관련 에러들이 많이 발생한다.</li>
<li>처음엔 ts로 실행시키는 것도 어렵고, 개발하는 것도 어렵고 불편하다 생각했지만, 
  완료 후에 보니 내가 작성한 코드는 null값에 대한 에러처리를 잘 안잡아 주고 있다는 것도 알게되고, 개발 코드도 다시 한 번 돌아보게 되는 시간이었다.</li>
</ul>
<h3 id="🔰-2-todo-list-화면에-현재-시간을-표시">🔰 2. Todo List 화면에 현재 시간을 표시</h3>
<ul>
<li>수업시간에 배운대로, <code>ISO 8601</code> 국제표준 형태로 저장해서, 
사용할 때 한국 시간으로 바꿔서 저장해주었다.</li>
</ul>
<h3 id="🔰-3-todo-항목에-완료-목표일을-기입">🔰 3. Todo 항목에 완료 목표일을 기입</h3>
<ul>
<li>antd Datepicker를 사용</li>
<li>disabledDate property를 사용하면 오늘 날짜 이전은 disabled 되도록 해준다
  ➡ TodoList다 보니, 오늘 날짜는 disabled 되면 안될 것 같아서 아래처럼 수정했다<pre><code class="language-jsx">const disabledDate = (current: moment.Moment): boolean =&gt;
  current &amp;&amp; current.valueOf() &lt; new Date().setHours(0, 0, 0, 0).valueOf();</code></pre>
</li>
</ul>
<h3 id="🔰-4-todo-항목에-완료-버튼을-누르면-todo-생성">🔰 4. Todo 항목에 완료 버튼을 누르면 Todo 생성</h3>
<p>아래의 경우에는 TodoList가 추가되지 않고, antd 모달 경고창 출력 &amp; 버튼 UI를 변경해줬다.</p>
<ul>
<li>TodoList 텍스트가 빈 값인 경우(ex &quot;      &quot; 공백문자열 포함)</li>
<li>TodoList 완료 목표일을 선택하지 않은 경우</li>
<li>TodoList 텍스트 &amp; 완료일이 동일한 아이템이 존재할 경우</li>
</ul>
<h3 id="🔰-5-로그인-기능">🔰 5. 로그인 기능</h3>
<p>라이브러리를 추가로 설치하지 못하는 경우이기 때문에,localStoarge 를 사용하여 아래처럼 로그인/로그아웃 기능을 구현했다.</p>
<ol>
<li>웹 사이트에 처음 접속 시, 모달창을 띄워서 사용자명을 입력받는다.</li>
<li><code>localStoarge</code>의 <code>todo-user</code> 값에 사용자명을 저장한다. </li>
<li>구현된 <code>Spinner</code> 컴포넌트를 활용하여, 1초 동안 로딩 중임을 보여주고 화면으로 전환한다.</li>
<li>TodoList 추가 시, 기존의 todos가 아닌 <code>사용자명-todos</code>에 입력값을 저장한다.</li>
<li>사용자가 로그아웃 버튼을 누르면 <code>todo-user</code> 값을 삭제한다.</li>
<li>다시 사용자가 로그인 할 경우, <code>사용자명-todos</code>에 저장된 목록을 불러온다.</li>
<li>만약 <code>todo-user</code>가 존재하지 않는다면,  다시 모달창을 띄워 사용자명을 입력 받는다.</li>
</ol>
<hr>
<h3 id="🔗노션"><a href="https://www.notion.so/TodoList-57bbaa44ab714d79b773a8bd8aa5fbc2">&gt; 🔗노션 &lt; </a></h3>
<ul>
<li><p><strong>개선될 수 있는 부분</strong>
간단한 TodoList다 보니, 개선되어야할 부분이 여러 개 생각이 났다.
그 중 구현해보고 싶은 아래 5가지를 정해서 기능을 완료했고 자세한 건 노션에 작성했다!</p>
<ul>
<li><strong>추가 기능 구현 부분</strong></li>
</ul>
<ol>
<li>TodoList 입력순/ 마감임박순 정렬 기능 구현</li>
<li>등록된 TodoList와 텍스트&amp;완료 목표일이 동일한 중복된 항목은 추가 불가능 기능 구현</li>
<li>완료 목표일 또는 텍스트가 입력되지 않은 경우 추가 불가능 기능 구현</li>
<li>DatePicker에서 현재 날짜보다 이전 날짜는 완료 목표일로 설정 불가능하도록 기능 구현</li>
<li>LocalStorage를 통한 로그인/ 로그아웃 기능 구현</li>
</ol>
</li>
</ul>
<ul>
<li><strong>로그인 기능</strong>
인터넷 연결이 될 때, 안될 때 로그인 기능 구현 방법 고려하기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Assignment 6] 솔라커넥트 - Sorting Machine]]></title>
            <link>https://velog.io/@daeun-react/Assignment-6-%EC%86%94%EB%9D%BC%EC%BB%A4%EB%84%A5%ED%8A%B8-Sorting-Machine</link>
            <guid>https://velog.io/@daeun-react/Assignment-6-%EC%86%94%EB%9D%BC%EC%BB%A4%EB%84%A5%ED%8A%B8-Sorting-Machine</guid>
            <pubDate>Wed, 18 Aug 2021 16:38:26 GMT</pubDate>
            <description><![CDATA[<p><strong>1. 타이머</strong></p>
<ul>
<li>재사용 가능한 Timer 컴포넌트 만들기</li>
<li>한국 표준 시 기준으로 타이머 생성 
“ko-KR” 지역시간 표기법 (예&gt; 2021년 7월 20일 화요일),
“en-US” 지역시간 표기법 (예&gt; Tuesday July 20, 2021) </li>
</ul>
<pre><code class="language-jsx">// Timer 컴포넌트
const Timer = ({ type }) =&gt; {
  const [date, setDate] = useState(new Date());

  useEffect(() =&gt; {
    const timer = setInterval(() =&gt; {
      setDate(new Date());
    }, 1000);

    return () =&gt; {
      clearInterval(timer);
    };
  }, []);

  return (
    &lt;Wrapper type={type}&gt;
      &lt;h2&gt;{dateLocalFunc(date, type)}&lt;/h2&gt;
    &lt;/Wrapper&gt;
  );
};

//utils/constant.js
export const DATE_LOCAL_OPTIONS_KR = {
  weekday: &#39;long&#39;,
  year: &#39;numeric&#39;,
  month: &#39;long&#39;,
  day: &#39;numeric&#39;,
  timeZone: &#39;Asia/seoul&#39;,
};

//utils/date.js
export const dateLocalFunc = (date, type) =&gt;
  type === &#39;KR&#39;
    ? date.toLocaleString(&#39;ko-KR&#39;, DATE_LOCAL_OPTIONS_KR)
    : date.toLocaleString(&#39;en-US&#39;, DATE_LOCAL_OPTIONS_KR);</code></pre>
<hr>
<p><strong>2. 입력</strong></p>
<ul>
<li>입력 데이터의 형식은 “숫자,숫자,숫자…” (예&gt; 1,2,3,4)</li>
<li>잘못된 형식의 입력 데이터는 예외처리 필요</li>
</ul>
<pre><code class="language-jsx">//utils/regex.js
export const inputRegEx = /^(([0-9])+[\s]?,[\s]?)*([0-9]+)$/;

const inputValidator = (str) =&gt; setInputError(!inputRegEx.test(str));

const onInputChange = (e) =&gt; {
  setInputTxt(e.target.value);
  inputValidator(e.target.value);
};

const onInputKeyPress = (e) =&gt; {
  if (e.key === &#39;Enter&#39;) {
    onSort();
  }
};

//생략..
//jsx 부분
&lt;InputNums
  value={inputTxt}
  ref={inputRef}
  onChange={onInputChange}
  onKeyPress={onInputKeyPress}
  /&gt;

&lt;Error isError={inputError &amp;&amp; inputTxt} /&gt;</code></pre>
<hr>
<p>*<em>3. 시작 버튼 및 결과 *</em></p>
<ul>
<li>사용자가 시작 버튼을 누르면 소팅이 시작.</li>
<li>오름차순 결과가 바로 보여지고, 3초 후 내림차순 결과 보여주기</li>
<li>결과 데이터의 형식은 “숫자, 숫자, 숫자…” (예&gt; 1, 2, 3, 4)</li>
</ul>
<pre><code class="language-jsx">//utils/stringToArray.js
export const stringToArray = (str) =&gt;
  str
    .trim()
    .split(&#39;,&#39;)
    .map((str) =&gt; parseInt(str));

const onSort = () =&gt; {
  const target = stringToArray(inputTxt);

  setAscend(&#39;Loading...&#39;);
  setDescend(&#39;Loading...&#39;);

  new Promise((resolve, _reject) =&gt; {
    setAscend(bubbleSort(target, &#39;asc&#39;).join(&#39;, &#39;));
    btnRef.current.disabled = true;
    inputRef.current.disabled = true;
    setTimeout(() =&gt; {
      resolve();
    }, 3000);
  }).then(() =&gt; {
    setDescend(bubbleSort(target, &#39;desc&#39;).join(&#39;, &#39;));
    btnRef.current.disabled = false;
    inputRef.current.disabled = false;
  });
};

//생략..
//jsx 부분
&lt;StartButton
  type=&quot;button&quot;
  ref={btnRef}
  disabled={inputError}
  onClick={onSort}&gt;
  시작 버튼
&lt;/StartButton&gt;</code></pre>
<ul>
<li>알고리즘은 소팅알고리즘(sort)을 사용하지 않고, 본인이 구현할 수 있는 정렬 방법으로 직접 구현</li>
</ul>
<pre><code class="language-jsx">//utils/constant.js
export const SORT = {
  ASC: &#39;asc&#39;,
  DESC: &#39;desc&#39;,
};

export const bubbleSort = (arr, sortType) =&gt; {
  let result = [...arr];

  for (let i = 0; i &lt; result.length - 1; i++) {
    for (let j = 0; j &lt; result.length - i; j++) {
      if (
        sortType === SORT.ASC
          ? result[j] &gt; result[j + 1]
          : result[j] &lt; result[j + 1]
      ) {
        [result[j], result[j + 1]] = [result[j + 1], result[j]];
      }
    }
  }

  return result;
};</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Assignment 6 회고록] 솔라커넥트 - Sorting Machine]]></title>
            <link>https://velog.io/@daeun-react/Assignment-6-%ED%9A%8C%EA%B3%A0%EB%A1%9D-%EC%86%94%EB%9D%BC%EC%BB%A4%EB%84%A5%ED%8A%B8-Sorting-Machine</link>
            <guid>https://velog.io/@daeun-react/Assignment-6-%ED%9A%8C%EA%B3%A0%EB%A1%9D-%EC%86%94%EB%9D%BC%EC%BB%A4%EB%84%A5%ED%8A%B8-Sorting-Machine</guid>
            <pubDate>Wed, 18 Aug 2021 15:03:54 GMT</pubDate>
            <description><![CDATA[<h3 id="🔗-배포링크">🔗 <a href="https://sorting-machine.netlify.app/">배포링크</a></h3>
<h3 id="🔗-github">🔗 <a href="https://github.com/daeun-react/wanted-solar-connect">Github</a></h3>
<hr>
<h3 id="과제를-끝내고-회고-내용">과제를 끝내고 회고 내용</h3>
<h3 id="🔰-1-자바스크립트-날짜-옵션-주기">🔰 1. 자바스크립트 날짜 옵션 주기</h3>
<p><code>Date()</code>를 사용할 때 옵션을 추가하면, 원하는 날짜 스트링 형식을 훨씬 간결하고 빠르게 구현할 수 있다.</p>
<h3 id="🔰-2-테스트-코드-작성">🔰 2. 테스트 코드 작성</h3>
<p>이번 과제를 하면서 간단하지만, <code>테스트 코드</code>를 작성해보았다. 
(자주 쓰지 않으면 금방 까먹게 된다. 테스트 코드도 계속 공부해야겠다💪)</p>
<ul>
<li>정규표현식 테스트 실행 <a href="https://github.com/daeun-react/wanted-solar-connect/blob/main/src/Tests/Regex.test.js">&gt; 테스트 코드</a></li>
<li>오름차순/내림차순 테스트 실행 <a href="https://github.com/daeun-react/wanted-solar-connect/blob/main/src/Tests/Sort.test.js">&gt; 테스트 코드</a></li>
<li>입력데이터 배열로 변환 테스트 실행 <a href="https://github.com/daeun-react/wanted-solar-connect/blob/main/src/Tests/StringToArray.test.js">&gt; 테스트 코드</a></li>
</ul>
<h3 id="🔰-3-정렬-알고리즘">🔰 3. 정렬 알고리즘</h3>
<p>입력데이터의 형식은 “숫자,숫자,숫자…” (예&gt; 1,2,3,4) 이렇게만 보고 정렬은 간단하군! 
복잡하게 생각하지 말고 구현이 쉬운 버블 정렬을 선택했는데... 
회고록을 쓰면서 성능이 더 좋은 정렬 알고리즘을 구현했어야 했나...? 싶은 마음이 든다.😥
<a href="https://coding-factory.tistory.com/615">&gt; 정렬 알고리즘 시간복잡도</a></p>
<hr>
<h3 id="과제-내용">과제 내용</h3>
<p><strong>1. 타이머</strong></p>
<ul>
<li>재사용 가능한 Timer 컴포넌트 만들기</li>
<li>한국 표준 시 기준으로 타이머 생성 
“ko-KR” 지역시간 표기법 (예&gt; 2021년 7월 20일 화요일),
“en-US” 지역시간 표기법 (예&gt; Tuesday July 20, 2021) </li>
</ul>
<p><strong>2. 입력</strong></p>
<ul>
<li>입력 데이터의 형식은 “숫자,숫자,숫자…” (예&gt; 1,2,3,4)</li>
<li>잘못된 형식의 입력 데이터는 예외처리 필요</li>
</ul>
<p>*<em>3. 시작 버튼 및 결과 *</em></p>
<ul>
<li>사용자가 시작 버튼을 누르면 소팅이 시작.</li>
<li>오름차순 결과가 바로 보여지고, 3초 후 내림차순 결과 보여주기</li>
<li>결과 데이터의 형식은 “숫자, 숫자, 숫자…” (예&gt; 1, 2, 3, 4)</li>
<li>알고리즘은 소팅알고리즘(sort)을 사용하지 않고, 본인이 구현할 수 있는 정렬 방법으로 직접 구현</li>
</ul>
<hr>
<h3 id="구현-내용정리">구현 내용정리</h3>
<h3 id="🔰--1-타이머----구현코드">🔰  <strong>1. 타이머</strong>   <a href="https://velog.io/@daeun-react/Assignment-6-%EC%86%94%EB%9D%BC%EC%BB%A4%EB%84%A5%ED%8A%B8-Sorting-Machine">&gt;&gt; 구현코드</a></h3>
<ul>
<li><code>setInterval()</code> 함수를 통해 <code>new Date()</code>를 1초마다 다시 받아온다.</li>
<li><code>dateLocalFunc()</code> 함수를 생성하여 보여줘야 할 지역시간 표기법으로 변경한다.</li>
<li><code>toLocaleString()</code> : 사용자의 문화권에 맞는 시간표기법으로 년,월,일 시간을 리턴한다.</li>
</ul>
<p><strong>⭐ <code>toLocaleString</code> 함수 사용할 때, 아래처럼 다양한 옵션이 있는지 몰랐다.
옵션만 잘 사용해도 나중에 날짜 관련 코드 짜는 데 많은 도움이 될 것 같다!!</strong>
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat">참고 - MDN - Intl.DateTimeFormat() constructor</a></p>
<pre><code class="language-css">`weekday`
- &quot;long&quot; (e.g., Thursday) /  &quot;short&quot; (e.g., Thu) / &quot;narrow&quot; (e.g., T).

`year`
- &quot;numeric&quot; (e.g., 2012) / &quot;2-digit&quot; (e.g., 12)

`month`
- &quot;numeric&quot; (e.g., 2) / &quot;2-digit&quot; (e.g., 02) / &quot;long&quot; (e.g., March) / &quot;short&quot; (e.g., Mar) / &quot;narrow&quot; (e.g., M)

`day`
- &quot;numeric&quot; (e.g., 1) / &quot;2-digit&quot; (e.g., 01)

`timeZone`
- The time zone to use. 
- The only value implementations must recognize is &quot;UTC&quot;; the default is the runtime&#39;s default time zone. 
- Implementations may also recognize the time zone names of the IANA time zone database, such as &quot;Asia/Shanghai&quot;, &quot;Asia/Kolkata&quot;, &quot;America/New_York&quot;.</code></pre>
<hr>
<h3 id="🔰--2-입력----구현코드">🔰  <strong>2. 입력</strong>   <a href="https://velog.io/@daeun-react/Assignment-6-%EC%86%94%EB%9D%BC%EC%BB%A4%EB%84%A5%ED%8A%B8-Sorting-Machine">&gt;&gt; 구현코드</a></h3>
<ul>
<li><p><strong>정규식</strong>으로 “숫자,숫자,숫자…”만 허용되고, 그 외는 에러로 간주하여 시작버튼을 누를 수 없도록 하였다.</p>
</li>
<li><p>그런데 결과값에는 공백이 포함되어 있고, “숫자,숫자,숫자…”만 입력하기엔 사용자가 공백을 입력하는 경우도 있을 것 같아 정규식에 콤마 &quot;,&quot; 앞 뒤로 공백을 허용하도록 변경하였다.</p>
</li>
<li><p>정규식이 맞게 되는지 확인을 위해 <strong>테스트 코드</strong>를 작성하여 확인했다.</p>
<pre><code class="language-jsx">// 정규 표현식
const inputRegEx = /^(([0-9])+[\s]?,[\s]?)*([0-9]+)$/;</code></pre>
</li>
</ul>
<hr>
<h3 id="🔰-3-시작-버튼-및-결과-----구현코드">🔰 *<em>3. 시작 버튼 및 결과 *</em>   <a href="https://velog.io/@daeun-react/Assignment-6-%EC%86%94%EB%9D%BC%EC%BB%A4%EB%84%A5%ED%8A%B8-Sorting-Machine">&gt;&gt; 구현코드</a></h3>
<ul>
<li><p>시작 버튼을 누르면 <code>stringToArray()</code> 함수로 입력된 값을 콤마&quot;,&quot; 기준으로 나누고, 모든 요소를 숫자로 변환한 배열 값을 반환시킨다.</p>
</li>
<li><p><code>bubbleSort(값, 정렬방식)</code> 에 따라 정렬되도록 함수를 실행시킨다.</p>
</li>
<li><p>오름차순이 되고 3초 후 내림차순이 보이는 로직을 구현하기 위해 <code>Promise</code>를 사용하였다.</p>
<pre><code class="language-javascript">new Promise((resolve, _reject) =&gt; {
  // 오름차순 로직 구현
  setTimeout(() =&gt; {
    resolve();
  }, 3000);
}).then(() =&gt; {
// 내림차순 로직 구현
});</code></pre>
</li>
<li><p>정렬하는 중에 input값 수정 및 button 클릭 이벤트가 발생하지 않도록 <code>disabled</code> 시켰다.</p>
</li>
<li><p>또, 내림차순은 3초 뒤 결과값이 나타나므로 기다리는 동안 <code>Loading...</code> 텍스트를 보여준다.</p>
</li>
<li><p>초기화 버튼을 추가하여 input값 및 소팅 결과를 초기화시킬 수 있도록 구현했다.</p>
</li>
</ul>
<hr>
<h3 id="👀-아쉬웠던-점과-해결방안">👀 아쉬웠던 점과 해결방안</h3>
<ol>
<li>정렬 알고리즘이라 당연히 양의 정수의 숫자로 생각했는데, 음수나 소수점에 대한 정렬도 되어야 한다. ➡ 리팩토링 하면서 테스트코드까지 함께 작성해봐야겠다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2021.08.16] 핵심 자바스크립트 개념2]]></title>
            <link>https://velog.io/@daeun-react/2021.08.16-%ED%95%B5%EC%8B%AC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B0%9C%EB%85%902</link>
            <guid>https://velog.io/@daeun-react/2021.08.16-%ED%95%B5%EC%8B%AC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B0%9C%EB%85%902</guid>
            <pubDate>Wed, 18 Aug 2021 04:04:52 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-실행-컨텍스트">📌 실행 컨텍스트?</h2>
<blockquote>
<p><strong>JavaScript 코드</strong>가 실행되고 있는 컨텍스트(환경)</p>
</blockquote>
<ul>
<li><p>실행컨텍스트는 <strong>실행할 코드</strong>에 제공할 환경 정보들을(변수 정보들) 모아놓는다. 
함수를 실행할 때마다, 그 함수에 대한 새로운 실행 컨텍스트를 생성하여 자신만의 고유한 컨텍스트에서 실행된다.</p>
</li>
<li><p>어떤 정보냐면.. 
→ 코드 실행하기 위한 여러가지 정보
→ ex) 어떤 변수가 있는지, 어떤 변수를 hoisting 할지, scope는 어떻고 scope chain은 어떻고, this는 어디에 어떻게 binding 되고 등등..</p>
</li>
</ul>
<hr>
<h2 id="📌-호이스팅">📌 호이스팅?</h2>
<h3 id="💡-변수의-호이스팅">💡 변수의 호이스팅</h3>
<ul>
<li>호이스팅은 <strong><code>변수의 선언</code>을 끌어올리는 것</strong>을 말한다.</li>
<li><strong>선언부를 끌어올리고, 할당은 코드가 실행되는 시점에 진행</strong>된다.</li>
</ul>
<blockquote>
<p>왜 y 변수에 
<code>Uncaught ReferenceError: y is not defined</code> 에러가 아닌, <code>undefined</code>가 찍힐까? </p>
</blockquote>
<pre><code class="language-javascript">var x = 1; 
console.log(x + &quot; &quot; + y); // ✅  &#39;1 undefined&#39;
var y = 2;

var x = 1; 
var y; // ✅ Declare y : 호이스팅이 발생하였으므로, undefined가 된다
console.log(x + &quot; &quot; + y); // &#39;1 undefined&#39;
y = 2; // Initialize y</code></pre>
<hr>
<h3 id="💡-var--let--const의-차이점">💡 var / let / const의 차이점</h3>
<ol>
<li><p><code>var</code>는 함수 레벨 스코프
<code>let</code>, <code>const</code>는 블록 레벨 스코프</p>
</li>
<li><p><code>var</code>로 선언한 변수는 선언 전에 사용해도 에러가 나지 않지만,
 <code>let</code>, <code>const</code>는 에러가 발생한다.</p>
</li>
<li><p><code>var</code>는 이미 선언되어있는 이름과 같은 이름으로 변수를 또 선언해도 에러가 나지 않지만,
<code>let</code>, <code>const</code>는 이미 존재하는 변수와 같은 이름의 변수를 또 선언하면 에러가 발생한다.</p>
</li>
<li><p><code>var</code>, <code>let</code>은 변수 선언시 초기 값을 주지 않아도 되지만,
 <code>const</code>는 반드시 초기값을 할당해야 한다.</p>
</li>
<li><p><code>var</code>, <code>let</code>은 값을 다시 할당할 수 있지만,
<code>const</code>는 한 번 할당한 값은 변경할 수 없다.
(단, 객체 안에 프로퍼티가 변경되는 것까지 막지는 못합니다)</p>
</li>
</ol>
<hr>
<p>** ✨ 2. 내용을 보면, 그럼 <code>let</code>과 <code>const</code>는 호이스팅이 되지 않는걸까? 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 할 수 있지만 사실 <code>var, let, const</code>는 다 호이스팅 된다. **</p>
<p>다만 <code>var</code>는 호이스팅 되면서 초기 값이 없으면 자동으로 undefined를 할당하고,
<code>let, const</code>는 자동으로 초기값이 할당되지 않는다. 
<code>let, const</code>는 변수가 선언되고 변수에 값이 할당 되기 전 <code>TDZ(Temporal Dead Zone)</code>에 있게 된다.</p>
<blockquote>
<p>*<em>Q1. TDZ 문제 &gt; 출력될 결과 값은?  *</em></p>
</blockquote>
<pre><code class="language-javascript">let letValue = &#39;out Scope&#39;;

function hello() {
  console.log(&#39;letValue&#39;, letValue);
  let letValue = &#39;inner scope&#39;;
};

hello();</code></pre>
<p>✅ 답 : <code>Uncaught ReferenceError: Cannot access &#39;letValue&#39; before initialization</code> 에러가 발생한다.</p>
<ol>
<li>JS엔진은 <code>letValue</code>변수와 <code>hello 함수</code>를 메모리에 등록한다.<br>➡ (<code>GlobalContext</code>의 <code>Lexical Enviroment</code>에 등록)</li>
<li><code>letValue</code>를 &#39;out Scope&#39;로 초기화한다.</li>
<li><code>hello() 함수</code>를 호출한다.</li>
<li><code>hello() 함수</code>를 호출하면 실행 컨텍스트가 만들어지고 <code>letValue</code>를 메모리에 등록 
➡ (<code>helloContext</code>의 <code>Lexical Enviroment에</code> 등록) 
*let은 블록레벨 스코프를 가진다.</li>
<li>console.log 실행
➡ <code>letValue</code>는 메모리에 초기화 되지 않은 채로 등록되어 있기 때문에 TDZ 상태에 있다 
➡ ReferenceError 발생!!!</li>
</ol>
<hr>
<h3 id="💡-함수의-호이스팅">💡 함수의 호이스팅</h3>
<h3 id="✅-함수-선언문function-declaration">✅ 함수 선언문(function declaration)</h3>
<pre><code class="language-javascript">function a(){
  //로직
}</code></pre>
<p>➡ function 정의만 존재하고 별도의 할당 명령이 없다.
➡ 함수 자체가 호이스팅이 된다.</p>
<pre><code class="language-javascript">catName(&quot;Chloe&quot;); // &quot;My cat&#39;s name is Chloe&quot;

function catName(name) {
  console.log(&quot;My cat&#39;s name is &quot; + name);
}</code></pre>
<h3 id="✅--함수-표현식function-expression">✅  함수 표현식(function expression)</h3>
<pre><code class="language-javascript">const a = function(){
  //로직
}</code></pre>
<p>➡ function 키워드로 정의한 함수를 변수에 할당하는 것을 말한다.
➡ 변수 const notHoisted; 선언만 호이스팅 되었고, 함수 할당 부분이 없으므로 에러 발생!</p>
<pre><code class="language-javascript">console.log(notHoisted) // undefined
notHoisted(); // TypeError: notHoisted is not a function

const notHoisted = function() {
   console.log(&#39;bar&#39;);
};</code></pre>
<hr>
<h2 id="📌-스코프">📌 스코프?</h2>
<ul>
<li>변수가 유효한(살아있는) 범위</li>
</ul>
<h3 id="💡-global-scope">💡 Global Scope</h3>
<ul>
<li>코드 어디에서든지 참조 가능</li>
<li>var로 선언한 변수는 전역 객체에 속하게 된다.(프로퍼티가 된다)<ul>
<li>client(브라우저)의 전역 객체는 <strong><code>window</code></strong>, Node.js에서는 <strong><code>global</code></strong></li>
</ul>
</li>
</ul>
<h3 id="💡-local-scope">💡 Local Scope</h3>
<ul>
<li>JavaScipt는 다른 언어와 달리 <strong>scope의 범위가 함수 블록 내</strong>이다. </li>
<li><strong>함수에 의해서만 scope가 생성</strong>된다. <em><strong>({} 블록과 상관이 없다!!!)</strong></em></li>
<li>JavaScipt에서 <strong>let, const로 변수를 선언할 때의 scope은 블록({}) 단위</strong>이다.</li>
</ul>
<pre><code class="language-jsx">    if (true) {
      var x = 5;
    }

    console.log(x);  // 5 → if 문 안에 있더라도, 일반 블록이므로 x는 전역변수가 된다.</code></pre>
<h3 id="💡-scope-chain">💡 Scope Chain</h3>
<ul>
<li>변수가 해당 scope에서 유효하지 않을 때, 안에서부터 <strong>바깥으로만</strong> 차례로 검색해 나가는 것</li>
</ul>
<blockquote>
<p><strong>Q1. Scope Chain</strong></p>
</blockquote>
<pre><code class="language-jsx">function sum() {
  var a = 3;
  var b = 5;

  function inner() {
    var b = 7;
    var c = 11;
    a = a + b + c;  // ✅ a = 3, b = 7, c = 11
    console.log(a);  // 21

  };
  console.log(a);  // 3
  inner();
  console.log(a);  // 21
};

sum();
console.log(a); // ✅ Uncaught ReferenceError: a is not defined</code></pre>
<blockquote>
<p><strong>Q2. Scope Chain</strong></p>
</blockquote>
<pre><code class="language-jsx">var a = 1;
var outer = function () {
    var inner = function () {
        console.log(a);
        var a = 3; // ✅ 호이스팅으로 undefined 출력됨.
    }
    inner();
    console.log(a);  // ✅ a의 값이 outer에 없으면 **바깥으로만** 차례로 검색해 나간다 ➡ 1 출력
}
outer();
console.log(a);  // ✅ 1 출력</code></pre>
<hr>
<h2 id="📌-클로져">📌 클로져?</h2>
<blockquote>
<p><strong>scope가 끝난 외부 함수의 변수를 참조할 수 있다.</strong></p>
</blockquote>
<ul>
<li><p><strong>예제</strong>
어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우, 
A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상</p>
<pre><code class="language-jsx">var A = function() {
  var a = 1;

  var B = function() {
      return ++a;
  };

  return B;
};
</code></pre>
</li>
</ul>
<p>var outer = A();
console.log(outer());  // 2
console.log(outer());  // 3</p>
<pre><code>  1. **`var outer = A()`** 에서 함수 B자체를 반환
      1. **`A()`** 실행했으므로 A의 실행컨텍스트는 종료됨
      2. **`outer`** 변수는 이제 **`B함수`**를 바라보고 있음
  2. **`outer()`** outer를 호출하면, 즉! B를 호출. a값은 계속 증가함
      1. B함수에는 a의 유효범위가 아니므로, 한 번 더 바깥(A)의 scope를 참조하고 계속 값이 증가함


- **메모리 관리**
  - JavaScript는 원래 메모리 관리에 신경쓰지 않아도 된다. 
    사용하지 않는 변수는 알아서 Garbage Collector에 수집
  - 그런데 closure에서는 의도적으로 변수를 사용하므로 메모리가 계속 소모됨
  ➡ 만약 GC에 수집되게 하려면 null이나 undefined를 할당하면 됨
---

## 📌 this?

- this는 실행컨텍스트가 생성될 때 결정된다. 
- 실행컨텍스트는 함수를 호출할 때 생성되므로, **this는 함수를 호출할 때 결정**된다.
- **this가 무엇이냐고 한다면 → this가 바라보고 있는 객체인데, 상황에 따라 대상이 달라진다.**

 ---

### 💡 1. 전역 공간에서 this가 바라보는 대상
- client(브라우저)에서는 `window`
- Node.js에서는 `global`

---

### 💡 2. 암시적 binding : 메서드로 호출될 때 this가 바라보는 대상 
- 객체의 프로퍼티에 할당된 함수를 호출하면, this는 해당 객체를 바라본다
- 물론 객체가 메서드로 호출해야 함

&gt; **Q1. 암시적 binding**

```jsx
var name = &#39;lee&#39;;
var user = {
  name: &#39;kim&#39;,
  getName: function() {
    console.log(this.name);
  },
  age: 50,
  child: {
    age: 15,
    underTwenty: function() {
      console.log(this.age);
      return this.age &lt; 20
    }
  }
}

user.getName();  // ✅ this는 user, &quot;kim&quot;
user.child.underTwenty();  // ✅ this는 user.child, &quot;15&quot;

user.parentUnderTwenty = user.child.underTwenty;
user.parentUnderTwenty(); // ✅ this는 user, &quot;50&quot;</code></pre><blockquote>
<p><strong>Q2. 암시적 binding</strong></p>
</blockquote>
<pre><code class="language-jsx">var name = &#39;lee&#39;;
var user = {
  name: &#39;kim&#39;,
  getName: function() {
    console.log(this.name); // ✅ &quot;kim&quot;

    var inner = function() {  // inner 함수에서 this는? -&gt; 전역 !!!
      console.log(this.name); // ✅ &quot;lee&quot;
    }
    inner();
  }
}

user.getName(); //✅ this는 user</code></pre>
<hr>
<h3 id="💡-3-명시적-binding--원하는-대상으로-this-binding">💡 3. 명시적 binding : 원하는 대상으로 this binding</h3>
<ul>
<li><h3 id="call">call</h3>
<p>➡ 함수를 호출할 때, 원하는 대상의 객체를 인자로 넘겨준다.</p>
</li>
<li><h3 id="apply">apply</h3>
<p>➡ call 메서드와 완전히 같은 기능이나, 호출할 함수에 인자를 배열로 넘김</p>
</li>
<li><h3 id="bind">bind</h3>
<p>➡ call과 비슷하지만, 바로 호출하는 것이 아니라 대상을 묶어놓기(binding)만 하는 것</p>
</li>
</ul>
<pre><code class="language-jsx">var user = {
  name: &#39;kim&#39;,
  getName: function() {
    console.log(this.name);
  },
  age: 50,
  child: {
    age: 15,
    underTwenty: function() {
      console.log(this.age); // ✅ user의 age : 50
      return this.age &lt; 20
    }
  }
}

user.child.underTwenty.call(user); //✅ this는 user로 명시적 binding</code></pre>
<hr>
<h3 id="💡-arrow-function">💡 arrow function</h3>
<ul>
<li>this의 대상이 어떤 객체가 호출했느냐로 결정되지 않는다.</li>
<li>함수 내부에 this는 없으며, scope chain의 가장 가까운 this로 대상 결정!</li>
</ul>
<hr>
<h3 id="💡-함수와-메서드-차이">💡 함수와 메서드 차이</h3>
<ul>
<li><p>함수와 메서드는 모두 function 키워드로 함수를 정의한 것을 의미</p>
</li>
<li><p><strong>메서드 : 객체의 프로퍼티로 함수가 정의</strong>되어야 한다. (=객체가 함수를 호출해야 메서드!)</p>
<pre><code class="language-jsx">  let user = {
      name: &#39;kim&#39;,
      underTwenty: function(age) {
          return age &lt; 20;
      }
  }

  user.underTwenty(30); // ✅ &quot;메서드&quot;!
  const under20 = user.underTwenty;
  under20(15); // ✅ 객체 안에 정의된 함수라도, 이것은 메서드가 아닌 &quot;함수&quot;!</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2021.08.12] 핵심 자바스크립트 개념1]]></title>
            <link>https://velog.io/@daeun-react/2021.08.12-%ED%95%B5%EC%8B%AC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B0%9C%EB%85%901</link>
            <guid>https://velog.io/@daeun-react/2021.08.12-%ED%95%B5%EC%8B%AC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B0%9C%EB%85%901</guid>
            <pubDate>Fri, 13 Aug 2021 08:14:49 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-동기와-비동기의-이해">📌 동기와 비동기의 이해</h2>
<h3 id="💡-동기synchronouse">💡 동기(Synchronouse)</h3>
<ul>
<li>현재 실행 중인 코드가 끝나야 다음 코드를 실행하는 것</li>
<li><strong>현재 실행중인 task가 종료될때까지, 다음 task가 대기하는 방식</strong></li>
<li>순차적으로 실행
➡ (장점) task 실행 순서가 보장된다.
➡ (단점) task가 블로킹(blocking) 된다.</li>
</ul>
<blockquote>
<pre><code class="language-js">// blocking 예시
const arr = [];
for (let i = 0; i &lt; 1000; i++) {
  arr.push(i);
  // 1000번 반복하면서 실행할 더더더더더 복잡한 코드
}
alert(&quot;안녕하세요);  // 확인 누를 때까지 console 안나옴
console.log(arr);</code></pre>
</blockquote>
<pre><code>
---

### 💡 비동기(Asynchronouse)
- 현재 실행 중인 코드가 완료되지 않아도, 다음 코드로 넘어감
- **비동기 task는 실행하라고 `브라우저`에 맡겨놓고, 다음 task로 넘어감**
  ➡ (장점) task가 블로킹(blocking) 되지 않는다.
  ➡ (단점) task 실행 순서가 보장된다.

&gt; ```javascript
// 화면 그리기 1
axios.get(url)
  .then(response =&gt; {
    // api 호출하고 응답받으면 실행
  })
// 화면 그리기 2
// 다른 로직~~</code></pre><ol>
<li>화면그리기 1 하고,</li>
<li>axios api 호출하고 (언제 응답이 올지는 모름)</li>
<li>화면그리기 2 하다가</li>
<li>응답이 오면 로직을 실행하고,</li>
<li>다시 다른 로직 진행한다.</li>
</ol>
<h3 id="💡-비동기-처리가-필요한-이유">💡 비동기 처리가 필요한 이유</h3>
<p><a href="https://velog.io/@daeun-react/Q.-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84">&gt; 이벤트루프 작성내용 참고</a></p>
<ul>
<li>자바스크립트 엔진은 <strong>한 번에 하나의 task만 실행할 수 있는 Single Thread.</strong> </li>
<li>Single Thread는 한 번에 하나의 task만 실행할 수 있기 때문에 처리에 시간이 걸리는 task를 실행하는 경우 <strong>Blocking(작업 중단)이 발생</strong>한다. ➡ 콜백함수의 등장!!</li>
</ul>
<hr>
<h2 id="📌-콜백함수-callback-function-cb">📌 콜백함수 (Callback Function; cb)</h2>
<ul>
<li><strong>함수의 매개변수가 함수일 때, 매개변수로 받은 함수</strong>를 콜백함수라고 부른다.</li>
<li>콜백 헬, 콜백 지옥 발생 ➡ function()안에 function()안에 function()안에 계속 코드 작성..</li>
</ul>
<blockquote>
<pre><code class="language-javascript">// [1] 콜백함수 예시 =&gt; 동기 함수 =&gt; closeFn이 콜백함수!
function showMessage(msg, closeFn) {
  closeFn(true);
}
</code></pre>
</blockquote>
<p>// [2] 콜백함수 예시 =&gt; 동기 함수 =&gt;  map 함수의 인자 el =&gt; el<em>2 함수가 콜백함수!
[1,2,3].map(el =&gt; el</em>2);</p>
<blockquote>
</blockquote>
<p>// [3] 콜백함수 예시 =&gt; 비동기 함수 =&gt; e =&gt; {} 함수가 콜백함수!
window.addEventListener(&#39;keydown&#39;, e =&gt; {
  // 로직
});</p>
<blockquote>
</blockquote>
<p>// [4] 콜백함수 예시 =&gt; 비동기 함수 =&gt; setTimeout에 넘긴 익명함수가 콜백함수!
setTimeout(function(){ 
  alert(&quot;Hello&quot;); 
}, 3000);</p>
<pre><code>
---


## 📌 Promise ?
- 비동기 동작을 처리하기 위해 ES6에 도입되었다.
- **Promise는 클래스**다.
- Promise 클래스를 **인스턴스화 해서 promise 객체를 만든다**.
- **반환된 promise로 원하는 비동기 동작을 처리**한다.
- Promise는 **`state`, `resolve`, `reject` 함수를 이해**하면 된다.

---

### 💡 1. resolve, reject

&gt; - **`resolve`** : 성공했을 때 실행할 함수

```javascript
let promise = new Promise(function(resolve, reject) {
  // 여기 비동기 로직을 작성!
  // 시켜놓고 언제 완료될지 모르는 로직!
  setTimeout(function() {
    resolve(&#39;hello world&#39;);// resolve 함수에 인자 넘기면
  }, 2000);
});

// resolve로 넘기는 콜백함수의 매개변수로 받을 수 있다.
promise.then(function(msg) {
  console.log(msg);  // 2초 뒤에 hello world!
});</code></pre><blockquote>
<p><strong><code>reject</code></strong> : 실패했을 때 실행할 함수</p>
</blockquote>
<pre><code class="language-javascript">let promise = new Promise(function(resolve, reject) {
  setTimeout(function() {
    reject(&#39;으악!&#39;); // 실패했다고 가정하고 reject 호출
  }, 2000);
});

// then 인자 둘 다 cb 함수
// 첫 번째는 성공했을 때 실행할 resolve 함수 정의
// 두 번째는 실패했을 때 실행할 reject 함수 정의
promise.then(function() {
    console.log(&#39;resolve&#39;);
  }, function(msg) {
    console.log(&#39;reject&#39;, msg);
});</code></pre>
<hr>
<blockquote>
<p><strong>Q1. Promise안에 resolve() 함수가 여러개 있으면 어떻게 동작할까?</strong></p>
</blockquote>
<pre><code class="language-javascript">let promise = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve(1); // ✅ 첫 번째 resolve 만 실행됨
        resolve(2);
    }, 1000);
});</code></pre>
<blockquote>
<p><strong>Q2. Promise안에 resolve(), reject() 함수가 여러개 있으면 어떻게 동작할까?</strong></p>
</blockquote>
<pre><code class="language-javascript">let promise = new Promise(function(resolve, reject) {
    setTimeout(function() {
        reject(1); // ✅ 첫 번째 reject 만 실행됨
        resolve(2);
        resolve(3);
    }, 1000);
});</code></pre>
<blockquote>
<p><strong>Q3. Promise안에 실행순서 맞추기!</strong></p>
</blockquote>
<pre><code class="language-javascript">let promise = new Promise(function(resolve, reject) {
    setTimeout(function() {
        console.log(1);
        resolve(2);
        console.log(3);
        resolve(4);
    }, 1000);
});

promise.then(function(data) {
    console.log(data);
});</code></pre>
<ol>
<li>console.log(1) </li>
<li>console.log(3) </li>
<li>resolve(2) 실행 &amp; console.log(2)
✅ ➡ 정답: 1 -&gt; 3 -&gt; 2</li>
</ol>
<hr>
<h3 id="💡-2-chaining">💡 2. chaining</h3>
<ul>
<li><strong>여러 개의 비동기 작업을 순차적으로 해야하는 경우</strong></li>
<li>순차적으로 각각의 작업이 이전 단계 비동기 작업을 성공하고 나서,
그 결과값을 이용하여 다음 비동기 작업을 실행해야 하는 경우</li>
<li><code>then의 콜백함수(=handler function)</code>는 여러 타입의 값을 반환할 수 있다.</li>
</ul>
<pre><code class="language-javascript">let promise = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve(1);
    }, 1000);
});

promise
  .then(function(first) {  
    console.log(&#39;first&#39;, first); // ✅ &#39;first&#39;,1
    return 22;  //값 2를 리턴
  })
  .then(function(second) { //second에 22가 들어온다.
    console.log(&#39;second&#39;, second); // ✅ &#39;second&#39;,22
    return new Promise(function(resolve, reject) { // new Promise를 리턴
      setTimeout(function() {
        resolve(333);
      }, 1000);
    });
  })
  .then(function(third) {
    console.log(&#39;third&#39;, third); // 1초 뒤 333 실행됨 // ✅  &#39;third&#39;, 333
  });</code></pre>
<hr>
<h3 id="💡-3-state">💡 3. state</h3>
<p> promise 객체는 &quot;상태&quot;를 갖고 있다.</p>
<ol>
<li><strong><code>Pending(대기)</code></strong>: 비동기 처리 로직이 아직 완료되지 않은 상태</li>
<li><strong><code>Fulfilled(이행)</code></strong>: 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태</li>
<li><strong><code>Rejected(실패)</code></strong>: 비동기 처리가 실패하거나 오류가 발생한 상태</li>
</ol>
<hr>
<h3 id="💡-4-에러-처리">💡 4. 에러 처리</h3>
<p>reject handler와 catch 방식은 똑같다. <strong>catch문이 가독성이 더 좋다.</strong></p>
<pre><code class="language-javascript">let promise = new Promise(function(resolve, reject) {
  setTimeout(function() {
    reject(&#39;으악!&#39;);
  }, 2000);
});

promise
  .then(function() {})
  .catch(function(err) {  // ✅ catch
    console.log(err);
  });</code></pre>
<hr>
<blockquote>
<p><strong>Q1. console.log 정답은? ➡ 4,5</strong></p>
</blockquote>
<pre><code class="language-javascript">function job() {
    return new Promise(function(resolve, reject) {
        reject(); // reject를 실행
    });
}

job()
  .then(function() {
    console.log(1);
  })
  .then(function() {
    console.log(2);
  })
  .then(function() {
    console.log(3);
  })
  .catch(function() {
    console.log(4); // ✅ 4 출력
  })
  .then(function() {
    console.log(5); // ✅ 5 출력
  });</code></pre>
<blockquote>
<p> *<em>Q2. console.log 정답은? ➡ success, error, Error caught *</em></p>
</blockquote>
<pre><code class="language-javascript">function job(state) {
    return new Promise(function(resolve, reject) {
        if (state) {
            resolve(&#39;success&#39;);
        } else {
            reject(&#39;error&#39;);
        }
    });
}

job(true)
  .then(function(data) {
    console.log(data); // ✅ job(true) 이므로 resolve 실행 &amp;&amp; &#39;success&#39; 출력
    return job(false); // return 값으로 job(false) 반환
  })
  .catch(function(error) { 
    console.log(error); // ✅ job(false) 이므로 reject 실행 &amp;&amp; &#39;error&#39; 출력
    return &#39;Error caught&#39;; // return 값으로 string 반환
  })
  .then(function(data) {
    console.log(data); // ✅ &#39;Error caught&#39;값을 전달 받음 &amp;&amp; &#39;Error caught&#39; 출력
    return job(true); // return 값으로 job(true) 반환
  })
  .catch(function(error) {
    console.log(error); //-&gt; job(true)의 resolve가 실행되므로 catch는 실행되지 않는다.
  });</code></pre>
<hr>
<h3 id="💡-5-promisefinally--promiseall">💡 5. Promise.finally() / Promise.all()</h3>
<ul>
<li><h3 id="promisefinally">Promise.finally()</h3>
<ul>
<li>finally() 메서드는 결과에 관계없이, promise가 처리되면 무언가를 프로세싱 또는 정리를 수행하려는 경우에 유용하다.</li>
<li>finally 콜백은 어떠한 인수도 전달받지 않는다.
➡  promise가 이행되었는지 또는 거부되었는지를 판단할 수 없기 때문!</li>
</ul>
</li>
<li><h3 id="promiseall">Promise.all()</h3>
<ul>
<li>여러 프로미스를 다 하고 그 다음에 하고 싶은 경우에 유용하다.</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
<p><strong>예제1 - Promise.all()</strong></p>
</blockquote>
<pre><code class="language-javascript">let urls = [
  &#39;https://api.github.com/users/iliakan&#39;,
  &#39;https://api.github.com/users/remy&#39;,
  &#39;https://api.github.com/users/jeresig&#39;
];

// map every url to the promise of the fetch
let requests = urls.map(url =&gt; fetch(url));

// Promise.all waits until all jobs are resolved
Promise
  .all(requests)
  .then(responses =&gt; responses.forEach(
    response =&gt; alert(`${response.url}: ${response.status}`)
));</code></pre>
<blockquote>
<p> <strong>예제2 - Promise.all() - 모든 promise가 resolve 될 때</strong></p>
</blockquote>
<pre><code class="language-javascript">const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) =&gt; {
  setTimeout(resolve, 3000, &#39;foo&#39;);
});

Promise.all([promise1, promise2, promise3]).then((values) =&gt; {
  console.log(values); // 3초 뒤 &gt; Array [3, 42, &quot;foo&quot;] 
});</code></pre>
<blockquote>
<p>*<em>예제3 - Promise.all() - reject되는 promise가 있다면?  *</em>
➡ <code>Promise.all()</code>은 배열 내 요소 중 어느 *<em>하나라도 거부하면 즉시 거부!! *</em></p>
</blockquote>
<pre><code class="language-javascript">const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) =&gt; {
  setTimeout(reject, 3000, &#39;foo&#39;);
});

Promise.all([promise1, promise2, promise3]).then((values) =&gt; {
  console.log(values); // 3초 뒤 &gt; `all:1 Uncaught (in promise) foo` 에러반환
});</code></pre>
<hr>
<h2 id="📌-async--await">📌 async &amp; await</h2>
<ul>
<li><p><code>async</code> function은 ES8에 도입되었으며, 비동기 함수를 선언한다.</p>
</li>
<li><p><code>async</code> function은 <strong>promise를 반환</strong>한다. </p>
</li>
<li><p><code>await</code>를 쓰려면 <code>async</code> 함수 안에 꼭 있어야 한다!</p>
<hr>
<ul>
<li><strong>(변경 전)</strong> 
.then().then().then() ~ 가독성이 떨어진다.</li>
</ul>
</li>
</ul>
<pre><code class="language-javascript">axios(&#39;https://api.test.com/proudcts&#39;)
  .then(function(response) {
    let firstProductId = response.products[0].id;
    return axios(&#39;https://api.test.com/proudct/comments?id=&#39;+firstProductId);
  })
  .then(function(response) {
    let firstCommentId = response.comments[0].id;
    return axios(&#39;https://api.test.com/proudct/comment/likes?id=&#39;+firstCommentId)
  })
  .then(function(response) {
    let likes = response.likes;
    let likesCount = likes.length;
});</code></pre>
<ul>
<li><p><strong>(변경 후)</strong> async/await 문법으로 수정하여 가독성을 높인다.</p>
<pre><code class="language-javascript">(async () =&gt; {
try {
 let productResponse = await fetch(&#39;https://api.test.com/proudcts&#39;);
 let firstProductId = productResponse.products[0].id;

 let commentResponse = await fetch(&#39;https://api.test.com/proudct/comments?id=&#39;+firstProductId);
 let firstCommentId = commentResponse.comments[0].id;

 let likeResponse = await fetch(&#39;https://api.test.com/proudct/comment/likes?id=&#39;+firstCommentId);
 let likesCount = likeResponse.likes.length;

} catch(error) {
 console.log(error);
}
})();</code></pre>
</li>
<li><p><code>fetch</code>/<code>axios</code> 함수는 <code>promise</code>를 반환한다</p>
</li>
<li><p><code>axios()</code>와 <code>new Promise()</code>는 똑같다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Assignment 3 리팩토링] 자란다 - 회원가입 페이지]]></title>
            <link>https://velog.io/@daeun-react/Assignment-3-%ED%9A%8C%EA%B3%A0%EB%A1%9D-%EC%9E%90%EB%9E%80%EB%8B%A4-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%ED%8E%98%EC%9D%B4%EC%A7%80-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@daeun-react/Assignment-3-%ED%9A%8C%EA%B3%A0%EB%A1%9D-%EC%9E%90%EB%9E%80%EB%8B%A4-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%ED%8E%98%EC%9D%B4%EC%A7%80-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 13 Aug 2021 08:10:53 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>2주 동안 진행된 과제 중에서, 꼭! 리팩토링 하고 싶은 부분을 선정하여 수정해주세요.</p>
</blockquote>
<h2 id="🔗-과제-제출-링크---노션"><a href="https://www.notion.so/683de4829a7749cfbcdbc8997137aaad">&gt; 🔗 과제 제출 링크 - 노션 &lt; </a></h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Assignment 5 알고리즘] 미스터카멜 - 주어진 문자의 자음별 개수를 구해주세요]]></title>
            <link>https://velog.io/@daeun-react/Assignment-5-%EB%AF%B8%EC%8A%A4%ED%84%B0%EC%B9%B4%EB%A9%9C-%EC%A3%BC%EC%96%B4%EC%A7%84-%EB%AC%B8%EC%9E%90%EC%9D%98-%EC%9E%90%EC%9D%8C%EB%B3%84-%EA%B0%9C%EC%88%98%EB%A5%BC-%EA%B5%AC%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</link>
            <guid>https://velog.io/@daeun-react/Assignment-5-%EB%AF%B8%EC%8A%A4%ED%84%B0%EC%B9%B4%EB%A9%9C-%EC%A3%BC%EC%96%B4%EC%A7%84-%EB%AC%B8%EC%9E%90%EC%9D%98-%EC%9E%90%EC%9D%8C%EB%B3%84-%EA%B0%9C%EC%88%98%EB%A5%BC-%EA%B5%AC%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</guid>
            <pubDate>Fri, 13 Aug 2021 08:09:12 GMT</pubDate>
            <description><![CDATA[<h3 id="🔗-노션-링크"><a href="https://www.notion.so/Assignment-5-1-4a5a7fda693e45ad966fd0f960a52e54">🔗 노션 링크</a></h3>
<hr>
<h3 id="📑-과제-내용">📑 과제 내용</h3>
<p>주어진 문자의 자음별 개수를 구해주세요.</p>
<ul>
<li>input: &quot;사과1호랑이,고니 수박BT닭&quot;</li>
<li>output: 
ㄱ:2
ㄴ:1
ㄷ:1
ㄹ:1
ㅁ:0
ㅂ:1
ㅅ:2
ㅇ:1
ㅈ:0
ㅊ:0
ㅋ:0
ㅌ:0
ㅍ:0
ㅎ:1</li>
</ul>
<hr>
<h3 id="🔰-자바스크립트-코드-작성">🔰 자바스크립트 코드 작성</h3>
<pre><code class="language-javascript">const input = &quot;사과1호랑이,고니 수박BT닭&quot;;
const BASE_INDEX = &#39;가&#39;.charCodeAt(0);
const CHOSUNG_LIST = [&#39;ㄱ&#39;, &#39;ㄲ&#39;, &#39;ㄴ&#39;, &#39;ㄷ&#39;, &#39;ㄸ&#39;, &#39;ㄹ&#39;, &#39;ㅁ&#39;, &#39;ㅂ&#39;, &#39;ㅃ&#39;, &#39;ㅅ&#39;, &#39;ㅆ&#39;, &#39;ㅇ&#39;, &#39;ㅈ&#39;, &#39;ㅉ&#39;, &#39;ㅊ&#39;, &#39;ㅋ&#39;, &#39;ㅌ&#39;, &#39;ㅍ&#39;, &#39;ㅎ&#39;];
const OUTPUT_LIST = [&#39;ㄱ&#39;, &#39;ㄴ&#39;, &#39;ㄷ&#39;, &#39;ㄹ&#39;, &#39;ㅁ&#39;, &#39;ㅂ&#39;, &#39;ㅅ&#39;, &#39;ㅇ&#39; , &#39;ㅈ&#39;, &#39;ㅊ&#39;, &#39;ㅋ&#39;, &#39;ㅌ&#39;, &#39;ㅍ&#39;, &#39;ㅎ&#39;];

const answer = (input) =&gt; {
  const CHOSUNG = input
    .replace(/[^ㄱ-ㅎ가-힣]/g, &quot;&quot;)
    .split(&quot;&quot;)
    .map((str) =&gt; CHOSUNG_LIST[parseInt((str.charCodeAt(0) - BASE_INDEX) / 588)]);

  return OUTPUT_LIST.reduce((acc, cur) =&gt; {
    acc[cur] = CHOSUNG.filter((str) =&gt; str === cur).length;
    return acc;
  }, {});
};

answer(input);

// {
//   &#39;ㄱ&#39;: 2,
//   &#39;ㄴ&#39;: 1,
//   &#39;ㄷ&#39;: 1,
//   &#39;ㄹ&#39;: 1,
//   &#39;ㅁ&#39;: 0,
//   &#39;ㅂ&#39;: 1,
//   &#39;ㅅ&#39;: 2,
//   &#39;ㅇ&#39;: 1,
//   &#39;ㅈ&#39;: 0,
//   &#39;ㅊ&#39;: 0,
//   &#39;ㅋ&#39;: 0,
//   &#39;ㅌ&#39;: 0,
//   &#39;ㅍ&#39;: 0,
//   &#39;ㅎ&#39;: 1
// }</code></pre>
<hr>
<h3 id="🔰-풀이과정-해설">🔰 풀이과정 해설</h3>
<ul>
<li><p><strong><code>replace(/^ㄱ-ㅎ가-힇/g, &quot;&quot;)</code> : 한글 외 다른 문자열을 제외한다.</strong></p>
</li>
<li><p><strong><code>split(&quot;&quot;)</code> : 문자열을 한 글자씩 배열로 바꾼다.</strong></p>
</li>
<li><p><strong><code>map((str) =&gt; CHOSUNG_LIST[parseInt((...)])</code> : 
[ &#39;사&#39;, &#39;과&#39;, &#39;호&#39;, &#39;랑&#39;, &#39;이&#39;, &#39;고&#39;, &#39;니&#39;, &#39;수&#39;, &#39;박&#39;, &#39;닭&#39; ]에 대한 초성을 뽑아내야 한다.</strong></p>
<ul>
<li><p>한글 유니코드에서 시작은 &#39;가&#39;로 <code>&#39;가&#39;.charCodeAt(0)=44032</code> 값이다.</p>
</li>
<li><p>&#39;가&#39; 다음 &#39;까&#39;는 <code>&#39;까&#39;.charCodeAt(0)=44620</code>로,
가 → 까 초성은 <code>588(=44620-44032)</code> 주기로 변경된다.</p>
</li>
<li><p>현재 문자열에 대한 초성을 알아내기 위해 <code>str.charCodeAt(0)</code> 에서 <code>&#39;가&#39;.charCodeAt(0)</code>를 빼고 초성 주기 588을 나눠 현재 문자열이 <code>CHOSUNG_LIST</code> 에 어디에 해당하는지 구한다.</p>
</li>
<li><p>결과로 문자열에 대한 초성 값이 배열로 받아진다.</p>
</li>
</ul>
</li>
<li><p><strong><code>OUTPUT_LIST.reduce((acc, cur) =&gt; {...}, {})</code> : 
[ &#39;ㅅ&#39;, &#39;ㄱ&#39;, &#39;ㅎ&#39;, &#39;ㄹ&#39;, &#39;ㅇ&#39;, &#39;ㄱ&#39;, &#39;ㄴ&#39;, &#39;ㅅ&#39;, &#39;ㅂ&#39;, &#39;ㄷ&#39; ]를 결과 형식에 맞게 카운트를 계산해줘야 한다.</strong></p>
<ul>
<li>&#39;ㄲ&#39;, &#39;ㄸ&#39;, &#39;ㅃ&#39;, &#39;ㅆ&#39;, &#39;ㅉ&#39; 5가지는 정답 output에 없어서 <code>OUTPUT_LIST</code> 변수를 따로 만들었다.</li>
<li><code>reduce</code> 함수를 통해 <code>CHOSUNG</code> 변수에서 현재 초성이 몇 개 있는지 확인해주면 된다!</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Q. 이벤트 루프]]></title>
            <link>https://velog.io/@daeun-react/Q.-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84</link>
            <guid>https://velog.io/@daeun-react/Q.-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84</guid>
            <pubDate>Fri, 13 Aug 2021 08:06:18 GMT</pubDate>
            <description><![CDATA[<p>코어 자바스크립트 책을 읽고 정리하였습니다.</p>
<hr>
<h2 id="이벤트-루프를-알아보기-전에👀">이벤트 루프를 알아보기 전에..👀</h2>
<blockquote>
<h4 id="자바스크립트는-싱글-스레드로-동작한다"><strong>&lt;&lt; 자바스크립트는 싱글 스레드로 동작한다 &gt;&gt;</strong></h4>
</blockquote>
<ul>
<li><p>자바스크립트를 공부할 때, 위의 말을 자주 듣게 된다.</p>
</li>
<li><p>싱글 스레드는 방식은 한 번에 하나의 태스크만 처리할 수 있다!
하지만 브라우저가 동작하는 것을 살펴보면 많은 태스크가 동시에 처리되는 것처럼 느껴진다.
(➡ HTML 요소가 애니메이션 효과를 통해 움직이면서 이벤트를 처리하기도 하고,
 HTTP 요청을 통해 서버로부터 데이터를 가지고 오면서 렌더링 하기도 한다. 
이처럼 자바스크립트의 동시성을 지원하는 것이 바로 <strong><code>이벤트 루프</code></strong>다.)</p>
<ul>
<li>싱글 스레드 방식으로 동작하는 것은 브라우저가 아니라 브라우저에 내장된 자바스크립트 엔진이라는 것에 주의하자.</li>
<li><em>➡ 자바스크립트 엔진은 싱글 스레드로 동작하지만, 브라우저는 멀티 스레드로 동작한다!*</em></li>
</ul>
</li>
</ul>
<hr>
<h2 id="자바스크립트-엔진-❓">자바스크립트 엔진 ❓</h2>
<p>자바스크립트 엔진은 크게 2개의 영역으로 구분할 수 있다.</p>
<ol>
<li><h3 id="📌-콜-스택-">*<em><code>📌 콜 스택</code> *</em></h3>
<p>함수를 호출하면 함수 실행 컨텐스트가 순차적으로 콜 스택에 푸시되어 순차적으로 실행된다. 자바스크립트 엔진은 단 하나의 콜 스택을 사용하기 때문에 최상위 실행 컨텍스트가 종료되어 콜 스택에서 제거되기 전까지는 다른 어떤 태스크도 실행되지 않는다.</p>
</li>
<li><h3 id="📌-힙"><strong><code>📌 힙</code></strong></h3>
<p>힙은 객체가 저장되는 메모리 공간이다. 
메모리에 값을 저장하려면 먼저 값을 저장할 메모리 공간의 크기를 결정해야 한다. 객체는 원시 값과는 달리 크기가 정해져 있지 않으므로 할당해야 할 메모리 공간의 크기를 런타임에 결정(동적 할당)해야 한다. 따라서 객체가 저장되는 메모리 공간인 힙은 구조화되어 있지 않다는 특징이 있다.</p>
</li>
</ol>
<p>➡  <code>콜 스택</code>과 <code>힙</code>으로 구성되어 있는 <strong>자바스트립트 엔진은 단순히 태스크가 요청되면 콜 스택을 통해 요청된 작업을 순차적으로 실행할 뿐이다.</strong></p>
<hr>
<h2 id="브라우저가-태스크-큐와-이벤트-루프를-제공한다-🎉">브라우저가 태스크 큐와 이벤트 루프를 제공한다 🎉</h2>
<ul>
<li>비동기 처리에서 소스코드의 평가와 실행을 제외한 모든 처리는 자바스크립트 엔진을 구동하는 환경인 브라우저 또는 Node.js가 담당한다. 이를 위해 브라우저 환경은 <code>태스크 큐</code>와 <code>이벤트 루프</code>를 제공한다. (➡ 자바스크립트의 동시성을 지원! )</li>
</ul>
<ol>
<li><h3 id="📌-태스크-큐-">*<em><code>📌 태스크 큐</code> *</em></h3>
<p>setTimeout이나 setInterval 과 같은 비동기 함수의 콜백 함수 또는 이벤트 핸들러가 일시적으로 보관되는 영역이다.</p>
</li>
<li><h3 id="📌-이벤트-루프-">*<em><code>📌 이벤트 루프</code> *</em></h3>
<p>콜 스택에 현재 실행중인 실행 컨텍스트가 있는지, 그리도 태스크 큐에 대기 중인 함수(콜백함수, 이벤트 핸들러 등)가 있는지 반복해서 확인한다.</p>
</li>
</ol>
<p><strong>➡ 만약 콜 스택이 비어있고 태스크 큐에 대기 중인 함수가 있다면 이벤트 루프는 순차적(FIFO)으로 태스크 큐에 대기 중인 함수를 콜 스택으로 이동시킨다.</strong> </p>
<hr>
<h2 id="예제를-통해-확인하기🔎">예제를 통해 확인하기🔎</h2>
<h2 id="➡-foo-bar-실행-순서-확인하기">➡ foo(), bar() 실행 순서 확인하기</h2>
<pre><code class="language-javascript">function foo(){
  console.log(&#39;foo&#39;);
}

function bar(){
  console.log(&#39;bar&#39;);
}

setTimeout(foo, 0);
bar();</code></pre>
<ol>
<li><p>전역 코드가 평가되어 실행 컨텍스트가 생성되고 콜 스택에 푸시된다.</p>
</li>
<li><p>전역 코드가 실행되기 시작하여 <code>setTimeout</code> 함수가 호출된다. 
이때 <code>setTimeout</code> 함수의 함수 실행 컨텍스트가 생성되고, 콜 스택에 푸시되어 현재 실행중인 실행 컨텍스트가 된다. 브라우저의 Web API인 타이머 함수도 함수이므로 함수 실행 컨텍스트를 생성한다.</p>
</li>
<li><p><code>setTimeout</code> 함수가 실행되면 콜백 함수를 호출 스케줄링하고 종료되어 콜 스택에서 팝 된다. 
이때 호출 스케일링, 즉 타이머 설정과 타이머가 만료되면 콜백 함수를 태스크 큐에 푸시하는 것은 브라우저의 역할이다.</p>
</li>
<li><p>브라우저가 수행하는 4-1과 자바스크립트 엔진이 수행하는 4-2는 병행 처리된다.</p>
<p>*<em>4-1. [브라우저] *</em>
➡ 브라우저는 타이머를 설정하고 만료를 기다린다. 이후 타이머가 만료되면 콜백 함수 <code>foo</code>가 태스크 큐에 푸시된다. 
✳ 위 예제의 경우 지연시간이 0 이지만 지연 시간이 4ms 이하인 경우 최소 지연 시간 4ms가 지정된다. 따라서 4ms 후에 콜백 함수 foo가 태스크 큐에 푸시되어 대기한다. 이 처리 또한 자바스크립트 엔진이 아니라 브라우저가 수행한다. 
✳ 이처럼 <code>setTimeout</code> 함수로 호출 스케쥴링한 콜백 함수는 정확히 지연 시간 후 호출된다는 보장은 없다. 지연 시간 이후 콜백함수가 태스크 큐에 푸시되어 대기하게 되지만 콜 스택이 비어야 호출되므로 약간의 시간차가 발생할 수 있기 때문이다.</p>
<p>*<em>4-2. [자바스크립트 엔진] *</em>
➡ <code>bar</code> 함수가 호출되어 <code>bar</code> 함수의 함수 실행 컨텍스트가 생성되고, 콜 스택에 푸시되어 현재 실행 중인 실행 컨텍스트가 된다. 
➡ 이후 <code>bar</code> 함수가 종료되어 콜 스택에서 팝 된다. 
✳ 이때  <code>foo</code> 함수는 아직 태스크 큐에서 대기 중이다.</p>
</li>
<li><p>전역 코드 실행이 종료되고 전역 실행 컨텍스트가 콜 스택에서 팝 된다. 이로써 콜 스택에서는 아무런 실행 컨텍스트도 존재하지 않게 된다.</p>
</li>
<li><p><code>이벤트 루프</code>에 의해 콜 스택이 비어 있음이 감지되고,
태스크 큐에서 대기 중인 콜백 함수 <code>foo</code>가 <code>이벤트 루프</code>에 이해 콜 스택에 푸시된다. 
➡ 콜백함수 <code>foo</code>의 함수 실행 컨텍스트가 생성되고, 콜 스택에 푸시되어 현재 실행중인 실행 컨텍스트가 된다. 
➡ 이후 <code>foo</code> 함수가 종료되어 콜 스택에서 팝 된다.</p>
</li>
</ol>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[Q. 브라우저 작동 원리]]></title>
            <link>https://velog.io/@daeun-react/Q.-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%9E%91%EB%8F%99-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@daeun-react/Q.-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%9E%91%EB%8F%99-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Fri, 13 Aug 2021 08:05:55 GMT</pubDate>
            <description><![CDATA[<p>코어 자바스크립트 책을 읽고 정리하였습니다.</p>
<hr>
<h2 id="브라우저가-html-css-js로-작성된-텍스트-문서를-어떻게-파싱해서-렌더링-하는지-알아보자">브라우저가 HTML, CSS, JS로 작성된 텍스트 문서를 어떻게 파싱해서 렌더링 하는지 알아보자</h2>
<hr>
<h3 id="🔄-브라우저의-렌더링-과정">🔄 브라우저의 렌더링 과정</h3>
<p><strong>- 전체적인 과정을 아래의 1~4와 같이 진행된다. 하나씩 자세히 알아보자!</strong></p>
<ol>
<li><p>브라우저는 HTML, CSS, JS, 이미지, 폰트 등 렌더링에 필요한 리소스를 요청하고 서버로부터 응답을 받는다.</p>
</li>
<li><p>브라우저의 렌더링 엔진은 서버로부터 응답된 HTML과 CSS를 파싱하여 DOM과 CSSOM을 생성하고 이들을 결합하여 렌더 트리를 생성한다.</p>
</li>
<li><p>브라우저의 자바스크립트 엔진은 서버로부터 응답된 자바스크립트를 파싱하여 AST(Abstract Syntax Tree)를 생성하고 바이트 코드로 변환하여 실행한다. 이때 자바스크립트는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있다. 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합된다.</p>
</li>
<li><p>렌더 트리를 기반으로 HTML 요소의 레이아웃(위치와 크기)을 계산하고 브라우저 화면에 HTML 요소를 페인팅한다.</p>
</li>
</ol>
<hr>
<h3 id="🌈-1-요청과-응답">🌈 1. 요청과 응답</h3>
<ul>
<li><p>브라우저의 핵심 기능은 필요한 리소스(HTML,CSS,JS,이미지,폰트 등)를 서버에 요청하고 서버로부터 응답받아서 브라우저에 시각적으로 렌더링하는 것</p>
</li>
<li><p>서버에 요청을 전송하기 위해 브라우저는 주소창을 제공한다</p>
</li>
<li><p>브라우저의 주소창에 URL을 입력하고 엔터키를 누르면 URL의 호스트 이름이 DNS를 통해 IP 주소로 변환되고, 이 IP 주소를 갖는 서버에게 요청을 전송한다.</p>
<blockquote>
<p><code>URI:https://www.mydomain.com:80/docs/search?category=js&amp;lang=ko#intro</code></p>
</blockquote>
<ul>
<li><code>URL: https://www.mydomain.com:80/docs/search</code></li>
<li><code>Scheme(Protocol): https</code></li>
<li><code>Host(Domain): www.mydomain.com</code></li>
<li><code>Port: 80</code></li>
<li><code>Path: /docs/search</code></li>
<li><code>Query: category=js&amp;lang=ko</code></li>
<li><code>Fragment: #intro</code></li>
</ul>
</li>
</ul>
<hr>
<h3 id="📕-2-1-html-파싱과-dom-생성">📕 2-1. HTML 파싱과 DOM 생성</h3>
<ul>
<li><p>브라우저의 요청에 의해 서버가 응답한 HTML 문서는 문자열로 이루어진 순수한 텍스트다.</p>
</li>
<li><p>순수한 텍스트인 HTML 문서를 브라우저에 시각적인 픽셀로 렌더링하려면 HTML 문서를 브라우저가 이해할 수 있는 자료구조(객체)로 변환하여 메모리에 저장해야 한다.</p>
</li>
</ul>
<blockquote>
<p><code>바이트</code> ➡ <code>문자</code> ➡ <code>토큰</code> ➡ <code>노드</code> ➡ <code>DOM</code></p>
</blockquote>
<ol>
<li>서버에 존재하던 HTML 파일이 브라우저에 의해 응답된다. 이때 서버는 브라우저가 요청한 HTML 파일을 읽어 들여 메모리에 저장한 다음 메모리에 저장된 <code>바이트(2진수)</code>를 인터넷을 경유하여 응답한다. 브라우저는 서버가 응답한 HTML 문서를 <code>바이트(2진수)</code> 형태로 응답받는다.</li>
</ol>
<ol start="2">
<li><p>응답된 바이트는 형태의 HTML 문서는 meta 태그의 charset 어트리뷰트에 지정된 인코딩 방식을 기준으로 <code>문자열</code>에 반환된다.</p>
</li>
<li><p>문자열로 반환된 HTML 문서를 읽어, 문법적으로 의미를 같는 코드의 최소 단위인 <code>토큰</code>들로 분해한다.</p>
</li>
<li><p>각 토큰들을 객체로 반환하여 <code>노드</code>들을 생성한다. 토큰의 내용에 따라 문서 노드, 요소 노드, 어트리뷰트 노드, 텍스트 노드가 생선된다. 노드는 이후 DOM을 구성하는 기본 요소가 된다.</p>
</li>
<li><p>HTML 문서는 HTML 요소들의 집합으로 이루어지며, HTML 요소는 중첩 관계를 갖는다. 모든 노드들은 트리 자료구조로 구성된다. 이 노드들로 구성된 트리 자료 구조를 <code>DOM</code> 이라 부른다.</p>
</li>
</ol>
<p><strong>➡ 즉, DOM은 HTML 문서를 파싱한 결과물이다.</strong></p>
<hr>
<h3 id="📒-2-2-css-파싱과-cssom-생성">📒 2-2. CSS 파싱과 CSSOM 생성</h3>
<ul>
<li><p>렌더링 엔진은 HTML을 처음부터 한 줄씩 순차적으로 파싱하여 DOM을 생성해 나가다가, CSS를 로드하는 link 태그나 style 태그를 만나면 DOM 생성을 일시 중단한다.</p>
</li>
<li><p>link 태그의 href 어트리뷰트에 지정된 CSS 파일을 서버에 요청하여 로드한 CSS 파일이나 style 태그 내의 CSS를 HTML과 동일한 파싱 과정(<code>바이트</code> ➡ <code>문자</code> ➡ <code>토큰</code> ➡ <code>노드</code> ➡ <code>DOM</code>)을 거치며 해석하여 CSSOM 파일을 생성한다.</p>
</li>
<li><p>이후 CSS 파싱을 완료하면 HTML 파싱이 중단된 시점부터 다시 HTML을 파싱하기 시작하여 DOM 생성을 재개한다.</p>
</li>
</ul>
<hr>
<h3 id="📗-2-3-렌더-트리-생성">📗 2-3. 렌더 트리 생성</h3>
<ul>
<li><p>렌더 트리 : 렌더링을 위한 트리 구조의 자료구조 
브라우저 화면에 렌더링 되지 않는 노드(ex. meta, script 태그)와 CSS에 의해 비표시(ex. display:none) 되는 노드들은 포함되지 않는다. 
➡ <strong>즉 렌더 트리는 화면에 렌더링 되는 노드만으로 구성된다.</strong></p>
</li>
<li><p>완성된 렌더 트리는 각 HTML 요소의 레이아웃(위치와 크기)을 계산하는 데 사용되며, 브라우저 화면에 픽셀을 렌더링하는 페인팅 처리에 입력된다.</p>
</li>
</ul>
<hr>
<h3 id="💥-3-자바스크립트-파싱과-실행">💥 3. 자바스크립트 파싱과 실행</h3>
<ul>
<li><p>HTML 문서를 파싱한 결과물로서 생성된 DOM은 HTML 문서의 구조와 정보뿐만 아니라 HTML 요소와 스타일 등을 변경할 수 있는 프로그래밍 인터페이스로서 DOM API를 제공한다.</p>
</li>
<li><p>자바스크립트 코드에서 DOM API를 사용하면 이미 생성된 DOM을 동적으로 조작할 수 있다.</p>
</li>
<li><p>자바스크립트 파일을 로드하는 script 태그나, 자바스크립트 코드를 콘텐츠로 담은 script 태그를 만나면 DOM 생성을 일시 중단한다.</p>
</li>
<li><p>그리고 script 태그의 src 어트리뷰트에 정의된 자바스크립트 파일을 서버에 요청하여 로드한 자바스크립트 파일이나, script 태그 내의 자바스크립트 코드를 파싱하기 위해 자바스크립트 엔진에 제어권을 넘긴다. </p>
</li>
<li><p>이후 자바스크립트 파싱과 실행이 종료되면 렌더링 엔진으로 다시 제어권을 넘겨 HTML 파싱이 중단된 지점부터 다시 HTML을 파싱을 시작하여 DOM 생성을 재개한다.</p>
</li>
</ul>
<hr>
<h3 id="🎨-4-리플로우와-리페인트">🎨 4. 리플로우와 리페인트</h3>
<ul>
<li><p>일반적인 브라우저 렌더링 과정 </p>
<ol>
<li><code>DOM/CSSOM Tree</code> (생성) </li>
<li><code>Render Tree</code> (생성) </li>
<li><code>Layout</code> (위치, 크기계산) </li>
<li><code>Paint</code> (색칠) </li>
<li><code>Composite</code> (조합)</li>
</ol>
</li>
<li><p>아래의 경우 반복해서 레이아웃 계산과 페인팅이 재차 실행된다.</p>
<ul>
<li>자바스크립트에 의한 노드 추가 또는 삭제</li>
<li>브라우저 창의 리사이징에 의한 뷰포트 크기 변경</li>
<li>HTML 요소의 레이아웃(위치, 크기)에 변경을 발생시키는 스타일 변경</li>
</ul>
</li>
</ul>
<ul>
<li><p><code>📌 리플로우(Reflow)</code> : 레이아웃 계산을 다시 하는 것
노드 추가/삭제, 요소의 크기/위치 변경, 윈도우 리사이징 등 레이아웃에 영향을 주는 변경이 발생한 경우에 실행됨 (ex. width/height 값 변경)</p>
</li>
<li><p><code>📌 리페인트(Repaint)</code> : 재결합된 렌더 트리를 기반으로 다시 페인트를 하는 것</p>
</li>
<li><p>리플로우, 리페인트가 반드시 순차적으로 동시에 실행되는게 아니다.
레이아웃에 영향이 없는 변경을 리페인트만 실행된다.
(ex. color, background-color 변경 시 Repaint만 실행됨)</p>
</li>
<li><p>(참고) 리플로우, 리페인트를 피하려면? ➡ GPU 도움받기 ➡ transform, opacity 속성을 변경</p>
</li>
</ul>
<hr>
<h3 id="🔎-자바스크립트-파싱에-의한-html-파싱-중단">🔎 자바스크립트 파싱에 의한 HTML 파싱 중단</h3>
<ul>
<li><p>렌더링 엔진과 자바스크립트 엔진은 직렬적으로 파싱을 수행한다.</p>
</li>
<li><p>script 태그의 위치에 따라 HTML 파싱이 블로킹되어 DOM 생성이 지연될 수 있어서, script 태그의 위치는 중요한 의미를 갖게된다.</p>
</li>
<li><p>자바스크립트를 body 요소의 가장 아래 위치시키면 좋은 점</p>
<ol>
<li>DOM이 완성되지 않은 상태에서 자바스크립트가 DOM을 조적하면 에러가 발생할 수 있으므로 하단에 위치하면 에러 상황을 피할 수 있다.</li>
<li>자바스크립트 로딩/파싱/실행으로 인해 HTML 요소들의 렌더링에 지장받는 일이 발생하지 않아 페이지 로딩 시작이 단축된다.</li>
</ol>
</li>
</ul>
<hr>
<h3 id="🔎-script-태그--asyncdefer-어트리뷰트">🔎 script 태그 &gt; async/defer 어트리뷰트</h3>
<p>위에 작성한 자바스크립트 파싱에 의한 DOM 생성이 중단되는 문제를 근본적으로 해결하기 위해 HTML5부터 script 태그에 <code>async</code>, <code>defer</code> 어트리뷰트가 추가되었다.</p>
<ul>
<li><p><code>📌 async</code> : 자바스크립트의 파싱과 실행은 파일의 로드가 완료된 직후에 진행되며, 이때 HTML 파싱이 중단된다. 여러개의 script 태그에 async 어트리뷰트를 지정하면 script 태그의 순서와 상관없이 로드가 완료된 자바스크립트부터 먼저 실행되므로 순서가 보장되지 않는다.</p>
</li>
<li><p><code>📌 defer</code> : 자바스크립트의 파싱과 실행은 HTML 파싱이 완료된 직후, 즉 DOM 생성이 완료된 직후(DOMContentLoaded) 진행된다. 따라서 DOM 생성이 완료된 이후 실행되어야 할 자바스크립에 유용하다.</p>
</li>
</ul>
<p>** ➡  <code>async/defer</code> 를 사용하면 HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 진행된다. <code>async/defer</code> 차이점은 실행 시점!**</p>
]]></description>
        </item>
    </channel>
</rss>