<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yoojin-kwon.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 04 May 2021 08:26:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yoojin-kwon.log</title>
            <url>https://images.velog.io/images/yoojin-kwon/profile/67b048a2-02d5-4368-b80c-d3106448cd41/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yoojin-kwon.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yoojin-kwon" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[new TIL. Routing]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-Routing</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-Routing</guid>
            <pubDate>Tue, 04 May 2021 08:26:04 GMT</pubDate>
            <description><![CDATA[<p>오늘은 리액트 라우터를 효율적인 설계하는 방법과 함께 웹 트랜드를 알아보고자 한다!</p>
<br>

<h3 id="🗂-spasingle-page-application와-함께-알아두면-좋은-개념">🗂 SPA(Single Page Application)와 함께 알아두면 좋은 개념</h3>
<p><strong>✔️ CSR(Client Side Rendering) 이란?</strong></p>
<p>처음 html 파일을 서버로부터 받아오고, 링크된 js를 서버에서 받아온 뒤 동적으로  랜더링하여 화면을 보여줌</p>
<p><strong>👎 CSR 단점</strong></p>
<ol>
<li>첫 화면을 랜더링하는 시간이 많이 소요됨</li>
<li>html 내 body가 비어져 있기 때문에 SEO에 불리함</li>
</ol>
<br>

<p>✔️ 단점을 보강하기 위해 과거 static sites에서 영감을 받은 <strong>SSR(Server Side Rendering)</strong></p>
<br>

<p><strong>👍 SSR 장점</strong></p>
<ol>
<li>첫 화면 랜더링 속도가 빨라짐</li>
<li>모든 컨텐츠가 html에 담겨오기 때문에 보다 효율적인 SEO 가능</li>
</ol>
<p><strong>👎 SSR 단점</strong></p>
<ol>
<li>사용자 인터렉션이 발생하면 전체 웹사이트를 서버에서 받아오기 때문에 user experience가 좋지 않을 수 있음(blinking issue!)</li>
<li>사용자가 많을 경우 과부하 걸리기 쉬움</li>
<li>need to wait before interacting</li>
</ol>
<br>

<p><strong>📌 CSR - SSR</strong></p>
<ul>
<li><p>** CSR** : 웹 어플리케이션 로직이 담긴 html, css, js를 받아온 뒤 웹 사이트가 사용자에게 보여지기 때문에 <code>TTV(Time to View)</code>, <code>TTI(Time to Interact)</code>가 동시에 이루어짐</p>
</li>
<li><p>*<em>SSR *</em>: 서버에서 index 파일을 받아온 뒤 사용자에게 웹 사이트를 보여줌. 하지만 동적으로 제어할 수 있는 js 파일을 받아오기 전까지는 인터렉션이 불가. 즉, <code>TTV</code> 뒤에 <code>TTI</code>가 이루어짐.</p>
</li>
</ul>
<hr>
<br>

<h3 id="💣-리랜더링을-막아라">💣 리랜더링을 막아라!</h3>
<p><strong>SPA(Single Page Application)</strong>에서 리액트는 컴포넌트를 분리하고 새로고침 없이 데이터를 동적으로 받을 수 있다는 점이 큰 장점이다. 
따라서, 컴포넌트는 <strong>랜더링</strong>을 기준으로 분리하는 것이 중요하다. </p>
<p>그렇기 때문에 라우팅을 하는 경우에도, header와 footer와 같이 모든 페이지에 공통적으로 들어가는 부분이 계속해서 랜더링되지 않게 하는 것이 중요하다. </p>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/4a4a9f50-c450-4122-b385-99c429de3f6b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-05-04%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.56.08.png" alt=""></p>
<p>마켓홀리 프로젝트 내 라우터의 문제점은 다른 컴포넌트로 이동했을 때, 계속해서 <code>&lt;Nav /&gt;</code>와 <code>&lt;Footer /&gt;</code>가 리랜더링된다는 것이다. 동기적으로 진행되어 속도 또한 늦어지게 된다. </p>
<p>따라서, Switch 부분을 컴포넌트로 따로 분리하여 그 내부에서만 랜더링이 되도록 하는 것이 성능 측면에서 유리할 것이다. </p>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/d7370565-4610-4a8e-b17c-9f07b21d4828/routing.001.jpeg.001.jpeg" alt=""></p>
<p>트리 구조를 위 이미지와 같이 설계한다면, 헤더와 네브 바와 같은 공통적인 부분은 패널이 다른 컴포넌트로 바뀔 때 다시 랜더링이 되지 않는다. </p>
<p>만약 네비게이션 바를 nested list 형태(클릭하면 상세 리스트가 열리도록)로 구성하고 싶다면, 클릭된 폴더만 랜더링되도록 각 폴더 별로 컴포넌트를 분리하는 것이 좋다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS-실행 컨텍스트]]></title>
            <link>https://velog.io/@yoojin-kwon/JS-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@yoojin-kwon/JS-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Sun, 02 May 2021 14:34:36 GMT</pubDate>
            <description><![CDATA[<ul>
<li>실행 컨텍스트</li>
<li>스택 &amp; 큐</li>
<li>함수 선언문 &amp; 함수 표현식
<img src="https://images.velog.io/images/yoojin-kwon/post/7df16ea5-9585-4607-acbe-c64d3415307d/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-30%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.42.30.png" alt=""></li>
<li>스코프 체인</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[new TIL. var vs. let]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-var-vs.-let</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-var-vs.-let</guid>
            <pubDate>Sun, 02 May 2021 14:34:10 GMT</pubDate>
            <description><![CDATA[<blockquote>
<pre><code class="language-javascript">console.log(age);
age = 4;
console.log(age);
var age;</code></pre>
</blockquote>
<pre><code>
**`var`** 
: 선언하기 전에 값을 할당할 수 있고, 값을 할당하기 전에 출력도 가능함 
👉 ** var 호이스팅**

&lt;br&gt;

#### 💣 var를 쓰면 안되는 이유

**1. var hoisting **: 어디에서 선언했는지 상관없이 항상 선언을 제일 위로 끌어올려주는 것 

**2. has no block scope** : 블럭을 이용해 선언을 했더라도 어디에서나 보일 수 있음. 규모있는 프로젝트를 진행할 경우 문제가 될 수 있음.

&lt;br&gt;

#### 📌 let - const
`let` = mutable data type
`const` = immutable data type 

&lt;br&gt;

#### 📌 favor immutable data type always 
1. 보안상 이유
2. thread safety
3. 협업 시 실수를 방지해줄 수 있음
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[📆 TODO APP 만들기]]></title>
            <link>https://velog.io/@yoojin-kwon/TODO-APP-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@yoojin-kwon/TODO-APP-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Tue, 27 Apr 2021 01:56:49 GMT</pubDate>
            <description><![CDATA[<p>간단한 일정관리 앱을 만들어 보았다.</p>
<p>기존에 앱의 구조와 컴포넌트들을 어떤 방식으로 설계해야 좋을지 고민이 많았는데, 튜토리얼을 따라 진행하니 개념이 보다 명확해진 것 같았다.(물론 정답은 없지만)</p>
<p>기존 프로젝트와 달리 컴포넌트 성능 최적화도 고민해볼 수 있는 기회였다!🤓</p>
<br>

<h3 id="⚙️-컴포넌트-구조">⚙️ 컴포넌트 구조</h3>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/dce1a0a5-9ae5-48d2-bfc2-b8c23ab20afb/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-25%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.03.25.png" alt=""></p>
<br>

<h3 id="📌-appjs--todotemplatejs">📌 App.js / TodoTemplate.js</h3>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/3bb83470-3357-4098-abb8-41634a92dbfd/code.png" alt=""></p>
<p>전체적으로 <code>TodoTemplate</code>컴포넌트가 input 창과 리스트를 감싸고 있는 구조이다. 그리고 <code>TodoTemplate.js</code>에서는 이를 {children}으로 받아오고 있다.</p>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/d722e6a8-44ec-4db8-a607-d8021d6b9d95/code1.png" alt=""></p>
<blockquote>
<h4 id="🔍-useref-사용한-이유">🔍 useRef 사용한 이유</h4>
<p>id은 새로운 항목을 만들때 참조되는 값이기 때문에 id가 바뀐다고 해서 다시 랜더링될 필요가 없다. 따라서 useRef를 사용하여 관리한다.</p>
</blockquote>
<blockquote>
<h4 id="🔍-usecallback-사용한-이유">🔍 useCallback 사용한 이유</h4>
<p>👉 랜더링 성능 최적화를 위해!
컴포넌트가 다시 랜더링될 때마다 함수를 만드는 것이 아니라, 한번 함수를 만들고 다시 재사용하기 위해 사용한다. </p>
</blockquote>
<h4 id="🔍-usecallback-사용법">🔍 useCallback 사용법</h4>
<p> 첫 번째 파라미터에는 생성하고 싶은 함수를, 두 번째 파리미터에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야 하는지 명시해준다(의존성 배열). 
onInsert 함수에서는 setTodos를 통해 todos 값이 변화하기 때문에 배열에 todos를 넣어주었다.</p>
<br>

<h3 id="📌-todoinsertjs">📌 TodoInsert.js</h3>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/c906b39f-4e94-48c4-839d-b43bc3173839/code2.png" alt=""></p>
<h4 id="1-oninsert-함수">1. onInsert 함수</h4>
<p>input 참에 입력된 텍스트를 받으면, 변수 todo에 nextId와 text, checked를 할당해준다. 그 후 concat 함수를 활용해 배열에 새로 입력된 항목을 추가해주고, nextId를 현재의 값에서 +1 해준다. </p>
<blockquote>
<h4 id="🔍-form-태그를-사용한-이유">🔍 form 태그를 사용한 이유</h4>
<p>input과 button 태그를 form 태그로 묶어주고, form 태그 내에서 onSubmit 이벤트를 준 이유는 버튼 클릭과 엔터 키로 입력할 수 있기 때문이다. 
➕ 더불어, semantic value와 가독성 측면에서도 의미가 있다고 생각한다.</p>
</blockquote>
<p>onChange 함수를 통해 input에 입력된 value 값을 업데이트 한다. 
사용자가 추가 버튼을 클릭했을 때 onSubmit 함수가 실행되는데, 여기에서는 value를 onInsert의 파라미터로 넣어주고 <code>setvalue(&#39;&#39;)</code>를 통해 input 창을 초기화 시켜둔다. </p>
<p><code>e.preventDefault()</code>는 onSubmit 이벤트가 브라우저를 새로고침 시키는 것을 방지해준다. </p>
<br>

<h3 id="📌-todolistjs">📌 TodoList.js</h3>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/f6543a09-3722-4de1-9c81-500d72f77bec/code3.png" alt=""></p>
<p>App.js에서 넘겨준 todos, onRemove, onToggle를 props로 받고, map 함수를 통해 TodoListItem 컴포넌트를 리스트로 만들어준다.</p>
<br>

<h3 id="📌-todolistitemjs">📌 TodoListItem.js</h3>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/b3cb6d38-eacd-4719-9909-4253972c2cc7/code4.png" alt=""></p>
<p>App.js에서 넘겨준 onRemove, onToggle 함수를 props로 받고 있다.</p>
<h4 id="1-onremove-함수">1. onRemove 함수</h4>
<p>클릭된 항목의 id를 받아 다시 setTodos를 해준다. 여기서 기존 데이터를 변형하지 않는 filter 함수를 사용해 클릭된 항목 이외의 것만 남겨준다. </p>
<p>마지막으로 state <code>todos</code>가 변형되었을 때 해당 함수가 실행될 수 있도록 의존성 배열에 todos를 넣어주고, useCallback 함수로 감싸주어 랜더링 성능을 최적화 해준다.</p>
<h4 id="2-ontoggle-함수">2. onToggle 함수</h4>
<p>체크하면 가운데 선이 생기고 다시 클릭하면 원래대로 돌아오는 토글 기능을 구현하기 위해 map 함수를 사용하여 기존 todos state에서 체크된 항목을 반영해 새로운 배열을 반환했다. </p>
<p>삼항연산자를 활용해 체크가 되었다면 스프레드 연산자로 나머지 항목은 유지하고 checked만 <code>!todo.checked</code>를 주었다. </p>
<br>

<blockquote>
<h4 id="🔍-classnamecncheckbox-checked">🔍 <code>className={cn(&#39;checkbox&#39;, {checked})}</code></h4>
</blockquote>
<ul>
<li><code>import cn from &#39;classnames&#39;;</code></li>
<li>조건부 스타일링을 주기 위해 classNames 라이브러리 사용</li>
<li>{checked}가 true인 경우 <code>className=&quot;checkbox checked&quot;</code>가 되는 것을 볼 수 있다.!<img src="https://images.velog.io/images/yoojin-kwon/post/8dbfda23-2966-46c8-a266-7bdf89c453fc/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-27%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.13.31.png" width="400px"></li>
</ul>
<br>

<h3 id="📌-css">📌 CSS</h3>
<ul>
<li><p><code>transition: 0.3s background ease-in;</code>
버튼 호버 시, 보다 부드러운 효과를 주기 위해 사용</p>
</li>
<li><p><code>&amp;:nth-child(even) {
  background-color: rgb(240, 240, 240);
}</code>
짝수번째 리스트는 배경 색상을 회색으로 주기 위해 사용</p>
</li>
<li><p>`svg {</p>
<pre><code>font-size: 20px;</code></pre><p>  }`
  react icon을 사용할 경우 아이콘에 className을 주었는데 그럴 필요 없이 svg로 명시하면 된다!</p>
</li>
</ul>
<ul>
<li><code>&amp; + &amp; {
  border-top: 1px solid lightgray;
}</code>
= <code>.todoListItem + .todoListItem {
  border-top: 1px solid lightgray;
}</code>
리스트 사이에 border를 줄 때 사용</li>
</ul>
<br>

<h3 id="📆-완성">📆 완성!</h3>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/a2455ed6-3b1c-4eee-9281-ad293d22421b/%E1%84%92%E1%85%AA%E1%84%86%E1%85%A7%E1%86%AB-%E1%84%80%E1%85%B5%E1%84%85%E1%85%A9%E1%86%A8-2021-04-27-%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB-10.57.02.gif" alt=""></p>
<hr>
<p>참고) 리액트를 다루는 기술</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[new TIL. Hooks - useEffect]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-Hooks-useEffect</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-Hooks-useEffect</guid>
            <pubDate>Sun, 25 Apr 2021 12:55:56 GMT</pubDate>
            <description><![CDATA[<h3 id="📌-useeffect">📌 useEffect</h3>
<p>랜더링이 될 때마다 실행되는 함수.
처음 랜더링될 때 + setState를 통해 업데이트가 될 때마다 실행된다.
<img src="https://images.velog.io/images/yoojin-kwon/post/5a802284-c1a0-425f-b196-b0c6b6e42a45/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.00.18.png" width="500px"><img src="https://images.velog.io/images/yoojin-kwon/post/675d59e5-d439-4982-9d3c-47efa5dcec00/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.19.32.png" width="500px"></p>
<p>👉 처음 랜더링될 때만 실행하고 싶다면, useEffect 함수의 두번째 파라미터로 빈 배열을 넣어주면 된다.
<img src="https://images.velog.io/images/yoojin-kwon/post/e8ccfd03-5353-4832-9ff2-95cef170ac3e/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.21.38.png" width="300px"></p>
<p>👉 <strong>의존성 배열 추가</strong>
특정 값이 업데이트될 때만 실행하고 싶다면 배열 내 검사하고 싶은 값을 넣어주면 된다.</p>
<blockquote>
<pre><code class="language-jsx">useEffect(()=&gt; {console.log({name})}, [name])
// 처음 랜더링될 때에도 useEffect가 실행되는 것을 알 수 있다. 
// 이는 state 초기값을 처음 세팅해주었기 때문! </code></pre>
</blockquote>
<p>```</p>
<p>👉 <strong>clean up!</strong>
컴포넌트가 unmount 되기 전 + 업데이트되기 전 실행하고 싶다면 cleanup 함수를 반환해주어야 한다.</p>
<ul>
<li>다음 번 랜더링보다 먼저 실행됨</li>
<li>cleanup 함수는 클로저로서 이전 환경을 기억하고 있음</li>
<li>unmount 되기 전에만 실행하고 싶다면 두번째 파라미터로 빈 배열을 넣어주면 됨</li>
</ul>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/bceb48df-bcae-4404-a753-25d79cc31b07/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.53.39.png" width="500px"><img src="https://images.velog.io/images/yoojin-kwon/post/4cf6dbfd-43c2-43b1-a0c9-e4961a0e8654/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.54.28.png" width="300px"></p>
<hr>
<p>참고) <a href="https://simsimjae.tistory.com/400?category=384814">https://simsimjae.tistory.com/400?category=384814</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[new TIL. Data Type]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-Data-Type</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-Data-Type</guid>
            <pubDate>Sun, 25 Apr 2021 07:24:41 GMT</pubDate>
            <description><![CDATA[<h3 id="🗂-변수variable-식별자identifier">🗂 변수(variable), 식별자(identifier)</h3>
<ul>
<li><strong>변수</strong> : 변경 가능한 데이터가 담길 수 있는 공간</li>
<li><strong>식별자</strong> : 어떤 데이터를 식별하는 데 사용되는 이름, 변수명</li>
</ul>
<br>

<h3 id="🗂-데이터-할당-과정">🗂 데이터 할당 과정</h3>
<ul>
<li><p>*<em>기본형 데이터 *</em>
: 변수 선언 시, 메모리 빈 공간에 식별자 저장, 우선 그 공간의 값은 undefined로 할당. 데이터 할당 시, 별도의 공간에 데이터 저장, 그 공간의 주소를 변수의 값 영역에 할당.</p>
</li>
<li><p><strong>참고형 데이터</strong>
: 참고형 데이터 내부 프로퍼티들을 위한 변수 영역 별도로 확보하고 확보된 주소를 변수에 연결.</p>
</li>
</ul>
<br>

<h3 id="🗂-불변값-가변값">🗂 불변값, 가변값</h3>
<h4 id="🔍-불변값의-성질">🔍 불변값의 성질</h4>
<p>변수 a에 &#39;abc&#39;를 할당했다가 뒤에 &#39;def&#39;를 추가하면 기존의 값이 바뀌는 것이 아니라 새로운 문자열 &#39;abcdef&#39;를 만들어서 그 주소를 변수 a에 저장함. 이와 같이 변경은 새로 만드는 동작을 통해서만 이루어지며, 가비지 컬렉팅을 당하지 않는 한 한번 만들어진 값은 영원히 변하지 않음.</p>
<p>기본형 데이터_(number, string, boolean, null, undefined, symbol)_는 모두 불변값</p>
<h4 id="🔍-참조형-데이터가-가변값인-경우">🔍 참조형 데이터가 가변값인 경우</h4>
<blockquote>
<pre><code class="language-javascript">// 기본형 데이터
var a = 10;
var b = a;
b = 15;
// 참고형 데이터
var obj1 = {c: 10, d: &#39;ddd&#39;};
var obj2 = obj1;
obj2.c = 20;</code></pre>
</blockquote>
<pre><code>
![](https://images.velog.io/images/yoojin-kwon/post/db0ef185-c33e-412a-a101-a91a055d9ce6/%E1%84%86%E1%85%AE%E1%84%8C%E1%85%A6.001.jpeg)

#### 🔍 참조형 데이터를 불변값으로 사용하는 경우
값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우
- 내부 프로퍼티들을 일일이 복사(깊은 복사)
- `immutable.js`, `ìmmer.js`와 같은 라이브러리 활용</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[new TIL. 데이터 추가/제거 기능 구현]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B6%94%EA%B0%80%EC%A0%9C%EA%B1%B0-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B6%94%EA%B0%80%EC%A0%9C%EA%B1%B0-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Mon, 19 Apr 2021 13:45:21 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/yoojin-kwon/post/01cc9750-a411-477f-8e0e-3920e6d40311/%E1%84%92%E1%85%AA%E1%84%86%E1%85%A7%E1%86%AB-%E1%84%80%E1%85%B5%E1%84%85%E1%85%A9%E1%86%A8-2021-04-19-%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE-9.04.19.gif" width=600px>input에 입력된 데이터를 추가하고, 더블 클릭한 데이터를 제거하는 기능을 구현하고자 한다.</p>
<br>

<h3 id="1-state-설정">1. state 설정</h3>
<p>map 함수를 활용하여 리스트를 구현할 것이기 때문에 key 역할을 할 id도 객체에 담아준다.</p>
<pre><code class="language-jsx">  const [names, setNames] = useState([
    { id: 1, text: &#39;React&#39; },
    { id: 2, text: &#39;JS&#39; },
    { id: 3, text: &#39;SASS&#39; },
    { id: 4, text: &#39;Styled Component&#39; },
  ]);</code></pre>
<p>미리 설정한 데이터 외 추가될 데이터가 있기 때문에 state 값을 업데이트 시켜줄 수 있어야 한다.</p>
<pre><code class="language-jsx">  const [nextId, setNextId] = useState(5);
  const [nextText, setNextText] = useState(&#39;&#39;);
</code></pre>
<br>

<h3 id="2-map-함수-구현">2. map 함수 구현</h3>
<p><strong>기존 배열로 새로운 배열을 만드는 map 함수</strong>를 활용하여 list를 구현한다.
여기서 <code>names</code>는 처음에 설정한 state 값, <code>name</code>은 배열 내 각 요소를 의미한다. </p>
<pre><code class="language-jsx">      &lt;ul&gt;
        {names.map(name =&gt; (
          &lt;li key={name.id}&gt;
            {name.text}
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;</code></pre>
<br>

<h3 id="3-데이터-추가-기능-구현">3. 데이터 추가 기능 구현</h3>
<p>데이터를 추가하기 위해 우선 input과 button을 만들어준다.
여기서 초기값인 value는 새롭게 입력될 nextText로 설정해준다. 
❗️이 초기값이 없다면 나중에 button을 클릭한 후 입력된 값을 초기화하는 기능을 구현할 수 없다.</p>
<p>또한, 입력된 값으로 state 값을 업데이트 시켜주기 위해 onChange 이벤트도 추가해준다.
여기서 엔터를 쳤을 때도 list에 추가될 수 있게 구현하기 위해 onKeyPress 이벤트도 함께 넣어준다.</p>
<pre><code class="language-jsx"> &lt;input
        type=&quot;text&quot;
        name=&quot;newStack&quot;
        value={nextText}
        onChange={onChangeInput}
        onKeyPress={onKeyPressInput}
      /&gt;</code></pre>
<pre><code class="language-jsx">  const onChangeInput = e =&gt; {
    setNextText(e.target.value);
  };

  const onKeyPressInput = e =&gt; {
    if (e.key === &#39;Enter&#39;) {
      onClickInput();
    }
  };</code></pre>
<blockquote>
<p><strong>🧐 e는 무엇일까?</strong>
콘솔 로그를 통해 <code>SyntheticBaseEvent</code>가 찍히는 것을 확인할 수 있다. 이벤트 핸들러는 모든 브라우저에서 이벤트를 동일하게 처리하기 위한 이벤트 래퍼 SyntheticEvent 객체를 전달받는다고 한다. 객체를 확인해보면 <code>e.target.value</code>는 input에 입력한 값이, <code>e.key</code>는 keyboard에서 누른 값이 찍히는 것을 알 수 있다.</p>
</blockquote>
<p>사용자는 input에 추가하고 싶은 값을 입력하고, 엔터를 치거나 버튼을 클릭할 것이다. 그럼 onClick 이벤트를 통해 onClickInput 함수가 실행되도록 구현을 했다.</p>
<pre><code class="language-jsx">&lt;button onClick={onClickInput}&gt;레벨업&lt;/button&gt;</code></pre>
<pre><code class="language-jsx">  const onClickInput = () =&gt; {
    const nextNames = names.concat({
      id: nextId,
      text: nextText,
    });
    setNextId(nextId + 1);
    setNames(nextNames);
    setNextText(&#39;&#39;);
  };</code></pre>
<p>concat 함수를 통해 names 배열에 새로운 id와 text를 추가해주고, setNextid를 통해 id를 업데이트 해준다. setNames를 통해 새로운 배열을 업데이트해주고, 마지막으로 input 창에 입력된 값을 초기화해주기 위해 <code>setNextText(&#39;&#39;)</code>를 사용해준다.</p>
<blockquote>
<p><strong>🧐 왜 concat 함수를 썼을까?</strong>
 기존 배열에 새로운 요소를 추가하는 함수는 push와 concat이 있다. 둘의 차이는 push는 아예 기존 배열 자체를 변경해주고, concat은 기존 배열을 복사하여 새로운 배열에 요소를 추가한다.
리액트는 데이터를 변형시키지 않음으로써 성능 최적화라는 효과를 얻을 수 있다. 더 자세한 내용은 앞으로 차차 알아가기로 하고... 우선은 이러한 이유 때문에 concat 함수를 썼다는 사실만 기억하자!</p>
</blockquote>
<br>

<h3 id="4-데이터-제거-기능-구현">4. 데이터 제거 기능 구현</h3>
<p>더블 클릭한 리스트 요소를 사라지게 하고 싶기 때문에 이벤트의 위치는 list에 둔다. </p>
<pre><code class="language-jsx">      &lt;ul&gt;
        {names.map(name =&gt; (
          &lt;li key={name.id} onDoubleClick={() =&gt; onRemove(name.id)}&gt;
            {name.text}
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;</code></pre>
<p>실행되는 onRemove 함수에서 어떤 값을 제거할지 알아야 하기 때문에 props로 더블 클릭한 요소의 id값을 넘겨준다. </p>
<pre><code class="language-jsx">  const onRemove = id =&gt; {
    const nextNames = names.filter(name =&gt; name.id !== id);
    setNames(nextNames);
  };</code></pre>
<p>그럼 그 id 값을 받아 filter 함수로 제거해주는데, filter 함수를 쓰는 이유도 아까 concat 함수를 쓰는 이유와 동일하다. id 값이 더블 클릭된 요소의 id 값과 같지 않는 것만 남겨준다. 그리고 다시 setNames!</p>
<blockquote>
<p><strong>🧐 filter 함수</strong></p>
</blockquote>
<pre><code class="language-jsx">const numbers = [1,2,3,4,5,6];
const withoutThree - numbers.filter(number =&gt; number !== 3); 
// [1,2,4,5,6]</code></pre>
<br>

<p>종합해보면,</p>
<pre><code class="language-jsx">function IterationSample() {
  const [names, setNames] = useState([
    { id: 1, text: &#39;React&#39; },
    { id: 2, text: &#39;JS&#39; },
    { id: 3, text: &#39;SASS&#39; },
    { id: 4, text: &#39;Styled Component&#39; },
  ]);

  const [nextText, setNextText] = useState(&#39;&#39;);
  const [nextId, setNextId] = useState(5);

  const onChangeInput = e =&gt; {
    setNextText(e.target.value);
  };

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

  const onClickInput = () =&gt; {
    const nextNames = names.concat({
      id: nextId,
      text: nextText,
    });
    setNextId(nextId + 1);
    setNames(nextNames);
    setNextText(&#39;&#39;);
  };

  const onRemove = id =&gt; {
    const nextNames = names.filter(name =&gt; name.id !== id);
    setNames(nextNames);
  };

  return (
    &lt;div className=&quot;iterationSample&quot;&gt;
      &lt;h3&gt;Skills&lt;/h3&gt;
      &lt;ul&gt;
        {names.map(name =&gt; (
          &lt;li key={name.id} onDoubleClick={() =&gt; onRemove(name.id)}&gt;
            {name.text}
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
      &lt;input
        type=&quot;text&quot;
        name=&quot;newStack&quot;
        value={nextText}
        onChange={onChangeInput}
        onKeyPress={onKeyPressInput}
      /&gt;
      &lt;button onClick={onClickInput}&gt;레벨업&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre>
<hr>
<p>참고) 리액트를 다루는 기술</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[new TIL. React Portals & Modal]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-React-Portals-Modal</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-React-Portals-Modal</guid>
            <pubDate>Fri, 16 Apr 2021 07:48:46 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/yoojin-kwon/post/e1c5ebbe-b463-4915-aa54-728a504e921e/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-16%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.03.19.png" alt=""></p>
<p>모달 창은 사용자에게 특정 내용을 강조하여 전달하고자 할 때 사용한다. 모달 창에 대한 주목도를 높이기 위해 일반적으로 배경을 어두운 색상으로 두어 대비를 준다. </p>
<p>그런데 위 이미지와 같이 다른 컨텐츠들이 모달 창보다 높은 z-index를 가진다면? 좋은 모달 창이라고 할 수 없을 것이다. </p>
<p>해결 방법으로 <strong>React Portals</strong>를 알아보고자 한다!</p>
<br>

<h3 id="📌-portals-이란">📌 Portals 이란?</h3>
<blockquote>
<p><code>React portal</code> is just a way to render components outside of the normal DOM hierarchy that is defined by the component tree.</p>
</blockquote>
<p>부모 컴포넌트 밖에서 랜더링되기 때문에 부모의 스타일을 상속받지도 않고, 모달 창과 같이 가장 위에 있는 레이어에서 구현되어야 할 경우 z-index을 설정하기도 편리하다.</p>
<blockquote>
<p>&quot; portals의 일반적인 사용 사례는 부모 컴포넌트가 overflow: hidden 이나 z-index 스타일을 가지지만, 자식이 컨테이너에서 시각적으로 “이탈해야 하는” 경우입니다. &quot;</p>
</blockquote>
<p>➕ 부모 컴포넌트와 같은 DOM 트리에 있지 않기 때문에 불필요한 랜더링이 발생하지 않는다.</p>
<blockquote>
<p>&quot; React portal is an incredibly useful tool since it allows rendering of components outside the normal DOM hierarchy without breaking event propagation of the component hierarchy. This is incredibly useful when rendering components such as modals, tooltips, popup messages, and so much more. &quot;</p>
</blockquote>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/e639edd5-0123-4886-85f2-e14438c4b65c/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-16%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.31.53.png" width="500px">( 위 코드처럼 other content의 z-index가 2라면 Modal 컴포넌트의 z-index가 아무리 높아도 부모의 z-index가 1이기 때문에 처음 보았던 이미지처럼 모달 창이 열렸을 때도 other content가 진하게 보인다🥲 )</p>
<br>

<h3 id="📌-그럼-어떻게-사용하면-될까">📌 그럼 어떻게 사용하면 될까?</h3>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/601e4fad-12da-492d-80d2-38818b9f936c/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-16%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.04.34.png" alt="">React에서는 가상 DOM이 들어갈 껍데기의 역할을 하는 index.html이 있다. 거기에는 <code>&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;</code>가 있고, 그것이 <code>index.js</code>를 통해 <code>App.js</code>로 연결되어 있다.</p>
<p>id가 root라는 DOM 외부에서 랜더링을 하기 위해서는 <code>ReactDOM.createPortal(child, container)</code>을 사용하면 된다.
<img src="https://images.velog.io/images/yoojin-kwon/post/a57fff7d-3730-41e3-8a45-5a3d0be612dd/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-16%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.09.08.png" width="500px"></p>
<p>여기서 container는 UI를 랜더링 시키고자 하는 DOM을 의미한다. </p>
<pre><code class="language-jsx">  &lt;body&gt;
    &lt;noscript&gt;You need to enable JavaScript to run this app.&lt;/noscript&gt;
    &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;div id=&quot;portal&quot;&gt;&lt;/div&gt;
  &lt;/body&gt;</code></pre>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/4e79edd2-d153-42ab-bbfe-bb232d316c51/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-16%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.43.15.png" alt=""></p>
<p>그러면 개발자 도구에서 전체 화면과 모달 창 컴포넌트 위치가 분리된 것을 볼 수 있다.</p>
<br>

<h3 id="📌-모달-창-구현-로직">📌 모달 창 구현 로직</h3>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/06295f92-c2b5-4ee4-b145-36b0e6fb8ab2/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-16%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.20.43.png" width="550px"><img src="https://images.velog.io/images/yoojin-kwon/post/a57fff7d-3730-41e3-8a45-5a3d0be612dd/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-16%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.09.08.png" width="500px"></p>
<p>부모 컴포넌트에서 모달 창을 열고 닫는 상태를 관리하는 <code>isOpen</code> state를 만들어주고, <code>open</code> props를 넘겨준다. onClick 이벤트가 실행될 경우, setInOpen 함수를 통해 state <code>isOpen</code>을 true 값으로 바꿔준다. </p>
<p>모달 창이 닫힐 때는 반대로 setInOpen 함수를 통해 state <code>isOpen</code>을 false로 바꿔주는데, 자식 컴포넌트인 Modal에 Close Modal 버튼이 있기 때문에 props로 넘겨주어야 한다. </p>
<p>따라서, state 값을 false로 변경해주는 함수를 onClose라는 props로 넘겨주고, <code>onClick={onClose}</code>를 통해 받아주면 된다!</p>
<br>

<hr>
<p>참고)
<a href="https://www.youtube.com/watch?v=LyLa7dU5tp8&amp;t=279s">-Learn React Portal In 12 Minutes By Building A Modal</a>
<a href="https://reactjs-kr.firebaseapp.com/docs/portals.html">-React Portals</a>
<a href="https://velog.io/@velopert/react-portals">-Portals 를 통한 부모 컴포넌트의 외부 DOM 에 컴포넌트 렌더링하기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[new TIL. Recoil]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-Recoil</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-Recoil</guid>
            <pubDate>Tue, 13 Apr 2021 11:43:38 GMT</pubDate>
            <description><![CDATA[<p>Redux vs. Mobx, 치열한 논쟁에서 새롭게 등장한 Recoil.
Recoil은 무엇일까?</p>
<hr>
<h3 id="📌-recoil">📌 Recoil?</h3>
<p><em>&quot;A state management library for React&quot;</em></p>
<br>

<h3 id="📌-recoilroot">📌 RecoilRoot</h3>
<blockquote>
</blockquote>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import {
  RecoilRoot,
  atom,
  selector,
  useRecoilState,
  useRecoilValue,
} from &#39;recoil&#39;;
ㅤ
function App() {
  return (
    &lt;RecoilRoot&gt;
      &lt;CharacterCounter /&gt;
    &lt;/RecoilRoot&gt;
  );
}</code></pre>
<p>Components that use recoil state need <code>RecoilRoot</code> to appear somewhere in the parent tree. </p>
<br>

<h3 id="📌-atom---데이터-조각">📌 Atom - &quot;데이터 조각&quot;</h3>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/91dac3fb-257d-4d45-b037-5174aad16498/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-13%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.00.53.png" alt=""></p>
<blockquote>
<p><code>Atom</code></p>
</blockquote>
<pre><code class="language-javascript">const fontSizeState = atom({
  key: &#39;fontSizeState&#39;,
  default: 14,
});</code></pre>
<blockquote>
<p>Atoms are units of state. They&#39;re updateable and subscribable: when an atom is updated, each subscribed component is re-rendered with the new value. They can be created at runtime, too. Atoms can be used in place of React local component state. If the same atom is used from multiple components, all those components share their state.</p>
</blockquote>
<br>

<h3 id="📌-userecoilstate">📌 useRecoilState</h3>
<blockquote>
<p><code>useRecoilState</code></p>
</blockquote>
<pre><code class="language-javascript">function FontButton() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  ㅤ
  return (
    &lt;button onClick={() =&gt; setFontSize((size) =&gt; size + 1)} style={{fontSize}}&gt;
      Click to Enlarge
    &lt;/button&gt;
  );
}</code></pre>
<blockquote>
<p>To read and write an atom from a component, we use a hook called <code>useRecoilState</code>. It&#39;s just like React&#39;s useState, but now the state can be shared between components.</p>
</blockquote>
<br>

<h3 id="📌-selector">📌 selector</h3>
<p><strong>1. Atom에서 파생된 데이터 조각
2. 데이터를 반환하는 순수함수</strong></p>
<blockquote>
<p><code>selector</code></p>
</blockquote>
<pre><code class="language-javascript">const fontSizeLabelState = selector({
  key: &#39;fontSizeLabelState&#39;,
  get: ({get}) =&gt; {
    const fontSize = get(fontSizeState);
    const unit = &#39;px&#39;;
ㅤ
    return `${fontSize}${unit}`;
  },
});</code></pre>
<blockquote>
<p><code>selector</code>는 atom의 상태에 의존하는 동적인 데이터를 생성합니다. selector에서는 get 함수(필수항목)를 통해 atom 정보들을 1개 이상 가져올 수 있습니다. 이를 통해 atom을 조합하여 간단히 새로운 데이터를 생성할 수 있습니다. 
물론 atom의 정보가 바뀌면 해당 atom을 의존하는 selector도 자동으로 리랜더링이 됩니다. 또한 한개 이상의 atom 정보를 업데이트 하도록 set 함수(선택항목)를 받을 수 있습니다. 
[인용_<a href="https://blog.woolta.com/categories/1/posts/209">https://blog.woolta.com/categories/1/posts/209</a>]</p>
</blockquote>
<br>

<h3 id="📌-userecoilvalue">📌 useRecoilValue</h3>
<blockquote>
<p><code>useRecoilValue</code></p>
</blockquote>
<pre><code class="language-javascript">function FontButton() {
  const [fontSize, setFontSize] = useRecoilState(fontSizeState);
  const fontSizeLabel = useRecoilValue(fontSizeLabelState);
ㅤ
  return (
    &lt;&gt;
      &lt;div&gt;Current font size: {fontSizeLabel}&lt;/div&gt;
      &lt;button onClick={() =&gt; setFontSize(fontSize + 1)} style={{fontSize}}&gt;
        Click to Enlarge
      &lt;/button&gt;
    &lt;/&gt;
  );
}</code></pre>
<blockquote>
<p>구독하는 값만 반환하는 함수입니다. 값의 update 함수가 필요없을 경우 사용합니다.</p>
</blockquote>
<br>

<h3 id="📌-suspense">📌 Suspense</h3>
<ul>
<li>컴포넌트가 완전히 랜더링될 수 있을 때까지 랜더링을 하지 않고 기다리는 역할</li>
<li>간단하게 비동기 상태 처리 가능
<img src="https://images.velog.io/images/yoojin-kwon/post/2fed2397-aba0-4b7c-b965-4bd4a27fd850/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-13%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.22.03.png" alt=""><img src="https://images.velog.io/images/yoojin-kwon/post/d1b163f6-345e-44d6-8b06-7c9c55676929/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-13%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.25.12.png" alt=""></li>
</ul>
<br>

<h3 id="📌-concurrent-mode">📌 Concurrent Mode</h3>
<ul>
<li>어떤 컴포넌트를 언제 랜더링할지 리액트 framwork가 알아서 최적화를 해주는 개념</li>
<li>간단하게 접근할 수 있는 API가 바로 React Suspense<br>

</li>
</ul>
<hr>
<p>[참고]</p>
<ul>
<li><a href="https://recoiljs.org/">https://recoiljs.org/</a></li>
<li><a href="https://tv.naver.com/v/16970954#comment_focus">https://tv.naver.com/v/16970954#comment_focus</a></li>
<li><a href="https://blog.woolta.com/categories/1/posts/209">https://blog.woolta.com/categories/1/posts/209</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 로마자 숫자로 변환]]></title>
            <link>https://velog.io/@yoojin-kwon/Algorithm-%EC%A4%91%EB%B3%B5%EB%90%98%EC%A7%80-%EC%95%8A%EC%9D%80-%EC%95%8C%ED%8C%8C%EB%B2%B3-%EB%8B%A8%EC%96%B4-%EA%B8%B8%EC%9D%B4-return-hgdns02c</link>
            <guid>https://velog.io/@yoojin-kwon/Algorithm-%EC%A4%91%EB%B3%B5%EB%90%98%EC%A7%80-%EC%95%8A%EC%9D%80-%EC%95%8C%ED%8C%8C%EB%B2%B3-%EB%8B%A8%EC%96%B4-%EA%B8%B8%EC%9D%B4-return-hgdns02c</guid>
            <pubDate>Sun, 11 Apr 2021 14:34:33 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<img src="https://images.velog.io/images/yoojin-kwon/post/ab057a17-f826-4fe4-a50b-c661a7c2e6a5/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.34.17.png" width="400px">

<h2 id="해결">해결</h2>
<pre><code class="language-javascript">const roman = {
  &#39;I&#39; : 1,
  &#39;V&#39; : 5,
  &#39;X&#39; : 10,
  &#39;L&#39; : 50,
  &#39;C&#39; : 100,
  &#39;D&#39; : 500,
  &#39;M&#39; : 1000,
}

const romanToNum = s =&gt; {
  let arr = s.split(&quot;&quot;);

  let result = arr.reduce((acc, val, idx) =&gt; {
    let curVal = roman[val];
    let nextVal = roman[arr[idx + 1]];

    if (curVal &lt; nextVal) {
     acc -= curVal
    } else {
      acc += curVal
    }
    return acc;
  }, 0)

  return result;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 중복되지 않은 알파벳 단어 길이 return]]></title>
            <link>https://velog.io/@yoojin-kwon/Algorithm-%EC%A4%91%EB%B3%B5%EB%90%98%EC%A7%80-%EC%95%8A%EC%9D%80-%EC%95%8C%ED%8C%8C%EB%B2%B3-%EB%8B%A8%EC%96%B4-%EA%B8%B8%EC%9D%B4-return</link>
            <guid>https://velog.io/@yoojin-kwon/Algorithm-%EC%A4%91%EB%B3%B5%EB%90%98%EC%A7%80-%EC%95%8A%EC%9D%80-%EC%95%8C%ED%8C%8C%EB%B2%B3-%EB%8B%A8%EC%96%B4-%EA%B8%B8%EC%9D%B4-return</guid>
            <pubDate>Sun, 11 Apr 2021 14:30:58 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<img src="https://images.velog.io/images/yoojin-kwon/post/6924afe7-b27b-4388-a030-0d717acff1cb/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.00.57.png" width="500px">

<h2 id="해결">해결</h2>
<pre><code class="language-javascript">const getLengthOfStr = str =&gt; {
    let arr = [];
    let newStr = &#39;&#39;;

    for (let i in str) {
        if (newStr.includes(str[i])) {
            newStr = newStr.slice(newStr.indexOf(str[i]) + 1);    
        }
        newStr += str[i];
        arr.push(newStr.length);
    }
    return Math.Max(...arr);
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[new TIL. git - rebase ver.]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-git-rebase-ver</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-git-rebase-ver</guid>
            <pubDate>Sun, 11 Apr 2021 14:22:12 GMT</pubDate>
            <description><![CDATA[<ol>
<li><p>작업하던 브랜치에서 <code>git add .</code> 👉 <code>git commit -m &quot;커밋메시지&quot;</code></p>
</li>
<li><p><code>git checkout master</code> 👉 <code>git pull origin master</code></p>
</li>
<li><p><code>git checkout branch</code> 👉 <code>git rebase -i master</code></p>
</li>
<li><p>충돌 해결 (package-lock-json의 경우, 충돌 해결하지 않고 최종 머지할 때 삭제 후 다시 <code>npm install</code>)</p>
</li>
<li><p><code>git add .</code> 👉 <code>git rebase --continue</code></p>
</li>
<li><p><code>git log</code> 👉 <code>git push origin branch -f</code></p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[new TIL. 함수형 컴포넌트, Hooks]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-%ED%95%A8%EC%88%98%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-Hooks</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-%ED%95%A8%EC%88%98%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-Hooks</guid>
            <pubDate>Sun, 04 Apr 2021 14:31:42 GMT</pubDate>
            <description><![CDATA[<h3 id="📌-hook">📌 Hook</h3>
<h4 id="usestate">useState</h4>
<p><code>const [state, setState ] = useState(initialState);</code></p>
<ul>
<li>setState : state를 업데이트할 때 사용하는 함수</li>
<li>initialState : 최초 렌더링 시 반환되는 state 값과 같다.</li>
</ul>
<blockquote>
<p><strong>Example</strong></p>
</blockquote>
<pre><code class="language-javascript">function Example() {
  const [count, setCount] = useState(0);
    const [isModalActive, setIsModalActive] = useState(false);
  return (
    &lt;div&gt;
      &lt;p&gt;You clicked {count} times&lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;
        Click me
      &lt;/button&gt;
      &lt;button onClick={() =&gt; setIsModalActive(!isModalActive)}&gt;modal btn
      &lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre>
<br>

<h4 id="useeffect">useEffect</h4>
<p><code>useEffect(() =&gt; {}, [state]);</code></p>
<ul>
<li>useEffect : 첫 번째 랜더링, 그리고 그 후 state가 업데이트될 때마다 실행</li>
<li>의존성 배열 : state 값의 변화만을 감지, state가 바뀔 때만 effect를 재실행(조건부 effect 발생)</li>
</ul>
<blockquote>
<p>*<em>cf. Lifecycle *</em>
<img src="https://images.velog.io/images/yoojin-kwon/post/836adc19-b308-4c42-884a-12fc02cde0b7/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-04-01%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.02.40.png" alt=""></p>
</blockquote>
<blockquote>
<p>** effect에서 함수를 반환하는 이유_effect를 위한 추가적인 정리(clean-up) 메커니즘**<br>
: 클린업 함수가 클로저로서 생성될 시점은 이전 렌더링이 되었을 때이기 때문에 이전 환경을 기억하고 있다.</p>
</blockquote>
<ul>
<li>클로저 : 자신이 생성될 시점의 환경을 기억하는 함수<pre><code class="language-javascript">const Foo = () =&gt; {
const [state, setState] = useState(0);
console.log(&quot;render&quot;, state); // 버튼 클릭 후 render, 1
useEffect(() =&gt; {
  console.log(&quot;useEffect Callback&quot;, state); // 버튼 클릭 후 callback, 1
  return () =&gt; console.log(&quot;cleanUp&quot;, state); // 버튼 클릭 후 cleanUp, 0
}, [state]);
return &lt;div onClick={() =&gt; setState(state + 1)}&gt;버튼&lt;/div&gt;;
};
export default Foo;</code></pre>
</li>
</ul>
<blockquote>
<h4 id="❗️-useeffect--">❗️ <code>useEffect(() =&gt; {});</code></h4>
<p>useEffect(function, deps) 에서 deps를 제외하고 사용하면 렌더링이 될 때마다 실행된다. 노트북이 너무 뜨겁게 돌아가길래 뭐지...? 했더니 바로 계속해서 렌더링이 되었던 것😅 첫번째 렌더링이 될 때만 useEffect를 실행하고 싶다면 deps에 빈 배열을 추가하면 된다. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[new TIL. git flow & rebase ]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-git-flow-rebase</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-git-flow-rebase</guid>
            <pubDate>Sat, 03 Apr 2021 09:17:12 GMT</pubDate>
            <description><![CDATA[<p><strong>git</strong>은 프로젝트 파일을 변경 사항을 추적하는 시스템이며,
<strong>github</strong>은 프로젝트에 필요한 모든 파일과 코드의 히스토리를 함께 공유하는 호스팅 서비스다.</p>
<p>2주 동안 프로젝트를 진행해보니, 생각보다 많은 branch, PR, 그리고 commit message가 쌓인 것을 확인할 수 있었다. </p>
<p>그동안 우리 굉장히 열심히 했구나... 라고 느낄 수 있었지만, 한편으로는 과연 history를 제대로 파악할 수 있을까? 라는 의구심이 들기 시작했다.</p>
<p>이에 대한 해결책으로 git flow &amp; rebase를 들수 있다.</p>
<h3 id="📌-git-flow">📌 Git Flow</h3>
<blockquote>
<p><strong>The Gitflow Workflow</strong> defines a strict branching model designed around the project release. This provides a robust framework for managing larger projects. <a href="https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow#:~:text=The%20overall%20flow%20of%20Gitflow,branch%20is%20created%20from%20master&amp;text=When%20the%20release%20branch%20is,to%20both%20develop%20and%20master">[출처]</a></p>
</blockquote>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/d9deef53-6853-4217-9dad-71bc989a8bbd/git-model@2x.png" alt=""></p>
<h4 id="purposes-of-the-branches">purposes of the branches</h4>
<ul>
<li><strong>master</strong> : used for production releases</li>
<li><strong>develop</strong> : contains stable features for the next release</li>
<li><strong>feature</strong> : used for developing certain functions</li>
<li><strong>release</strong> : used for isolating and stabilizing the release</li>
<li><strong>hotfix</strong> : severe bug fixed for production</li>
</ul>
<p><br><br></p>
<h3 id="📌-rebase">📌 Rebase</h3>
<p>협업하는 개발자가 프로젝트의 history를 원활하게 파악하기 위해서는 rebase 작업이 필요하다. 다양한 branch에서 작업들이 이루어진다면 불필요한 merge commit이 발생하고, 그렇다면 github의 효율성을 낮추기 때문이다. </p>
<blockquote>
<p>Rebase는 내 commit의 base를 변경하여, commit history를 일렬로 잘 정리해줍니다. </p>
</blockquote>
<ul>
<li>해당 브랜치의 base commit을 확인하는 방법 : <code>git merge-base main branchname</code> </li>
</ul>
<h4 id="rebase-process">Rebase Process</h4>
<ol>
<li><p>새로운 작업을 마친 후 push 하기 전, main(master) branch에서 pull 받는다.
<code>git checkout main</code> <code>git pull origin main</code></p>
</li>
<li><p>작업한 branch로 이동하여 <code>git rebase -i main</code></p>
</li>
<li><p><strong>squash : use commit but meld into previous commit</strong>
가장 오래된 commit message를 pick하고 나머지는 squash. 그후 esc + :wq!</p>
</li>
<li><p>최종적으로 rebase된 commit message를 수정하는 과정. 현재까지의 작업 내용을 정리하여 작성한다. 그후 esc + :wq!</p>
<p>commit message 수정 : <code>git commit --amend</code></p>
</li>
<li><p><code>git log</code>로 확인 후 최종 push! <code>git push origin branchname -f</code></p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[☑️ javascript - 다시 한 번 복습해야 할 파트]]></title>
            <link>https://velog.io/@yoojin-kwon/javascript-%EB%8B%A4%EC%8B%9C-%ED%95%9C-%EB%B2%88-%EB%B3%B5%EC%8A%B5%ED%95%B4%EC%95%BC-%ED%95%A0-%ED%8C%8C%ED%8A%B8</link>
            <guid>https://velog.io/@yoojin-kwon/javascript-%EB%8B%A4%EC%8B%9C-%ED%95%9C-%EB%B2%88-%EB%B3%B5%EC%8A%B5%ED%95%B4%EC%95%BC-%ED%95%A0-%ED%8C%8C%ED%8A%B8</guid>
            <pubDate>Sun, 28 Mar 2021 14:25:54 GMT</pubDate>
            <description><![CDATA[<h3 id="javascript-replit-17---배열-조작하기">javascript repl.it 17 - 배열 조작하기</h3>
<img src="https://images.velog.io/images/yoojin-kwon/post/e5f703da-bbe0-4cb2-9097-071f093be672/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-22%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.47.46.png" width="700px">

<pre><code>// Answer

function divideArrayInHalf(array) {  
    let result = [];
    for(let i=4; i &gt;= 0; i--){
      if(array[i]&lt;=10){
        result.unshift(array[i]);
      }else{
        result.push(array[i]);
      }
    } return result; 
}</code></pre><h4 id="fail이였던-이유">fail이였던 이유</h4>
<ul>
<li><p>for 문의 syntax에 맞지 않아서 
<img src="https://images.velog.io/images/yoojin-kwon/post/75a58ac7-c737-41b7-8f4e-fd5d760c8615/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-19%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.09.12.png" alt=""></p>
<blockquote>
<p>; 하나까지 놓치지 말고 코드 작성하자!</p>
</blockquote>
</li>
<li><p>return을 if 문 안에 주었기 때문에 함수 실행 중단</p>
<blockquote>
<ul>
<li>return 명령문은 함수 실행을 종료하고, 주어진 값을 함수 호출 지점으로 반환한다.  </li>
</ul>
</blockquote>
<ul>
<li>함수 본문에서 return 명령문에 도달하면 함수의 실행은 그 지점에서 중단됩니다. </li>
</ul>
</li>
</ul>
<p><br><br></p>
<h3 id="javascript-replit-20---날짜와-시간">javascript repl.it 20 - 날짜와 시간</h3>
<img src="https://images.velog.io/images/yoojin-kwon/post/982c1f3f-002b-4c5f-9a1f-f3efa19c29a4/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-22%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.58.43.png" width="700px">

<pre><code>// Answer

function getWesternAge(birthday) {
  let rightNow = new Date();

  let birthYear = birthday.getFullYear();
  let thisYear = rightNow.getFullYear();
  let birthMonth = birthday.getMonth()+1;
  let thisMonth = rightNow.getMonth()+1;
  let birthDate = birthday.getDate();
  let thisDate = rightNow.getDate();

  if(birthMonth &lt; thisMonth){
   return thisYear - birthYear;
  } else if((birthMonth === thisMonth) &amp;&amp; (birthDate &lt;= thisDate) ){
   return thisYear - birthYear;
  } else{
   return thisYear - birthYear - 1; 
  }

}</code></pre><h4 id="fail이였던-이유-1">fail이였던 이유</h4>
<ul>
<li><p>일치 연산자(===) 대신 = 를 썼다.</p>
<blockquote>
<ul>
<li>a = b와 같이 등호가 하나일 때는 할당을 의미한다.</li>
</ul>
</blockquote>
<ul>
<li>일치 연산자(strict equality operator) ===를 사용하면 형 변환 없이 값을 비교할 수 있다.</li>
</ul>
</li>
<li><p>tip) 코드에 오류가 발생한다면 console.log를 통해 결과값 확인해보기</p>
</li>
</ul>
<p><br><br></p>
<h3 id="javascript-replit-21---number">javascript repl.it 21 - Number</h3>
<img src="https://images.velog.io/images/yoojin-kwon/post/c0348dc3-45fd-4f20-9562-5a733345264c/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-22%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.12.46.png" width="700px">

<pre><code>// Answer

function getRandomNumber (min, max) {

 return Math.random() * (max-min) + min;

}</code></pre><h4 id="풀이법">풀이법</h4>
<blockquote>
<p>0 &lt;= Math.random() &lt; 1 
  0 &lt; Math.random() * (max-min) &lt; (max-min) // 양변에 (max-min) 곱하기
  min &lt; Math.random() * (max-min) +min &lt; max // 양변에 min 더하기</p>
</blockquote>
<p><br><br></p>
<h3 id="javascript-replit-22---object">javascript repl.it 22 - Object</h3>
<img src="https://images.velog.io/images/yoojin-kwon/post/51bb9d10-4ab6-4932-89d3-161b0dcf6254/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-22%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.32.16.png" width="700px">

<pre><code>// Answer

function getData(salesArr,reviewArr,likeArr){

  let amount = 0;
  for(let i = 0; i &lt; salesArr.length; i++){
    amount += salesArr[i][1];
    }

  let review = 0;
  for(var i = 0; i &lt; reviewArr.length; i++){
    review += reviewArr[i][1];
    }

  let like = 0;
  for(var i = 0; i &lt; likeArr.length; i++){
    like += likeArr[i][1];
    }

  let objData = {
    sumAmount : amount,
    sumReview : review,
    sumLike : like,
  };

  return objData;
}</code></pre><h4 id="풀이법-1">풀이법</h4>
<ul>
<li>let amount = 0; 으로 설정<blockquote>
<p>변수 선언과 초기화를 동시에 할 수 있다.</p>
</blockquote>
</li>
<li>할당 연산자 활용 <blockquote>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/0f1ad59e-39b1-4ade-8e48-645a2d3f4343/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-22%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.48.37.png" width="700px"><code>amount += salesArr[i][1]; // amount = amount + salesArr[i][1]</code></p>
</blockquote>
</li>
</ul>
<p><br><br></p>
<h3 id="javascript-replit-24---class">javascript repl.it 24 - Class</h3>
<img src="https://images.velog.io/images/yoojin-kwon/post/384646d8-b721-4124-a1df-7101e1cdfe36/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-23%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.38.26.png" width="700px">

<pre><code>// Answer

class MyMath {
 constructor(a, b){ 
   this.number1 = a;
   this.number2 = b;
   }

   getNumber(){
     return [this.number1, this.number2];
   }

   add(){
     return this.number1 + this.number2;
   }

   substract(){ 
     return this.number1 - this.number2;
   }

   multiply(){
     return this.number1 * this.number2;
   }
 }</code></pre><h4 id="fail이였던-이유-2">fail이였던 이유</h4>
<ul>
<li>class syntax에 익숙해지자! 
constructor도 또 하나의 함수일 뿐이다.</li>
</ul>
<p><br><br></p>
<h3 id="javascript-replit-27---template-literals-string-method">javascript repl.it 27 - Template literals, string method</h3>
<img src="https://images.velog.io/images/yoojin-kwon/post/a8d8c6aa-e1b9-457a-8746-b3ee1544284b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-23%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.47.10.png" width="700px">

<pre><code>// Answer

const handleEdit = (nickname, interests) =&gt; {

 return {
   nickname : nickname,
   interests : interests.split(&#39;,&#39;),
   bio : `제 닉네임은 ${nickname}입니다. 취미는 ${interests.split(&#39;,&#39;)}입니다.`

 };
}</code></pre><h4 id="fail이였던-이유-3">fail이였던 이유</h4>
<ul>
<li>split<blockquote>
<p>split() 메서드는 String 객체를 지정한 구분자를 이용하여 여러 개의 문자열로 나눈다.
split syntax &gt;&gt; <code>string.split( &#39;separator&#39;, limit )</code></p>
</blockquote>
<ul>
<li>separator에는 분할의 기준을, limit로 최대 분할 개수를 정한다.(선택 사항으로, 값을 정하지 않으면 전체를 다 분할한다.)</li>
<li>interests.split(&#39;, &#39;)은 ,(쉼표)를 기준으로 분할한다.</li>
</ul>
</li>
</ul>
<p><br><br></p>
<h3 id="javascript-replit-28---array-methods">javascript repl.it 28 - Array methods</h3>
<img src="https://images.velog.io/images/yoojin-kwon/post/b505fbf2-1408-4e93-85d8-e61321b7db5d/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-23%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.20.25.png" width="700px">

<pre><code>// Answer

const moreThan100 = nums =&gt; {
  return nums.map(el =&gt; {
    if (el &gt;= 100) return true;
    if (el &lt; 100) return false;
    })
}


const formatDate = dates =&gt; {
  return dates.map(dates =&gt; {
    let dateArr = dates.split(&#39;-&#39;);

    return `${dateArr[0]}년 ${dateArr[1]}월 ${dateArr[2]}일`;
  });
}</code></pre><h4 id="fail이였던-이유-4">fail이였던 이유</h4>
<ul>
<li><p>Array.map()</p>
<blockquote>
<p>map() 메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 <strong>새로운 배열을 반환</strong>합니다.</p>
</blockquote>
<pre><code>const array1 = [1, 4, 9, 16];
    // pass a function to map
const map1 = array1.map(x =&gt; x * 2); 
console.log(map1);
   // expected output: Array [2, 8, 18, 32]</code></pre></li>
<li><p>Array.forEach()</p>
<blockquote>
<p>forEach() 메서드는 주어진 함수를 <strong>배열 요소 각각에 대해 실행</strong>합니다.</p>
</blockquote>
<pre><code>  const array1 = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;];
   array1.forEach(element =&gt; console.log(element));
      // expected output: &quot;a&quot; 
      // expected output: &quot;b&quot;
      // expected output: &quot;c&quot;</code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MarketHoly 프로젝트 리뷰 ]]></title>
            <link>https://velog.io/@yoojin-kwon/1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@yoojin-kwon/1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Sun, 28 Mar 2021 14:19:32 GMT</pubDate>
            <description><![CDATA[<p>드디어 1차 프로젝트가 마무리되었다. </p>
<p>2주동안 하루하루 빠짐없이 쌓아왔던 우리 팀만의 코드들과 협업이 빛을 발하는 순간이라 두근거리기도, 한편으로는 아쉽기도 한 그런 날이였던 것 같아 잊기 전에 기록해보고자 한다.</p>
<p><br><br></p>
<h3 id="📌-overall">📌 Overall</h3>
<p>오랜만에 다시 해보는 팀 프로젝트라 처음에는 마냥 설렜던 것 같다. </p>
<p>광고홍보학을 전공한 나는 대다수의 수업이 제안서 기획으로 이루어졌고, 그래서 팀 프로젝트는 나의 대학 생활의 대부분을 차지했었다. 졸업 후 홍보대행사의 AE로서 업무를 진행했을 때도 광고주 뿐만 아니라 미디어랩사, 디자이너 등 다양한 파트너와 협업을 이어나갔다.</p>
<p>그런 나에게 &#39;팀 프로젝트&#39;라는 자체는 익숙했지만 &#39;개발자&#39;라는 역할로 참여한 팀 프로젝트는 처음이라 이전과는 다른 결의 협업을 상상(?)했던 것 같다. </p>
<p>하지만, 2주 후 나름대로 내린 결론은 <strong>&#39;협업의 본질은 같다&#39;</strong>이다. 효율적이면서도 전달력있는 커뮤니케이션을 위해 여전히 끊임없는 고민이 필요하다. 앞으로 현업에서는 기획자와 디자이너, 그리고 대내외적인 다양한 분야의 사람들과 이야기를 나누어야 할 것이다. </p>
<p>그런 점에서 앞으로 나아갈 개발자라는 길은 대학 때부터 걸어왔던 나의 길과 어느정도 일맥상통 한 것 같다.</p>
<p><br><br></p>
<h3 id="📌-project-process--scrum">📌 Project Process : Scrum</h3>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/5725979a-b8cc-402a-b7be-e589fef1751b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.00.23.png" alt=""><img src="https://images.velog.io/images/yoojin-kwon/post/955ebd4f-3f8d-4550-8dfd-0e974b182e6c/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-18%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.02.48.png" alt=""></p>
<p>각 기능별로 역할을 분배했지만, 우리 팀원들은 서로의 문제를 함께 적극적으로 해결해나갔다. 다만 팀원 모두 공통적으로 아쉬움을 남겼던 부분이 있었다. 바로 <strong>Scrum</strong>. </p>
<p>프로젝트 전체를 놓고 보았을 때, 1주일이라는 Sprint Routine이 있었는데 아무래도 첫 프로젝트이고 전체적인 흐름에 대한 이해가 부족했기 때문에 하나의 Sprint가 너무 길어져 회고할 시간이 절대적으로 부족했다. </p>
<p>2차 프로젝트에서는 daily standup 미팅에서 부족함을 느꼈던 부분에 대한 논의가 보다 활발하게 이루어질 수 있도록 하자. </p>
<p><br><br></p>
<h3 id="📌-기억하고-싶은-코드">📌 기억하고 싶은 코드</h3>
<h4 id="1-쿼리스트링을-활용한-페이지네이션-로직-구현">1) 쿼리스트링을 활용한 페이지네이션 로직 구현</h4>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/9e8ffe19-2528-479f-a734-67ee7b869063/ezgif.com-gif-maker%20(6).gif" alt=""> 자세한 내용은 여기에서! 👉 <a href="https://velog.io/@yoojin-kwon/new-TIL.-Paginationquery-string">MD 추천 - 페이지네이션 기능 구현</a>
<br></p>
<h4 id="2-컴포넌트-재활용">2) 컴포넌트 재활용</h4>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/4d707447-9c66-42de-a9eb-db147afe0dcd/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.26.11.png" alt=""><img src="https://images.velog.io/images/yoojin-kwon/post/fe5457c5-ae12-4ed3-85e8-b6d15161dc48/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.26.38.png" alt=""></p>
<p>이번 프로젝트에서 컴포넌트 재활용을 위해 많은 고민을 했던 것 같다. 비슷한 구성 요소로 이루어져 있기는 하지만, 이미지 및 텍스트 사이즈부터 일일특가 및 countdown 마크까지 다르게 적용해주기 위해 일일특가에 사용될 컴포넌트에는 modifier를 주어 구분했다. </p>
<p>백엔드에서 &#39;이 상품 어때요?&#39; 와 &#39;일일특가&#39;의 할인율이 <code>discount_rate</code>와 <code>daily_discount_rate</code>로 다르게 들어올 수 밖에 없는 상황이였기 때문에 삼항연산자를 활용하여 분리해주었다. </p>
<p>다음 번 프로젝트에서는 보다 더 효율적인 방법으로 컴포넌트를 구조화하고 재활용하고 싶은 마음이 더 커졌달까...🤓
<img src="https://images.velog.io/images/yoojin-kwon/post/285a4e81-d91b-4596-afd6-41a07ffd46a9/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.45.02.png" alt=""></p>
<p><br><br></p>
<h3 id="📌-기억하고-싶은-코드리뷰">📌 기억하고 싶은 코드리뷰</h3>
<h4 id="1-spread-syntax스프레드-연산자를-활용하여-중복-제거">1) Spread Syntax(스프레드 연산자)를 활용하여 중복 제거</h4>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/f869571c-7d2b-464b-836e-127a38a12ba7/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%209.49.05.png" alt=""><br></p>
<h4 id="2-페이지-간-props-전달">2) 페이지 간 props 전달</h4>
<p>장바구니 기능 구현 중, 다음 주소 api를 통해 사용자가 선택한 주소가 화면에 업데이트되도록 구현하고 싶었다. 부모-자식 관계의 컴포넌트가 아니였기 때문에 단순히 state 값을 props로 넘겨줄 수는 없어 localStorage에 저장하는 방법을 생각했다.</p>
<p>하지만...
<img src="https://images.velog.io/images/yoojin-kwon/post/ac9045e3-5a11-4315-aa1d-ce197ec24a02/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.01.27.png" alt=""></p>
<p>리뷰와 같이 로컬 스토리지는 개발자 도구에서도 계속 확인할 수 있는 보안에 굉장히 취약한 부분이였던 것이다. 그래서 알아낸 다른 방법은 바로 <code>history.push()</code>
시간 관계 상 장바구니 기능을 계속해서 맡을 수 없었는데, 다음 프로젝트에서 동일한 문제를 만나면 꼭 사용해보고싶다!
<img src="https://images.velog.io/images/yoojin-kwon/post/f6e3a6ac-04d9-4002-9a82-383d19e4993b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.17.50.png" width="500px"></p>
<ul>
<li>history.push()로 props를 넘겨주는 경우</li>
<li>history.location()으로 props를 받아오는 경우</li>
</ul>
<p><a href="https://velog.io/@dhlee91/this.props.history.push%EB%A1%9C-props-%EB%84%98%EA%B2%A8%EC%A3%BC%EA%B8%B0">[참고_pdl39님 velog]</a></p>
<p><br><br></p>
<h3 id="📌-마무리">📌 마무리</h3>
<p><strong>나만의 보폭으로 이뤄낸 1차 프로젝트🏃‍♀️</strong></p>
<p>팀 내에서 나의 역할은 Main Page 기능 구현이였다. 한 페이지였지만 4가지 기능 구현을 해야 하는 상황이였고, 그래서 결국 맡았던 장바구니 기능 구현을 끝까지 다 해내지 못했다. </p>
<p>그 시점 나의 성장 속도가 못마땅했던 것 같다. 하지만 하나의 코드를 작성하더라고 내 것으로 소화하기 위해 노력했고, 이렇게 회고의 리뷰를 작성하면서 그 동안의 성장이 &#39;겨우&#39;가 아닌 &#39;이 만큼이나&#39;라고 새삼 느껴졌다. </p>
<p>성장하기 위한 과정을 함께 한 팀원들에게도 감사 인사를 전하며, 2주 동안 나 자신 수고했다!👍</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[new TIL. Pagination(Query String)]]></title>
            <link>https://velog.io/@yoojin-kwon/new-TIL.-Paginationquery-string</link>
            <guid>https://velog.io/@yoojin-kwon/new-TIL.-Paginationquery-string</guid>
            <pubDate>Sun, 28 Mar 2021 07:45:21 GMT</pubDate>
            <description><![CDATA[<p>마켓컬리 메인 페이지에서 <strong>MD 추천</strong>은 카테고리 버튼을 클릭할 때마다 해당 카테고리 내 추천 제품이 보여진다. 여기에서 고민이 시작되었는데... </p>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/01fee99f-f7b7-495e-bff6-c6c8b33c3a60/ezgif.com-gif-maker.gif" alt=""></p>
<p>우선 동일한 페이지에서 구현되어 URL 변화는 없고, 그렇기 때문에 동적 라우팅을 적용하는 것은 아니라고 판단했다. </p>
<p>여기서 두 가지 가설을 세웠는데, <em><strong>1) 카테고리 버튼을 클릭할 때마다 해당 카테고리의 index를 post하고 그에 맞는 데이터(추천 제품)을 받아와 컴포넌트에 담아준다.</strong></em> <em><strong>2) 모든 버튼에 해당하는 데이터를 받아오고 클릭된 버튼에 맞는 데이터만 필터링한다.</strong></em></p>
<p>하지만 아무리 생각해도 2번 가설은 너무 많은 데이터를 받아오기 때문에 적합하지 않을 것 같고, 개발자 도구 network에서 버튼을 클릭할 때마다 통신이 일어난다는 것을 확인할 수 있었다. </p>
<p>결국 1번 가설이 맞다는 판단이 들었다.
<img src="https://images.velog.io/images/yoojin-kwon/post/e2a55fd8-4895-45f2-828c-c6a0cd6bd738/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-24%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.34.30.png" alt=""></p>
<br>

<h2 id="📌-pagination">📌 Pagination</h2>
<p>해결책을 찾는 중... 아주 딱 맞는 타이밍에 <strong>Pagination</strong> 세션을 듣게 되었다 야호!🙌
서버에서 오는 데이터를 원하는 길이로 끊어서 전달 받을 수 있는 기능이 바로 페이지네이션이다. 웹에서 흔하게 볼 수 있는 page 1,2,3,4,,,를 구현하기 위한 기능이다.</p>
<p>그렇다면 처음 세웠던 가설과 같이 클릭한 카테고리에 대한 정보를 백엔드에 전달해야하는데 이는 <strong>쿼리 스트링(Query String)</strong>을 사용하면 된다.</p>
<blockquote>
<p>A query string is a part of a uniform resource locator (URL) that assigns values to specified parameters. A query string commonly includes fields added to a base URL by a Web browser or other client application, for example as part of an HTML form [출처_wikipedia]</p>
</blockquote>
<p>페이지네이션을 위해서는 쿼리 스트링에 limit와 offset을 포함시켜주어야 한다.</p>
<ul>
<li><strong>limit</strong> : 한 페이지에 보여줄 데이터 수</li>
<li><strong>offset</strong> : 데이터가 시작하는 위치(index)</li>
</ul>
<p>우리 팀의 경우 하나의 카테고리 당 6개의 추천제품을 보여주기로 했기 때문에 limit=6이고 각 카테고리마다 동일한 값이기 때문에 변수로 지정해주었다. <code>const LIMIT = 6;</code></p>
<br>

<h2 id="📌-나의-코드">📌 나의 코드</h2>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/99d58cf0-20b7-4445-a590-3f2da34f74a3/%E1%84%8B%E1%85%B2%E1%84%8C%E1%85%B5%E1%86%AB%E1%84%8B%E1%85%B4%20%E1%84%8F%E1%85%A9%E1%84%83%E1%85%B3.001.jpeg" alt=""><img src="https://images.velog.io/images/yoojin-kwon/post/354f38a1-d908-4af3-8fac-6ccc713cc105/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.39.31.png" width="600px"></p>
<p>사용자가 원하는 카테고리 버튼을 클릭하면 카테고리에 해당하는 ListCategory 컴포넌트에서 onClick 이벤트를 통해 handleColor 함수가 실행된다. (함수명을 handleColor로 설정한 이유는 클릭될 때마다 회색에서 보라색으로 백그라운드 컬러가 변경되어야 하기 때문!)</p>
<p>클릭을 했을 때 <em><strong>1) 버튼 색상 변경,</strong></em>  <strong><em>2)해당되는 카테고리 추천 제품 데이터 불러오기,</em></strong> 두 가지 이벤트를 실행하고 싶기 때문에 handleColor 함수 안에 handleCategory 함수(2번에 해당)를 넣어주었다.</p>
<br>

<p>먼저 1번부터 살펴보자면, 처음 웹이 로딩되었을 때 디폴트로 채소가 클릭되었으면 해서 state 값으로 <code>clickIndex=&#39;1&#39;</code>을 설정해주었다. 버튼을 클릭하면 함수가 실행되고, 클릭된 data-idx로 clickIndex가 재 설정된다. </p>
<p>그렇게 된다면 삼항연산자에서 clickIndex가 index+1 값과 동일해져 true가 되고 className이 clicked로 변경된다. scss에서 클래스 별로 다른 배경 색을 적용했기 때문에 클릭된 버튼의 색상이 바뀌게 된다.
<br></p>
<blockquote>
<p><strong>비표준 속성, dataset</strong> <a href="https://ko.javascript.info/dom-attributes-and-properties">[출처_javascript.info]</a>
<br>비표준 속성은 사용자가 직접 지정한 데이터를 HTML에서 자바스크립트로 넘기고 싶은 경우나 자바스크립트를 사용해 조작할 HTML 요소를 표시하기 위해 사용할 수 있다.
<code>data-</code> 로 시작하는 속성 전체는 개발자가 용도에 맞게 사용하도록 별도로 예약된다. <code>dataset</code> 프로퍼티를 사용하면 이 속성에 접근할 수 있다.
<img src="https://images.velog.io/images/yoojin-kwon/post/a8b99c9b-0fce-487f-8d36-6925b15c17c7/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.58.43.png" alt=""></p>
</blockquote>
<br>
2번의 경우, handleColor 함수에서 클릭된 카테고리의 data-idx를 handleCategory 함수에 인자로 넘긴다. Limit와 Offset을 지정한 후, fetch 함수를 통해 해당 url의 페이지 및 데이터를 요청한다.

<p>id가 3인 카테고리를 클릭한 경우, <code>/product/mdrecommendation?limit=6&amp;offset=18</code></p>
<br>

<h2 id="📌-구현-웹">📌 구현 웹</h2>
<p><img src="https://images.velog.io/images/yoojin-kwon/post/a85d3431-d264-4c50-af94-e3e68239157d/ezgif.com-gif-maker%20(6).gif" alt=""></p>
<p>페이지네이션이라는 개념을 접하기 전, 어떤 방식으로 데이터가 들어오고 출력될지 고민하고 그에 대한 해결책을 찾아 나갔다는 점에서 개인적으로 기억에 가장 남는 기능 구현이였다. 카테고리 별 정보 전달이라는 웹의 가장 기본적인 기능인 만큼 앞으로도 유용하게 활용할 것 같다!🤓</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 재귀함수 - factorial]]></title>
            <link>https://velog.io/@yoojin-kwon/Algorithm-%EC%9E%AC%EA%B7%80%ED%95%A8%EC%88%98-factorial</link>
            <guid>https://velog.io/@yoojin-kwon/Algorithm-%EC%9E%AC%EA%B7%80%ED%95%A8%EC%88%98-factorial</guid>
            <pubDate>Fri, 19 Mar 2021 04:25:33 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<img src="https://images.velog.io/images/yoojin-kwon/post/35af12d9-2f13-4e92-9b56-3aedc4fdfdce/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-19%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.02.59.png" width="800px">

<h2 id="해결">해결</h2>
<pre><code class="language-javascript">const factorial = n =&gt; {
  if(n&lt;=1){
    return 1;
  }else{
    return n * factorial(n-1);
  }
}</code></pre>
<h2 id="til">TIL</h2>
<h3 id="재귀recursion--recursion-is-simply-when-a-function-calls-itself"><strong><em><code>재귀(Recursion)</code></em></strong> = Recursion is simply when a function calls itself.</h3>
<br>

<p>the three key features of recursion</p>
<h4 id="1-종료-조건termination-condition">1) 종료 조건(Termination Condition)</h4>
<ul>
<li><code>if(something bad happened){ STOP };</code></li>
<li>재귀의 안전장치로서 원하지 않는 값이 들어왔을 때 재귀가 계속해서 동작하는 것을 방지(긴급 브레이크라고 생각하자!)</li>
<li><code>// if(n&lt;0) return;</code><h4 id="2-기반-조건base-case">2) 기반 조건(Base Case)</h4>
</li>
<li><code>if(this happens) { Yay! We&#39;re done };</code></li>
<li>재귀를 종료한다는 점에서는 종료 조건과 유사하지만, 기반 조건은 재귀 함수의 목적지다.</li>
<li>만약 기반 조건이 없다면 재귀는 무한 로딩의 굴레로...😫</li>
<li><code>//   if(n&lt;=1) return 1;</code><h4 id="3-재귀recursion">3) 재귀(Recursion)</h4>
</li>
<li>재귀가 실질적으로 일어나는 부분. Our function calling itself.</li>
<li><code>// else{return n * factorial(n-1);}</code></li>
</ul>
<br>

<p>삼항 연산자를 사용해 보다 간단하게 로직을 구현할 수도 있다.</p>
<blockquote>
<pre><code class="language-javascript">const factorial = (n) =&gt; {
 return (n != 1) ? n * factorial(n - 1) : 1;
}</code></pre>
</blockquote>
<pre><code>
-------

[[참고_jakeseo-javascript.js님 velog]](https://velog.io/@jakeseo_me/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%9D%BC%EB%A9%B4-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%A0-33%EA%B0%80%EC%A7%80-%EA%B0%9C%EB%85%90-23-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9E%AC%EA%B7%80Recursion-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0)
[[참고_codeburst]](https://codeburst.io/learn-and-understand-recursion-in-javascript-b588218e87ea)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[code convention] React import]]></title>
            <link>https://velog.io/@yoojin-kwon/code-convention-React-import</link>
            <guid>https://velog.io/@yoojin-kwon/code-convention-React-import</guid>
            <pubDate>Thu, 18 Mar 2021 12:05:03 GMT</pubDate>
            <description><![CDATA[<p>하나의 컴포넌트에서도 여러 import가 있기 때문에, 순서를 잘 지킨다면 가독성이 좋아질 수 있다👩‍💻</p>
<h2 id="css-property-순서">CSS property 순서</h2>
<h4 id="1-react">1. React</h4>
<h4 id="2-librarypackage">2. Library(Package)</h4>
<h4 id="3-component">3. Component</h4>
<h4 id="4-변수--이미지">4. 변수 / 이미지</h4>
<h4 id="5-css-파일scss-파일">5. css 파일(scss 파일)</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 배열 내 특정 수 마지막으로 이동]]></title>
            <link>https://velog.io/@yoojin-kwon/Algorithm-%EB%B0%B0%EC%97%B4-%EB%82%B4-%ED%8A%B9%EC%A0%95-%EC%88%98-%EB%A7%88%EC%A7%80%EB%A7%89%EC%9C%BC%EB%A1%9C-%EC%9D%B4%EB%8F%99</link>
            <guid>https://velog.io/@yoojin-kwon/Algorithm-%EB%B0%B0%EC%97%B4-%EB%82%B4-%ED%8A%B9%EC%A0%95-%EC%88%98-%EB%A7%88%EC%A7%80%EB%A7%89%EC%9C%BC%EB%A1%9C-%EC%9D%B4%EB%8F%99</guid>
            <pubDate>Thu, 18 Mar 2021 07:59:22 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<img src="https://images.velog.io/images/yoojin-kwon/post/63a9a038-84aa-4802-845c-91573bcecb79/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-03-18%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.40.23.png" width="700px">

<h2 id="해결">해결</h2>
<pre><code class="language-javascript">const moveZeroes = nums =&gt; {

  let countzero = 0;

  for(let i of nums){
   if(i===0){
    countzero++
   }
  }

  const filterzero = nums.filter((el) =&gt; (el !== 0));

  for(i=0; i&lt;countzero; i++){
    filterzero.push(0)
  }

  return filterzero;
}</code></pre>
<h2 id="til">TIL</h2>
<p><strong>*<code>for..of</code> vs. <code>for..in</code> *</strong></p>
<ul>
<li>현재 요소의 &quot;값&quot;을 얻고 싶다면 <code>for..of</code>
현재 요소의 &quot;인덱스&quot;를 얻고 싶다면 <code>for..in</code></li>
</ul>
<blockquote>
<pre><code class="language-javascript">let fruits = [&quot;사과&quot;, &quot;오렌지&quot;, &quot;자두&quot;];
for (let value of fruits) {
  alert( value ); // 사과, 오렌지, 자두
}</code></pre>
</blockquote>
<pre><code>```javascript
let arr = [&quot;사과&quot;, &quot;오렌지&quot;, &quot;배&quot;];
for (let key in arr) {
  alert( arr[key] ); // 사과, 오렌지, 배
}</code></pre><p><strong><em><code>filter</code> 메소드</em></strong></p>
<blockquote>
<pre><code class="language-javascript">let users = [
  {id: 1, name: &quot;John&quot;},
  {id: 2, name: &quot;Pete&quot;},
  {id: 3, name: &quot;Mary&quot;}
];
// 앞쪽 사용자 두 명을 반환합니다.
let someUsers = users.filter(item =&gt; item.id &lt; 3);
alert(someUsers.length); // 2</code></pre>
</blockquote>
<pre><code>
***`let` vs. `const`***
```javascript
let countzero = 0;

  for(let i of nums){
   if(i===0){
    countzero++
   }
  }
```
처음에는 countzero를 `const`로 선언해주었다. 근데 for 문 안에서 countzero는 변화하는 숫자이기 때문에 `let`으로 바꿔야 맞다.

-------

[[참고_모던 자바스크립트 튜토리얼]](https://ko.javascript.info/array-methods)
</code></pre>]]></description>
        </item>
    </channel>
</rss>