<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>taekjun_s.log</title>
        <link>https://velog.io/</link>
        <description>매일 하루에 딱 한 걸음만</description>
        <lastBuildDate>Mon, 13 Sep 2021 07:23:27 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>taekjun_s.log</title>
            <url>https://images.velog.io/images/taekjun_s/profile/fd12efec-8702-4a9e-9f42-a8376906af37/374443FA-B6AC-4617-AC7C-2E880E00BF79_1_201_a.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. taekjun_s.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/taekjun_s" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Github에 올라간 commit을 깔끔하게 삭제하고 싶다면?]]></title>
            <link>https://velog.io/@taekjun_s/Github%EC%97%90-%EC%98%AC%EB%9D%BC%EA%B0%84-commit%EC%9D%84-%EA%B9%94%EB%81%94%ED%95%98%EA%B2%8C-%EC%82%AD%EC%A0%9C%ED%95%98%EA%B3%A0-%EC%8B%B6%EB%8B%A4%EB%A9%B4</link>
            <guid>https://velog.io/@taekjun_s/Github%EC%97%90-%EC%98%AC%EB%9D%BC%EA%B0%84-commit%EC%9D%84-%EA%B9%94%EB%81%94%ED%95%98%EA%B2%8C-%EC%82%AD%EC%A0%9C%ED%95%98%EA%B3%A0-%EC%8B%B6%EB%8B%A4%EB%A9%B4</guid>
            <pubDate>Mon, 13 Sep 2021 07:23:27 GMT</pubDate>
            <description><![CDATA[<h2 id="1-git-log를-직관적으로-확인하는-방법">1. Git log를 직관적으로 확인하는 방법</h2>
<p>:: git log --branches --graph --decorate --oneline</p>
<ul>
<li>빨간색 글자 (ex. origin/master)
:: remote영역
:: 내가 remote에 push한 지점</li>
<li>초록색 글자 (ex. master)
:: local영역
:: 해당 branch의 최신 commit</li>
<li>HEAD
:: 현재 작업 중인 branch
:: ex) develop branch에서 log를 확인했을 때
<img src="https://images.velog.io/images/taekjun_s/post/8a5bb0f0-e7ad-4dd3-81d5-901bc8ef40db/image.png" alt="">
:: ex) pages/boardlist branch에서 log를 확인했을 때
<img src="https://images.velog.io/images/taekjun_s/post/f381e505-7acb-4ff4-95fb-90a92b91c182/image.png" alt=""></li>
</ul>
<h2 id="2-commit을-지우고-싶다면">2. commit을 지우고 싶다면?</h2>
<p><img src="https://images.velog.io/images/taekjun_s/post/f3e1cd1d-ebf3-4012-830b-b7c6bdb934be/image.png" alt=""></p>
<p>예를 들어, develop branch에서 AWS라이브러리 추가 commit을 지운다고 가정해보자. 우선 <code>git reset --hard ac6f43e</code>을 입력하면 &#39;AWS라이브러리 추가&#39;의 직전 commit인 &#39;초기세팅 수정&#39; commit으로 이동한다. 여기서부터 commit을 새로 쌓아올리면 &#39;AWS라이브러리 추가&#39; commit은 삭제된다. 
** Github에 push한 commit을 삭제하고 싶다면, 위와 동일한 과정을 거친 후에 새로운 commit을 입력하고 push하자.**</p>
<ul>
<li><p>주의사항
:: <code>git reset --hard</code>만 입력할 경우에는 현재 branch에서 작업한 내용 중 commit하지 않은 내용만 지워진다. 
:: 이 방법으로 지우면 원격 저장소에 흔적도 없이 commit을 삭제할 수 있다. 하지만 내 commit을 pull 한 팀원이 있다면, 다음에 그 팀원이 push할 때 내가 지운 commit이 다시 추가될 수 있다! <strong>즉, 1. 나 혼자만 사용하는 브랜치</strong>에 커밋을 push하였고, 이를 되돌리고 싶은 경우 2. <strong>팀원들과 직접 커뮤니케이션</strong>해서 내가 <strong>되돌릴 커밋을 pull한 팀원이 없다고 확인된 경우</strong> 사용하자!
출처: <a href="https://enant.tistory.com/45">https://enant.tistory.com/45</a> [ENAN]</p>
</li>
<li><p>reset 외에 revert 명령어를 사용할 수도 있다. 단, history에 남기 때문에 되돌릴 수도 있으므로 공개되면 안되는 파일이 업로드된 경우에는 reset을 사용해야 한다.</p>
</li>
</ul>
<h2 id="3-그-외">3. 그 외</h2>
<p><a href="https://enant.tistory.com/45">Git의 개념과 명령어가 잘 정리된 블로그</a>가 있어 명령어가 헷갈릴 때마다 챙겨보려고 기록한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[트러블 슈팅_3]]></title>
            <link>https://velog.io/@taekjun_s/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%853</link>
            <guid>https://velog.io/@taekjun_s/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%853</guid>
            <pubDate>Sun, 12 Sep 2021 06:42:45 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p>각자의 작업물을 develop 브랜치에 머지하는 과정에서 log가 뒤엉키고 conflict를 해결하더라도 동일한 conflict가 지속적으로 발생했다.</p>
<h1 id="원인">원인</h1>
<p>develop 브랜치에서 각각의 branch를 생성하지 않고 master에서 각각의 branch를 생성했다.</p>
<p><img src="https://images.velog.io/images/taekjun_s/post/a8aafd64-d17c-4d89-9d7d-ed96fec93573/image.png" alt=""></p>
<h1 id="해결-방법">해결 방법</h1>
<ol>
<li><p>repo 이동
1) github의 기존 repository를 삭제한다.
2) local에서 정상적인 방법으로 새로운 branch를 생성한다. (ex. master → develop → branch)
3) 기존 branch의 작업물을 새로운 branch로 옮긴다.
4) 기존 branch는 삭제한다.
5) github에 새로운 repository를 생성한다.
6) local과 새로운 repository를 연결한다.
7) push한다.</p>
</li>
<li><p>git cherry-pick 명령어 사용하여 브랜치에서 브랜치로 커밋 이동하기</p>
</li>
</ol>
<h1 id="결과">결과</h1>
<p>두 가지의 이유로 에러가 발생했다.</p>
<p>1)  react 스크립트의 버전 오류로 인해 발생한 에러</p>
<ul>
<li>에러 내용
:: Could not find a required file. Name: index.js</li>
<li>해결방법
:: npm i react-scripts --save</li>
</ul>
<p>2) 각자가 추가로 설치한 라이브러리로 인해 발생한 에러</p>
<ul>
<li>npm i react-scripts --save
:: react-script 업데이트</li>
<li>npm i react-kakao-login
:: 카카오 로그인 라이브러리</li>
<li>npm i axios
:: axios 라이브러리</li>
<li>npm i --save-dev @types/react-slick
:: slick 라이브러리 타입스크립트 버전</li>
<li>npm install react-slick --save
:: slick 라이브러리 리액트 버전</li>
<li>npm install slick-carousel
:: slick 라이브러리 css</li>
</ul>
<p>위의 과정을 거친 후에 정상적으로 작동하는 모습을 확인할 수 있었다.</p>
<p><img src="https://images.velog.io/images/taekjun_s/post/6feeba9a-af4d-476c-986f-e2cd58bb22f5/image.png" alt=""></p>
<p>끝❗️</p>
<h2 id="추가로-알게-된-내용">추가로 알게 된 내용</h2>
<h3 id="github에서-merge할-때도-커밋처럼-github에-merge한-내용을-정리할-수-있다">github에서 merge할 때도 커밋처럼 github에 merge한 내용을 정리할 수 있다.</h3>
<p><img src="https://images.velog.io/images/taekjun_s/post/b5c60576-6465-4184-9d70-43da08d14393/image.png" alt=""></p>
<p>아래의 내용은 <a href="https://meetup.toast.com/posts/122">해당 블로그</a>를 참조하였습니다.</p>
<p>0) 기본 구조
<img src="https://images.velog.io/images/taekjun_s/post/ae6e2398-1018-4196-82d8-5929b86432d9/image.png" alt=""></p>
<ul>
<li>master (A)에서 branch를 하나 생성</li>
<li>branch에서 commit이 발생 → (b) → (c)</li>
<li>master (A)에서 commit 발생 → (A&#39;)</li>
<li>모든 작업은 branch에서 이루어진다고 가정<h4 id="-예시를-위한-것일뿐-master에서는-작업하면-안됩니다">** 예시를 위한 것일뿐, master에서는 작업하면 안됩니다.</h4>
</li>
</ul>
<h3 id="1-merge">1) merge</h3>
<p><img src="https://images.velog.io/images/taekjun_s/post/2d3ee395-a471-46d0-9e1e-7faf2e554f4d/image.png" alt=""></p>
<ul>
<li>commit (d)의 베이스는 master (A&#39;)와 commit (c)</li>
</ul>
<h4 id="요약-베이스가-여러-갈래로-나뉘기-때문에-커밋과-log가--복잡하고-알아보기-어렵다">요약: 베이스가 여러 갈래로 나뉘기 때문에 커밋과 log가  복잡하고 알아보기 어렵다.</h4>
<h3 id="2-squash">2) squash</h3>
<p><img src="https://images.velog.io/images/taekjun_s/post/bc89b329-0e3c-4700-b992-a0edc1c2b7da/image.png" alt=""></p>
<ul>
<li>commit (a), (b), (c)를 합친 하나의 commit (a,b,c)를 생성</li>
<li>commit (a,b,c)의 베이스는 master (A)</li>
</ul>
<h3 id="3-rebase">3) rebase</h3>
<p><img src="https://images.velog.io/images/taekjun_s/post/ebd18157-4e31-4f89-a15a-5d004bbf9f6f/image.png" alt=""></p>
<ul>
<li>commit (a)의 베이스는 master (A&#39;)</li>
</ul>
<h4 id="요약-베이스-자체를-옮겨버리기때문에-log가-깔끔해져서-알아보기-쉽다">요약: 베이스 자체를 옮겨버리기때문에 log가 깔끔해져서 알아보기 쉽다.</h4>
<h3 id="4-rebase--squash">4) rebase &amp; squash</h3>
<p><img src="https://images.velog.io/images/taekjun_s/post/61aa761f-f984-43f2-84bc-a6110ee2ce43/image.png" alt=""></p>
<h3 id="오늘의-결론">오늘의 결론</h3>
<ol>
<li>merge보다는 <strong>squash와 rebase를 사용</strong>하자.</li>
<li>rebase와 squash를 같이 하면 필요한 커밋만 남으니 <strong>커밋을 깔끔하게 관리</strong>할 수 있다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[트러블 슈팅_2]]></title>
            <link>https://velog.io/@taekjun_s/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%852</link>
            <guid>https://velog.io/@taekjun_s/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%852</guid>
            <pubDate>Fri, 10 Sep 2021 07:11:34 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p>페이지가 내려간 상태에서 페이지를 올렸다가 다시 내리면 데이터를 처음부터 받아오는 문제가 발생했다. </p>
<p>페이지별로 데이터를 받아오기 위해 id를 state에 넣어두고 데이터를 불러올 때마다 1씩 id값을 더하도록 코드를 짰다.</p>
<blockquote>
</blockquote>
<pre><code>const getItems = async (pageLoadId: number): Promise&lt;void&gt; =&gt; {
  const res = await fetch(`/data/mock${pageLoadId}.json`);
  const json = await res.json();
&gt;    
  const result = json;
&gt;    
  setDataList(prevState =&gt; {
    return [...prevState, ...result];
  });
&gt;    
  setPageLoadId(prevState =&gt; {
    return prevState + 1;
  });
};
&gt;
useEffect(() =&gt; {
  const handleIntersection = (entires: any) =&gt; {
    entires.forEach((entry: any) =&gt; {
      if (!entry.isIntersecting) {
        return;
      }
&gt;
      getItems(pageLoadId);
&gt;            
    });
};
&gt;
  const io = new IntersectionObserver(handleIntersection);
&gt;
  if (target.current) {
    io.observe(target.current);
  }
&gt;
}, [dataList]);</code></pre><p>그런데 id값을 확인해보니 내려갈 때는 정상적으로 1이 더해지는데, 올라올 때는 -1이 더해지는 현상이 나타났다.
<img src="https://images.velog.io/images/taekjun_s/post/a5ceb5a3-188d-45e5-b697-3972212ea568/image.png" alt=""></p>
<h1 id="원인">원인</h1>
<p>observer의 관찰을 disconnect하는 코드가 빠져있어서, 관찰 대상으로 등록된 모든 DOM이 보일 때마다 콜백함수가 실행되었다.</p>
<h1 id="해결-방법">해결 방법</h1>
<p>useEffect의 return값에 observer의 관찰을 disconnect하는 메소드가 실행되게끔 arrow function을 추가했다. </p>
<blockquote>
</blockquote>
<pre><code>const getItems = async (pageLoadId: number): Promise&lt;void&gt; =&gt; {
  const res = await fetch(`/data/mock${pageLoadId}.json`);
  const json = await res.json();
&gt;    
  const result = json;
&gt;    
  setDataList(prevState =&gt; {
    return [...prevState, ...result];
  });
&gt;    
  setPageLoadId(prevState =&gt; {
    return prevState + 1;
  });
};
&gt;
useEffect(() =&gt; {
  const handleIntersection = (entires: any) =&gt; {
    entires.forEach((entry: any) =&gt; {
      if (!entry.isIntersecting) {
        return;
      }
&gt;
      getItems(pageLoadId);
&gt;            
    });
};
&gt;
  const io = new IntersectionObserver(handleIntersection);
&gt;
  if (target.current) {
    io.observe(target.current);
  }
&gt;
  return () =&gt; io.disconnect();
}, [dataList]);</code></pre><h1 id="결과">결과</h1>
<p><img src="https://images.velog.io/images/taekjun_s/post/a986f181-4ae4-492d-b4aa-ad63df875f6d/image.png" alt=""></p>
<p>깔끔하게 해결❗️</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[트러블 슈팅_1]]></title>
            <link>https://velog.io/@taekjun_s/%ED%81%B4%EB%A1%9C%EC%A0%80%EC%99%80-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4</link>
            <guid>https://velog.io/@taekjun_s/%ED%81%B4%EB%A1%9C%EC%A0%80%EC%99%80-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4</guid>
            <pubDate>Thu, 09 Sep 2021 08:31:45 GMT</pubDate>
            <description><![CDATA[<h1 id="부제-클로저와-무한-스크롤">부제: 클로저와 무한 스크롤</h1>
<p><img src="https://images.velog.io/images/taekjun_s/post/a1aa007c-86ed-489f-b03c-e383c9e97df7/image.png" alt=""></p>
<h2 id="문제">문제</h2>
<p>observer의 관찰대상이 드러날 때 loadItems 함수가 반복적으로 호출되는 것까지는 확인했지만, datas에 데이터가 쌓이지 않고 초기값 아래에 새로운 값으로 갱신되기만 하는 문제가 있었다.</p>
<h2 id="원인">원인</h2>
<p>useEffect가 한 번만 호출되며, loadItems 함수가 외부 변수를 기억하고 있는 것이 원인이었다. </p>
<p>loadItems 함수는 useEffect가 호출될 때마다 새로 그려지는데, useEffect가 한 번만 호출되며 loadItems 함수는 새로 그려지지 않는다. 그렇기때문에 loadItems 함수는 <strong>처음에 그려질 당시의 외부 변수값을 기억해두고 호출될 때마다 꺼내 사용한다</strong>.</p>
<h2 id="해결-방법">해결 방법</h2>
<ol>
<li>useEffect가 원할 때마다 호출되도록 dependency를 바꾼다.</li>
<li>loadItems 함수에 외부 변수를 사용하지 않는다.</li>
</ol>
<h2 id="결과">결과</h2>
<ol>
<li><p>datas가 업데이트될 때마다 useEffect가 호출되도록 dependency를 변경.</p>
</li>
<li><p>외부 변수에 영향을 받지 않도록 매개 변수 활용.</p>
</li>
</ol>
<p><img src="https://images.velog.io/images/taekjun_s/post/4cbdbf97-1537-4e90-beea-8203cf3a20e6/image.png" alt=""></p>
<h2 id="설명">설명</h2>
<p>직관적인 이해를 돕기 위해 연욱님께서 <a href="https://codesandbox.io/s/why-use-prevstate-in-setstate-g38yt?file=/example.js">코드샌드박스</a>에 작성하신 코드를 몇 줄 빌려왔다. 사이트에 방문해서 직접 버튼을 클릭해보면 이해에 큰 도움이 될 듯하다. </p>
<blockquote>
</blockquote>
<pre><code>function Home() {
  const [count, setCount] = useState(0);
&gt;
  const asyncUpdate = () =&gt; {
    setTimeout(() =&gt; {
      // setCount(count + 1); // 이상한데?
      // setCount((prev) =&gt; prev + 1); // 원하는 대로 나오는걸?
    }, 2000);
  };
&gt;
  const immediateUpdate = () =&gt; {
    setCount(count + 1);
  };
&gt;
  return (
    &lt;div&gt;
      &lt;h2&gt;count:{count}&lt;/h2&gt;
      &lt;button onClick={asyncUpdate}&gt;asyncUpdate&lt;/button&gt;
      &lt;button onClick={immediateUpdate}&gt;immediateUpdate&lt;/button&gt;
    &lt;/div&gt;
  );</code></pre><p>여기 2초에 1번, 자동으로 1을 더하게 만드는 버튼과 누르는 즉시 1을 더하는 버튼이 있다. 그리고 setTimeout함수 안에 외부 변수를 사용할 때와 사용하지 않을 때의 차이를 나타내는 각각의 코드가 있다.</p>
<ol>
<li><p><code>setCount(count + 1)</code> 
:: asyncUpdate버튼을 누른 후 immediateUpdate버튼을 여러번 누르다보면 숫자가 잘 올라가다가 갑자기 뚝 떨어지는 모습을 볼 수 있다. </p>
</li>
<li><p><code>setCount((prev) =&gt; prev + 1)</code>
:: 위의 코드와는 달리 숫자가 누르는 대로 자연스럽게 올라가는 모습을 볼 수 있다.</p>
</li>
</ol>
<p>함수가 호출될 때마다 외부 변수에서 업데이트된 값이 아닌 초기값만 가져오는 문제가 있음을 알 수 있다. 외부 변수를 기억하는 것은 클로저 함수의 특징이다.</p>
<h2 id="클로저">클로저</h2>
<p><strong>외부 변수를 기억하고 이 외부 변수에 접근할 수 있는 함수를 말한다.</strong>
출처: <a href="https://ko.javascript.info/closure">코어 자바스크립트</a></p>
<p>클로저를 이해하기 위해서는 스코프 체인과 렉시컬 스코프, 그리고 실행 컨텍스트와 렉시컬 환경에 대한 사전 지식이 필요하다.</p>
<h4 id="1-스코프-체인부터-시작해보자">1. 스코프 체인부터 시작해보자.</h4>
<ul>
<li>사전 지식
:: 스코프는 함수 단위로 생성된다.
:: <strong>밖에 있는 변수를 내부에서 사용하는 것은 가능하다.</strong> 
(내 집 안에서는 밖에 있는 물건을 가져다가 쓸 수 있는데, 밖에서 다른 집 안에 있는 물건을 가져올 수는 없는 것처럼....?)</li>
</ul>
<blockquote>
</blockquote>
<pre><code>let d = 4;
&gt;
function  outer() {
  let c = 3;
  let b = 2;
&gt;  
  function inner() {
    let b = 1;
    let a = 0;
    &gt;
    console.log(d);
  }
&gt;
  inner();
}
&gt;
outer();</code></pre><ul>
<li>실행되는 과정</li>
</ul>
<pre><code>1) outer함수를 호출하면 inner함수가 자동으로 호출된다. 

2) inner함수에서 console.log(d)가 실행된다.

3) 이 때 변수 d를 찾기 시작하는데, 스코프를 기준으로 탐색을 한다.

4) console.log(d)가 호출된 inner함수의 스코프에서 제일 먼저 변수 d를 찾는다.

5) 없다면 outer함수의 스코프에서 변수 d를 찾는다.

6) 없다면 전역 스코프에서 변수 d를 찾는다.

7) 있다면 변수 d의 값을 반환하고, 없다면 에러를 띄운다.</code></pre><ul>
<li>정리
:: 변수(d)를 찾기 위해 연결된 스코프(inner → outer → 전역)를 타고 올라가야한다는 것을 알 수 있다. 이처럼 <code>변수를 찾을 때는 연결된 스코프를 타고 올라가며 찾으라는 규칙</code>이  바로 스코프 체인이다.</li>
</ul>
<h4 id="2-렉시컬-스코프">2. 렉시컬 스코프</h4>
<ul>
<li>사전 지식
:: 스코프는 함수 단위로 생성된다.
:: 렉시컬 스코프는 상위 스코프를 결정하는 방식이다.
:: 렉시컬 스코프는 호출되는 위치가 아니라 <code>선언되는 위치에 따라 결정</code>된다.</li>
</ul>
<p>출처: <a href="https://poiemaweb.com/js-scope">모던 자바스크립트 Deep Dive</a></p>
<blockquote>
</blockquote>
<pre><code>var x = 1;
&gt;
function foo() {
  var x = 10;
  bar();
}
&gt;
function bar() {
  console.log(x);
}
&gt;
foo(); // 10
bar(); // 1</code></pre><ul>
<li>실행되는 과정</li>
</ul>
<pre><code>1) bar는 전역에서 선언되었지만, foo함수 안에서 호출되었다.

2) 이 때 렉시컬 스코프 방식을 따를 경우 bar가 선언된 전역 스코프가 bar의 상위 스코프가 된다.

3) bar함수가 호출되었을 때 bar함수 내부 스코프에 변수 x가 있는지 확인한다.

4) 없다면 스코프 체인 규칙에 따라 상위 스코프인 전역 스코프에 변수 x가 있는지 확인한다.</code></pre><ul>
<li>정리
:: 렉시컬 스코프는 상위 스코프를 지정하는 방식 중 하나이고, 대부분의 프로그래밍 언어는 렉시컬 스코프 방식을 따르고 있다. 헷갈리면 <code>렉시컬 스코프 방식 = 선언된 위치</code>라고 기억하자.</li>
</ul>
<h4 id="실행-컨텍스트와-렉시컬-환경은-설명할-만큼-충분히-내용을-이해한-후에-추가할-예정입니다">실행 컨텍스트와 렉시컬 환경은 설명할 만큼 충분히 내용을 이해한 후에 추가할 예정입니다.</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘_2016년]]></title>
            <link>https://velog.io/@taekjun_s/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%982016%EB%85%84</link>
            <guid>https://velog.io/@taekjun_s/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%982016%EB%85%84</guid>
            <pubDate>Wed, 08 Sep 2021 04:38:33 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘의-문제">오늘의 문제</h1>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/12901">2016년</a></p>
<h1 id="풀이">풀이</h1>
<blockquote>
</blockquote>
<pre><code>function solution(a, b) {
  let date = new Date(`${a} ${b}, 2016`).getDay();
&gt;  
  switch (date) {
    case 0 : 
      return &#39;SUN&#39;;
      break;
    case 1 : 
      return &#39;MON&#39;;
      break;      
    case 2 : 
      return &#39;TUE&#39;;
      break;
    case 3 : 
      return &#39;WED&#39;;
      break;
    case 4 : 
      return &#39;THU&#39;;
      break;
    case 5 : 
      return &#39;FRI&#39;;
      break;
    case 6 : 
      return &#39;SAT&#39;;
      break;
  }
}</code></pre><h1 id="과정">과정</h1>
<p><code>let date = new Date(`${a} ${b}, 2016`);</code> 
VSC에서 console.log로 찍어봤을 때와 runJS에서 console.log로 찍었을 때 나오는 생김새가 다르길래 호기심이 생겨서 겸사겸사 반환값의 타입을 확인해봤다. </p>
<ul>
<li><p>VSC
<img src="https://images.velog.io/images/taekjun_s/post/229bf5eb-4ec0-4f23-ad78-9d018c9663a5/image.png" alt=""></p>
</li>
<li><p>runJS
<img src="https://images.velog.io/images/taekjun_s/post/f54135fc-3a87-42d4-b2a3-f68589887425/image.png" alt=""></p>
</li>
</ul>
<p>당연히 문자열일거라고 생각했는데, 찾아보니 참조형 데이터타입 중 하나인 Date 객체 타입이었다. new operator는 그동안 종종 사용해왔기에 분명 객체 타입의 인스턴스를 생성한다는 것을 알고 있었다. 섣불리 문자열이라고 판단한 이유에 대해 고민해보니 Date 메소드와 헷갈렸다는 결론이 나왔다. 그래서 리팩토링을 할 때는 Date 메소드를 사용해봤더니 훨씬 깔끔하게 코드를 작성할 수 있었다.</p>
<blockquote>
</blockquote>
<pre><code>  let date = Date();
  date.slice(0, 3).toUpperCase();</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트 초기 환경 세팅_front]]></title>
            <link>https://velog.io/@taekjun_s/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B4%88%EA%B8%B0-%ED%99%98%EA%B2%BD-%EC%84%B8%ED%8C%85front</link>
            <guid>https://velog.io/@taekjun_s/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B4%88%EA%B8%B0-%ED%99%98%EA%B2%BD-%EC%84%B8%ED%8C%85front</guid>
            <pubDate>Tue, 07 Sep 2021 06:00:09 GMT</pubDate>
            <description><![CDATA[<p>프로젝트의 구체적인 방향을 설정한다고 월요일의 2/3를 사용했고, 남은 1/3은 초기환경을 세팅하는 데에 쓴 것 같다. 2달 조금 넘는 기간동안 초기 세팅만 3번을 했지만 아직 익숙하지 않은 내 모습을 보며, 초기 환경 세팅의 전반적인 흐름을 정리할 필요성을 느껴 기록으로 남긴다.</p>
<h2 id="사용-기술-스택">사용 기술 스택</h2>
<ul>
<li>React with TypeScript, React-Router, SCSS</li>
<li>Redux</li>
<li>Create React App</li>
<li>ESLint, Prettier</li>
</ul>
<h2 id="세팅-과정">세팅 과정</h2>
<p><strong>1. <code>npx create-react-app (폴더명) --template redux-typescript</code></strong>
:: Redux를 사용한다면 위의 코드 한 줄로 React, Redux, TypeScript, Redux toolkit을 모두 설치할 수 있다.</p>
<p><strong>2. <code>npm install react-router-dom --save</code></strong>
:: React-Router 설치</p>
<p><strong>3. <code>npm install -D prettier eslint-config-prettier eslint-plugin-prettier</code></strong>
:: ESLint의 포맷팅과 Prettier 포맷팅의 충돌 방지</p>
<ul>
<li>타입스크립트를 사용한다면 아래의 코드도 설치
<code>npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-react</code></li>
</ul>
<p>*<em>4. <code>.vscode/settings.json</code> 파일 생성 후 아래 내용 복사 붙여넣기 *</em></p>
<blockquote>
</blockquote>
<pre><code>{
  &quot;editor.defaultFormatter&quot;: &quot;esbenp.prettier-vscode&quot;,
    &quot;editor.tabSize&quot;: 2,
  &quot;editor.formatOnSave&quot;: true,
    &quot;editor.codeActionsOnSave&quot;: {
    &quot;source.fixAll.eslint&quot;: true,
  },
  &quot;javascript.format.enable&quot;: false,
  &quot;eslint.alwaysShowStatus&quot;: true,
  &quot;files.autoSave&quot;: &quot;onFocusChange&quot;
}</code></pre><p><strong>5. <code>.eslintrc</code> 파일 생성 후 아래 내용 복사 붙여넣기</strong></p>
<blockquote>
</blockquote>
<pre><code>{
  &quot;extends&quot;: [&quot;react-app&quot;, &quot;plugin:prettier/recommended&quot;]
}</code></pre><p><strong>6. 코드 컨벤션 협의</strong></p>
<ul>
<li>특이사항이 없다면 <code>.prettierrc</code> 파일 생성 후 아래 내용 복사 붙여넣기**</li>
</ul>
<blockquote>
</blockquote>
<pre><code>{
  &quot;printWidth&quot;: 100,
  &quot;tabWidth&quot;: 2,
  &quot;singleQuote&quot;: true,
  &quot;trailingComma&quot;: &quot;all&quot;,
  &quot;bracketSpacing&quot;: true,
  &quot;semi&quot;: true,
  &quot;useTabs&quot;: true,
  &quot;arrowParens&quot;: &quot;avoid&quot;,
  &quot;endOfLine&quot;: &quot;lf&quot;
}</code></pre><ul>
<li>3 ~ 6번에 대한 설명은 <a href="https://velog.io/@taekjun_s/eslint%EC%99%80-prettier-%EC%B4%88%EA%B8%B0-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95">ESLint와 Prettier 초기 설정 방법</a>을 참고.</li>
</ul>
<p><strong>7. <code>npm install node-sass@4.14.1</code></strong>
:: Sass 설치</p>
<p><strong>8. css 초기 설정</strong>
:: common.scss 및 reset.scss</p>
<h2 id="주의사항">주의사항</h2>
<p>사전에 사용할 기술 스택과 라이브러리, 컨벤션을 모두 정리하고 세팅을 시작했지만, 세팅 도중에 몇 가지 변경사항이 생겼다. 하지만 바로 결정하기 힘든 부분이라 저녁을 먹으며 결정을 하고 나중에서야 세팅을 마무리했다. 그로 인해 변경 사항 중 몇 가지를 반영하지 않아 팀원들과 하나하나 찾아가며 수정해야 하는 불상사가 발생했다. 
다음에 <code>초기세팅을 할 때는 세팅 도중에 변경하는 일이 없도록 사전에 확실히 마무리하고 앉은 자리에서 끝내야겠다.</code> 그러면 번거로운 일 없이 깔끔하게 초기환경을 세팅할 수 있지 않을까.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ESLint와 Prettier 초기 설정 방법]]></title>
            <link>https://velog.io/@taekjun_s/eslint%EC%99%80-prettier-%EC%B4%88%EA%B8%B0-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@taekjun_s/eslint%EC%99%80-prettier-%EC%B4%88%EA%B8%B0-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 05 Sep 2021 09:33:05 GMT</pubDate>
            <description><![CDATA[<p>eslint는 주로 <strong>잘못 입력한 문법을 자동으로 수정</strong>(lint기능)하기 위해 사용하고, Prettier는 <strong>팀원 간의 코딩 컨벤션</strong>(포맷팅)을 맞추기 위해 사용합니다. 하지만 <code>eslint에 포맷팅 기능이 내장되어 있어 Prettier와 함께 사용할 경우 충돌이 발생</code>할 수 있습니다. 초기 설정 과정에서 충돌을 미연에 방지하고자 아래의 블로그와 위코드에서 제공한 가이드를 참고하여 eslint와 prettier에 대해 정리한 글입니다. 사용의 편의를 위해 작성하였습니다. 부족한 부분은 댓글로 알려주시면 감사하겠습니다.
<a href="https://simsimjae.medium.com/prettier%EC%99%80-eslint%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%84%A4%EC%A0%95-110dc8ab94b6">* 참고 블로그</a></p>
<h3 id="eslint-설치">eslint 설치</h3>
<ul>
<li>CRA(Create-React-App)에는 <code>eslint가 내장</code>되어 있으니 설치 파트는 건너뛰셔도 무방합니다.</li>
</ul>
<p><strong>1. <code>npm install eslint --save-dev</code></strong></p>
<p><strong>2. <code>npx eslint --init</code></strong>
:: 단, package.json파일이 없는 경우 <code>npm init</code>을 먼저 설치할 것</p>
<p>*<em>3. <code>npx eslint 적용할 파일명</code> *</em>
:: ex) npx eslint test.js</p>
<p><strong>4. git을 이용하는 경우에는 .gitignore 파일에 <code>.eslintcache</code> 추가하기</strong></p>
<h3 id="prettier와-충돌막기-포맷팅룰-세팅">Prettier와 충돌막기 (포맷팅룰 세팅)</h3>
<p>** 1. <code>npm i -D prettier eslint-config-prettier eslint-plugin-prettier</code> **</p>
<ul>
<li>eslint-config-prettier
:: prettier와 겹치는 포맷팅룰을 삭제</li>
<li>eslint-plugin-prettier
:: prettier의 포맷팅 기능을 추가</li>
</ul>
<p>** 2. 타입스크립트를 사용하는 경우만 아래의 내용을 추가 설치하시면 됩니다.**
:: <code>npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-react</code></p>
<ul>
<li>@typescript-eslint/parser
:: 타입스크립트 parser 사용</li>
<li>@typescript-eslint/eslint-plugin
:: 타입스크립트 룰 모음집</li>
<li>eslint-plugin-react
:: 리액트와 관련된 eslint 룰셋</li>
</ul>
<p>** 3. root에 <code>.eslintrc</code> 파일을 생성하여 아래 내용을 복사 붙여넣기** </p>
<ul>
<li>src, public폴더와 같은 위치에 생성할 것!</li>
</ul>
<blockquote>
</blockquote>
<pre><code>{
  &quot;extends&quot;: [&quot;plugin:prettier/recommended&quot;]
}</code></pre><h4 id="airbnb의-eslint를-같이-쓰고-싶다면-아래와-같이-해주세요">Airbnb의 eslint를 같이 쓰고 싶다면 아래와 같이 해주세요.</h4>
<p>1) <code>npm i -D eslint eslint-config-airbnb-base eslint-plugin-import</code></p>
<p>2) root에 <code>.eslintrc</code> 파일을 생성하여 아래 내용을 복사 붙여넣기</p>
<ul>
<li>src, public폴더와 같은 위치에 생성할 것!</li>
</ul>
<blockquote>
</blockquote>
<pre><code>{
  &quot;extends&quot;: [&quot;airbnb-base&quot;, &quot;plugin:prettier/recommended&quot;]
}</code></pre><p>** 4. 여기서부터는 팀 컨벤션에 따라 원하는 옵션을 추가하거나 뺄 수 있습니다. **</p>
<ul>
<li>추천 세팅</li>
</ul>
<p>1) root에 <code>.vscode</code>폴더를 만들고 <code>settings.json</code>을 파일 생성한 후에 아래 내용을 복사 붙여넣기
** setting<span style="color:red">s</span> 오타주의❗️ s빼먹으면 안됩니다❗️</p>
<blockquote>
</blockquote>
<pre><code>{
  &quot;editor.defaultFormatter&quot;: &quot;esbenp.prettier-vscode&quot;,
    &quot;editor.tabSize&quot;: 2,
  &quot;editor.formatOnSave&quot;: true,
    &quot;editor.codeActionsOnSave&quot;: {
    &quot;source.fixAll.eslint&quot;: true,
  },
    &quot;javascript.format.enable&quot;: false,
    &quot;eslint.alwaysShowStatus&quot;: true,
    &quot;files.autoSave&quot;: &quot;onFocusChange&quot;
}</code></pre><p>2) root에 <code>.prettierrc</code> 파일을 생성한 후 아래 내용을 복사 붙여넣기</p>
<blockquote>
</blockquote>
<pre><code>{
  &quot;printWidth&quot;: 100, // 한 줄에 들어갈 수 있는 글자 수 제한
  &quot;tabWidth&quot;: 2, // tab 클릭 시 들여쓰기 = space 2번 
  &quot;singleQuote&quot;: true, // 작은 따옴표 사용
  &quot;trailingComma&quot;: &quot;all&quot;, // [1, 2, 3,] 허용, false는 불허
  &quot;bracketSpacing&quot;: true, // [1,2] → [ 1, 2 ]
  &quot;semi&quot;: true, // 세미콜론 사용 여부
  &quot;useTabs&quot;: true, // 탭 사용 여부
  &quot;arrowParens&quot;: &quot;avoid&quot;, // (x) =&gt; x를 x =&gt; x로 변환
  &quot;endOfLine&quot;: &quot;lf&quot; // EoF 방식이라고 하는데 아직 이해 못함
}</code></pre><ul>
<li>주의사항
::  다양한 설정파일이 존재할 경우 다음과 같은 순서로 설정이 적용됩니다. 중복되는 항목은 마지막에 적용되는 설정이 반영됩니다.
<code>settings.json → .editorconfig → .prettierrc</code>
:: eslint와 prettier 외에 다른 포맷터는 충돌을 일으킬 수 있으니 설치하지 말 것 
:: Window 환경에서 delete &#39;cr&#39; prettier/prettier 문제가 발생할 수 있습니다. <a href="https://saengmotmi.netlify.app/trouble%20shooting/2020-06-28%20delete%20cr%20prettier/">도움이 될만한 글을 링크</a>로 남겨둡니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redux 학습 내용 정리 1차]]></title>
            <link>https://velog.io/@taekjun_s/Redux-%ED%95%99%EC%8A%B5-%EB%82%B4%EC%9A%A9-%EC%A0%95%EB%A6%AC-1%EC%B0%A8</link>
            <guid>https://velog.io/@taekjun_s/Redux-%ED%95%99%EC%8A%B5-%EB%82%B4%EC%9A%A9-%EC%A0%95%EB%A6%AC-1%EC%B0%A8</guid>
            <pubDate>Sat, 04 Sep 2021 08:48:14 GMT</pubDate>
            <description><![CDATA[<h4 id="전체적인-flow">전체적인 flow</h4>
<p><img src="https://images.velog.io/images/taekjun_s/post/3143e856-8cbc-4b45-b74e-6f931c7a45bd/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘_두 정수 사이의 합]]></title>
            <link>https://velog.io/@taekjun_s/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EB%91%90-%EC%A0%95%EC%88%98-%EC%82%AC%EC%9D%B4%EC%9D%98-%ED%95%A9</link>
            <guid>https://velog.io/@taekjun_s/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EB%91%90-%EC%A0%95%EC%88%98-%EC%82%AC%EC%9D%B4%EC%9D%98-%ED%95%A9</guid>
            <pubDate>Sat, 04 Sep 2021 06:36:30 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘의-문제">오늘의 문제</h1>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/12912">두 정수 사이의 합</a></p>
<h1 id="풀이">풀이</h1>
<blockquote>
</blockquote>
<pre><code>function solution(a, b) {
  let sumA = 0;
  let sumB = 0;
  if( a &gt; b) {
    sumA = a*(a+1)/2, sumB = (b-1)*b/2;
    return sumA - sumB;
  } else {
    sumA = (a-1)*a/2, sumB = b*(b+1)/2;
    return sumB - sumA;
  }
}</code></pre><h1 id="과정">과정</h1>
<p>1부터 n까지의 합을 계산하는 n(n+1)/2 공식을 사용했다. a와 b의 값을 비교하여 큰 값의 합에서 작은 값의 합을 빼는 방식으로 접근했다. 
예를 들어 a = 5, b = 3일 때, 1 ~ 5까지의 합(sumA)에서 1 ~ 2까지의 합(sumB)을 뺐고, 반대로 a = 4, b = 5일 때는, 1 ~ 5까지의 합(sumB)에서 1 ~ 3까지의 합(sumA)를 뺐다. </p>
<p>풀고 나니 보다 효율적인 방법이 있을 것 같아 다른 사람들의 풀이를 살펴봤다. 그리고 난 엄청난 충격에 빠졌다.</p>
<blockquote>
</blockquote>
<pre><code>function adder(a, b){
  return (a+b)*(Math.abs(b-a)+1)/2;
}</code></pre><p>위의 코드는 a부터 b까지의 산술평균을 구하는 (a+b)n/2 공식을 사용했다. 여기서 n은 a부터 b까지의 더할 숫자의 개수를 의미한다. 즉 <code>(a+b)n/2</code>는 <code>(a+b)(b-a+1)/2</code>와 같다. 그리고 개수를 셀 때 음수는 필요없으므로 (b-a)의 <code>절대값을 구하기 위해 Math.abs</code> 메소드를 사용했다. 
예를 들어 a = -10, b = 3일 때, 위의 식에 대입하면 <code>(-10 + 3)(|-10 - 3| + 1) / 2</code> 이므로 -7 * (|-13| + 1) / 2 = -49라는 값을 도출할 수 있다.</p>
<p>틈틈이 수학공부도 해야겠다.....</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[타입스크립트_1]]></title>
            <link>https://velog.io/@taekjun_s/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B81</link>
            <guid>https://velog.io/@taekjun_s/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B81</guid>
            <pubDate>Thu, 02 Sep 2021 07:17:00 GMT</pubDate>
            <description><![CDATA[<h1 id="기본-세팅-과정">기본 세팅 과정</h1>
<ul>
<li><p>npm install -g typescript
:: 전역 설치</p>
</li>
<li><p>tsc -v 
:: 버전 확인</p>
</li>
<li><p>index.html 생성</p>
</li>
<li><p>ts파일 생성
:: 타입스크립트 파일의 확장자는 ts이다.
(ex. app.ts)</p>
</li>
<li><p>tsc app.ts
:: ts파일을 js파일로 변환</p>
</li>
<li><p>tsc --init
:: tsconfig.json 파일 추가 
:: tsconfig.json 파일이 추가되며 duplicate function implementation 에러가 사라지는 것을 확인할 수 있다.</p>
</li>
<li><p>tsc -w app.ts
:: 자동 컴파일 </p>
</li>
<li><p>live server로 구현 내용 확인
<img src="https://images.velog.io/images/taekjun_s/post/1e1fa454-724a-489f-8111-38f6eaf5ad99/image.png" alt=""></p>
</li>
</ul>
<h1 id="특징">특징</h1>
<h3 id="1-다운-레벨링">1. 다운 레벨링</h3>
<p>ECMAScript의 하위 버전에서 상위 버전의 내용을 호환 가능하도록 변환하는 과정을 다운레벨링이라고 한다. 특정 파일을 ES6버전에 맞추고 싶다면 아래와 같이 코드를 입력하면 된다.
:: <code>tsc --target es2015 파일명 (input.ts 등)</code></p>
<h3 id="2-타입-추론">2. 타입 추론</h3>
<p>타입스크립트는 말 그대로 타입을 추론할 수 있다. 아래의 코드를 보자.</p>
<blockquote>
</blockquote>
<pre><code>let test = 5;
test = &#39;five&#39;; // error</code></pre><p>변수 test에 타입을 선언하지 않았지만 5를 할당하는 순간, 변수 test의 타입은 number로 추론되었다. 다시 말해서, 컴퓨터는 <code>let test:number = 5;</code> 로 인식했다. 그래서 변수 test에 문자열을 할당하게 되면 error를 반환한다.</p>
<h3 id="3-타입-명시">3. 타입 명시</h3>
<p>타입스크립트는 선언할 때 데이터 타입을 명시하기 위해 만들어진 언어로, 타입 명시는 타입스크립트의 본질이라고 말할 수 있다. 타입은 string, number, string[], number[], boolean 외에도 여러가지가 있으며 <code>선언할 때</code>, <code>변수</code>와 함수의 <code>매개변수</code> 그리고 <code>함수의 반환값</code>에 명시할 수 있다. </p>
<p>참고: <a href="https://poiemaweb.com/typescript-typing">PoiemaWeb</a></p>
<h4 id="1-변수">1) 변수</h4>
<blockquote>
</blockquote>
<pre><code>let greeting: string = &#39;hi&#39;;
greeting = &#39;welcome&#39;;</code></pre><h4 id="2-함수의-매개변수">2) 함수의 매개변수</h4>
<blockquote>
</blockquote>
<pre><code>function sendGreeting(message: string, userName: number) {
  return `${message}, ${userName}`;
}
&gt;
sendGreeting(&#39;hi&#39;, &#39;Jack&#39;) // hi, Jack
sendGreeting(&#39;hi&#39;, 1) // 매개변수와 타입이 다르므로 error 반환
sendGreeting(&#39;hi&#39;) // 매개변수와 인자의 수가 일치하지 않으므로 error 반환</code></pre><ul>
<li>특이사항
:: 매개변수와 <code>타입이 다른 인자는 에러가 발생한다.</code>
:: <code>매개변수 수와 인자 수는 일치</code>해야 한다.</li>
</ul>
<h4 id="2-1-선택적-매개변수">2-1) 선택적 매개변수</h4>
<p>입력을 해도 되고 안해도 되는 매개변수를 만들고 싶다면 optional을 활용하면 된다. optional로 만들고 싶은 변수(혹은 매개변수 등)뒤에 물음표를 붙여주면 된다. <code>userName?: number</code>  이런 식으로.</p>
<blockquote>
</blockquote>
<pre><code>function sendGreeting(message: string, userName?: number) {
  return `${message}, ${userName}`;
}
&gt;
sendGreeting(&#39;hi&#39;, &#39;Jack&#39;) // hi, Jack
sendGreeting(&#39;hi&#39;) // hi, undefined
sendGreeting(&#39;hi&#39;, 1) // 매개변수와 타입이 다르므로 error 반환</code></pre><ul>
<li>특이사항
:: 단, <strong>인자가 전달되지 않으면 undefined를 반환</strong>한다.
:: 선택적 매개변수는 <strong>반드시</strong> <code>필수 매개변수 뒤에 위치</code>해야 한다.</li>
</ul>
<h4 id="2-2-기본-매개변수">2-2) 기본 매개변수</h4>
<p>선택적 매개변수를 사용할 때, <code>undefined가 반환되는 것을 방지</code>하기 위해 기본 매개변수를 사용한다. 그리고 기본 매개변수를 사용하면 타입추론으로 인해 타입을 명시할 필요가 없고, 선택적 매개변수 역시 적용되지 않는다.</p>
<blockquote>
</blockquote>
<pre><code>function sendGreeting(message = &#39;Hello&#39;, userName = &#39;there&#39;) {
  return `${message}, ${userName}`;
}
&gt;
sendGreeting(); // hello, there
sendGreeting(&#39;Good Morning&#39;); // Good morning, there
sendGreeting(&#39;Good afternoon&#39;, &#39;Jenny&#39;); // Good afternoon, Jenny</code></pre><h4 id="3-함수의-반환값">3) 함수의 반환값</h4>
<p>함수가 반환하는 값의 타입 또한 지정할 수 있는데, 매개변수를 지정하는 소괄호 다음에 타입을 지정하면 된다. 예를 들면 <code>function greeting (msg = &#39;Hello&#39;, user = &#39;there&#39;):string { }</code> 이런 식으로 사용할 수 있다.</p>
<blockquote>
</blockquote>
<pre><code>function sendGreeting(message = &#39;Hello&#39;, userName = &#39;there&#39;):string {
  return `${message}, ${userName}`;
}</code></pre><ul>
<li>특이사항
:: 타입 <code>void는 오로지 반환값이 없는 함수만 명시할 수 있다.</code>
:: 지정한 반환값의 타입과 실제 반환값이 다를 경우, 에러가 발생한다.</li>
</ul>
<h4 id="3-1-void">3-1) void</h4>
<p>타입 void에는 null과 undefined만 할당이 가능하다.</p>
<p>단, <code>--strictNullChecks</code>가 true일 때는, null은 <code>any</code>와 <code>null 타입에만 할당할 수 있다.</code> (undefined는 예외적으로 void에 할당 가능)</p>
<h4 id="3-2-화살표-함수식으로-변환">3-2) 화살표 함수식으로 변환</h4>
<blockquote>
</blockquote>
<pre><code>const sendGreeting = (message: &#39;Hello&#39;, userName = &#39;there&#39;):void =&gt; {
  console.log(`${message}, ${userName}`);
}</code></pre><ul>
<li>특이사항
:: 위의 코드와 같이 반환값이 없는 경우 반환값의 타입으로 void를 지정한다.</li>
</ul>
<h4 id="3-3-객체구조의-형태로-타입을-지정">3-3) 객체구조의 형태로 타입을 지정</h4>
<p>함수의 반환값을 객체 형태의 타입으로 지정할 수도 있다.</p>
<blockquote>
</blockquote>
<pre><code>function getData(data:number):{
  studentID: number;
  studentName: string;
  gender: string;
  data: number;
} {
  return data;
}</code></pre><h3 id="4-타입-단언">4. 타입 단언</h3>
<p>타입이 헷갈리지 않도록 한 가지 타입으로 단언하는 것을 말한다. 단언을 하는 방법에는 angle-bracket문법과 as문법이 있다. <code>JSX와 함께 사용할 때는, as문법의 단언만 허용된다.</code></p>
<p>4-1) angle-bracket&quot; 문법</p>
<blockquote>
</blockquote>
<pre><code>let someValue: any = &quot;this is a string&quot;;
let strLength: number = (&lt;string&gt;someValue).length;</code></pre><p>4-2) as-문법</p>
<blockquote>
</blockquote>
<pre><code>let div = document.querySelector(&#39;div&#39;) as HTMLDivElement // let div: HTMLDivElement
div.innerText;</code></pre><p>단언하기 전 div는 HTMLDivElement || null의 유니언 타입을 가지고 있다. null일 경우 오류가 발생할 수 있기때문에 에러를 띄운다. 이 때 <code>에러를 미연에 방지</code>하기 위해 타입을 단언한다.</p>
<h3 id="5-interface">5. Interface</h3>
<p>객체 형태의 타입을 지정할 때 효율성과 가독성을 높여주는 것이 바로 interface이다. interface는 ts에서 js로 컴파일할 때 삭제되기때문에 렌더링에 영향을 주지 않는다.</p>
<blockquote>
</blockquote>
<pre><code>interface Student {
  studentID: number;
  studentName: string;
  gender: string;
  data: number;
}
&gt;
function getData(data:number):Student{
  return {
    studentID: number;
    studentName: string;
    gender: string;
    data: number;
  };
}</code></pre><ul>
<li>특이사항
:: 반드시 <strong>대문자로 시작</strong>한다.
:: interface의 구조와 return 값의 구조는 동일해야 한다. 만약 return 값이 interface의 구조와 다르다면 에러가 반환되는 것을 확인할 수 있다.</li>
</ul>
<h4 id="4-1-interface-내-메소드-사용">4-1) interface 내 메소드 사용</h4>
<blockquote>
</blockquote>
<pre><code>interface Student {
  studentID: number;
  studentName: string;
  gender?: string;
  data: number;
  addComment? (comment: string): string;     
  deleteComment?: (comment:string) =&gt; string;
}
&gt;
function getData(data:number):Student{
  return {
    studentID: number;
    studentName: string;
    data: number;
  };
}</code></pre><h4 id="4-2-읽기전용-프로퍼티">4-2) 읽기전용 프로퍼티</h4>
<p>특정 프로퍼티 앞에 readonly를 붙이면 된다. 읽기전용으로 만들 경우 <code>재할당이 불가능</code>하다.</p>
<p>예제 1.</p>
<blockquote>
</blockquote>
<pre><code>interface Student {
  readonly studentID: number;
  studentName: string;
  gender?: string;
  data: number;
  addComment? (comment: string): string;     
  deleteComment?: (comment:string) =&gt; string;
}
&gt;
function getData(data:number):Student{
  return {
    studentID: number;
    studentName: string;
    data: number;
  };
}</code></pre><p>예제 2.</p>
<blockquote>
</blockquote>
<pre><code>let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray&lt;number&gt; = a;
ro[0] = 12; // 오류!
ro.push(5); // 오류!
ro.length = 100; // 오류!
a = ro; // 오류!</code></pre><h4 id="4-3-선택적-프로퍼티">4-3) 선택적 프로퍼티</h4>
<p>return할 때 interface의 내용을 빼고 싶다면?! 이 때 활용할 수 있는 것이 optional이다. 선택적 매개변수와 동일한 방법으로 사용할 수 있다.</p>
<blockquote>
</blockquote>
<pre><code>interface SquareConfig {
  color?: string;
  width?: number;
}
&gt;
function createSquare(config: SquareConfig): {color: string; area: number} {
  let newSquare = {color: &quot;white&quot;, area: 100}; // 기본값
  if (config.color) {
      newSquare.color = config.color;
  }
  if (config.width) {
      newSquare.area = config.width * config.width;
  }
  return newSquare;
}
&gt;
let mySquare = createSquare({color: &quot;black&quot;});</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘_K번째 수]]></title>
            <link>https://velog.io/@taekjun_s/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98K%EB%B2%88%EC%A7%B8-%EC%88%98</link>
            <guid>https://velog.io/@taekjun_s/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98K%EB%B2%88%EC%A7%B8-%EC%88%98</guid>
            <pubDate>Thu, 02 Sep 2021 05:41:10 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘의-문제">오늘의 문제</h1>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/42748">K번째 수</a></p>
<h1 id="풀이">풀이</h1>
<blockquote>
</blockquote>
<pre><code>function solution(array, commands) {
  let answer = [];
  commands.map(el =&gt; {
    let result;
    result = (array.slice(el[0]-1, el[1]).sort((a, b) =&gt; {return a - b}))[el[2]-1];
    answer.push(result);
  })
  return answer;
}</code></pre><h1 id="과정">과정</h1>
<p>오늘 문제의 핵심은 sort였다. 처음에 sort()로 사용하며 순서를 정의하지 않고 사용하였더니 테스트 2번에서 에러가 발생했다.</p>
<p>sort 메소드를 사용할 때 순서를 정의하는 함수를 넣지 않을 경우에는, 비교 대상을 모두 문자열로 변환하며 유니코드를 기준으로 정렬한다.</p>
<p>[1, 5, 10, 20, 16]을 정렬하는 경우, 순서를 정의하는 함수에 따라 아래와 같이 결과값이 달라진다.</p>
<p><code>1. sort(); // [1, 10, 16, 20, 5]</code>
<code>2. sort(function(a, b) {return a - b}); // [1, 5, 10, 16, 20]</code>
:: 오름차순 (a - b)
<code>3. sort(function(a, b) {return b - a}); // [20, 16, 10, 5, 1]</code>
:: 내림차순 (b - a)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘_폰켓몬]]></title>
            <link>https://velog.io/@taekjun_s/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%ED%8F%B0%EC%BC%93%EB%AA%AC</link>
            <guid>https://velog.io/@taekjun_s/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%ED%8F%B0%EC%BC%93%EB%AA%AC</guid>
            <pubDate>Thu, 02 Sep 2021 05:20:54 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘의-문제">오늘의 문제</h1>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/1845">폰켓몬</a></p>
<h1 id="풀이">풀이</h1>
<blockquote>
</blockquote>
<pre><code>function solution(nums) {
  let trans = new Set(nums);
  let array = [...trans];
  let numsCount = nums.length/2;
  let arrayCount = array.length;
&gt;  
  if (nums.length/2 &gt;= array.length) {
    return arrayCount;
  } else {
    return numsCount;
  }  
}</code></pre><h1 id="과정">과정</h1>
<p>오늘의 문제의 핵심은 중복 제거였다. 위코드 초기에는 새 배열을 만들고 push, shift 메소드를 활용해 중복을 제거하는 방법을 활용했다면 이번에는 set을 활용하여 문제를 풀었다.</p>
<ul>
<li>set은 배열을 입력하면 중복 값을 제거하여 유일한 값만 저장한다.</li>
</ul>
<p><code>1. let trans = new Set([1, 2, 3, 3]);</code>
<code>2. console.log(trans); // Set(3) {1, 2, 3}</code></p>
<ul>
<li>이 값들을 배열로 변환하기 위해 스프레드 오퍼레이터를 활용한다.</li>
</ul>
<p><code>3. let array = [...trans];</code>
<code>4. console.log(array); // [1, 2, 3]</code></p>
<ul>
<li>위의 과정을 축약하면 아래와 같다.</li>
</ul>
<p><code>let trans = [...new Set([1, 2, 3, 3])]</code></p>
<p>위의 내용을 토대로 리팩토링을 진행했다.</p>
<blockquote>
</blockquote>
<pre><code>function solution(nums) {
  let array = [...new Set(nums)];
  return array.splice(0, nums.length/2).length;
}</code></pre><p>조금 더 찾아보니 위의 코드를 한 줄로 줄일 수도 있었다.</p>
<blockquote>
</blockquote>
<pre><code>const solution = nums =&gt; [...new Set(nums)].splice(0, nums.length/2).length;</code></pre><p>단지 효율성만을 위한 코드를 짠다면 한 줄로 줄인 코드가 최선이고,
가독성과 효율성 모두를 고려한다면 처음 리팩토링한 코드가 최선 아닐까?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[아워스페이스 프로젝트 4일차]]></title>
            <link>https://velog.io/@taekjun_s/%EC%95%84%EC%9B%8C%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-4%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@taekjun_s/%EC%95%84%EC%9B%8C%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-4%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 20 Aug 2021 07:08:03 GMT</pubDate>
            <description><![CDATA[<ul>
<li>오늘의 미팅 내용
<img src="https://images.velog.io/images/taekjun_s/post/05a32d20-3c1b-4dc0-86db-d272ab789dc6/image.png" alt=""></li>
</ul>
<h1 id="오늘-한-일">오늘 한 일</h1>
<ul>
<li>캘린더 컴포넌트와 예약 컴포넌트 머지</li>
<li>예약 컴포넌트</li>
</ul>
<h1 id="기록">기록</h1>
<ul>
<li>자식 컴포넌트에서 부모 컴포넌트로 데이터 전달하는 방법
1) 부모 컴포넌트에서 함수를 선언하고, 해당 함수를 자식 컴포넌트에 props로 넘겨준다.
2) 전달받은 함수를 자식 컴포넌트에서 호출하되, 전달할 데이터를 함수의 인자로 입력한다.</li>
</ul>
<h1 id="문제">문제</h1>
<ol>
<li>cannot update a component (&#39;...&#39;) while rendering a different component (&#39;...&#39;)</li>
</ol>
<ul>
<li>상황: 연결된 컴포넌트 또는 페이지가 동시에 렌더링이 일어나서 발생하는 오류</li>
<li>원인
:: 함수형 컴포넌트를 사용할 때, state가 컴포넌트끼리 연결되어있는 상태에서 state값이 변경되면 연결된 모든 컴포넌트에서 동시에 렌더링이 발생한다.</li>
<li>해결방안<ul>
<li>state가 변하면 렌더링이 발생하므로 전달할 데이터를 변수에 담아서 전달한다.</li>
</ul>
</li>
</ul>
<p>며칠동안 state의 특성을 정확하게 이해하지 못하고, 잡힐듯말듯 애매한 상태가 지속되어 답답했었는데, 잠결에 뭔가가 머리 속을 스쳐지나가면서 단번에 이해가 되었다. 이런 경험이 처음이라 당황스럽기도 하고 새롭기도 해서 기록으로 남기기 위해 블로그에 적는다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[아워스페이스 프로젝트 2일차]]></title>
            <link>https://velog.io/@taekjun_s/%EC%95%84%EC%9B%8C%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@taekjun_s/%EC%95%84%EC%9B%8C%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 19 Aug 2021 10:33:27 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-한-일">오늘 한 일</h1>
<ul>
<li>상세페이지 레이아웃 구현</li>
<li>예약 컴포넌트 레이아웃 구현</li>
<li>react-datepicker 라이브러리 사용</li>
</ul>
<h1 id="끄적">끄적</h1>
<p>처음으로 라이브러리를 사용했다. <a href="https://www.npmjs.com/package/react-datepicker">react-datepicker</a>라는 캘린더 라이브러리인데 사용하기 쉬워 많이 사용되는 라이브러리라고 한다. 공식 홈페이지를 있는 코드를 참고하면 커스터마이징도 가능하다.</p>
<ol>
<li><p>설치
:: npm install react-datepicker --save</p>
</li>
<li><p>package.json 파일에서 설치 여부 확인
:: &quot;react-datepicker&quot;: &quot;^4.2.0&quot; (21.08.19.)</p>
</li>
<li><p>사용하려는 페이지에 import
:: import DatePicker from &quot;react-datepicker&quot;;
:: import &quot;react-datepicker/dist/react-datepicker.css&quot;;</p>
</li>
</ol>
<p>CSS를 커스터마이징하기 위해 크롬 개발자 도구에서 하나씩 찍어가며 클래스 네임을 파악해야 했다. 
<img src="https://images.velog.io/images/taekjun_s/post/8230075f-7fae-4661-870d-26fc8ae851b5/image.png" alt=""></p>
<p>아래는 저렇게 하나씩 찍어가며 만든 결과물!!</p>
<p><img src="https://images.velog.io/images/taekjun_s/post/d9819827-9bd4-41b4-83c3-23eb98339b1d/image.png" alt=""></p>
<p>생각보다 결과물이 너무 잘나와서 마음에 쏙 들었다. 처음에는 아무 것도 모르고 라이브러리를 통째로 뜯어서 고치려고도 했었는데 멘토님께 여쭤보니 그건 지금 할 수 있는 일은 아니라고 단호하게 말씀하셨다. 
앞으로도 라이브러리를 쓸 일이 많겠지. 라이브러리를 뜯었을 때 분석할 수 있는 수준으로 얼른 성장해야지. </p>
<blockquote>
</blockquote>
<p>언젠가는 <code>나만의 라이브러리를 직접 만들어서 쓰는</code> 개발자가 되어야지.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[아워스페이스 프로젝트 1일차]]></title>
            <link>https://velog.io/@taekjun_s/%EC%95%84%EC%9B%8C-%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@taekjun_s/%EC%95%84%EC%9B%8C-%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Wed, 18 Aug 2021 01:24:49 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>클론 사이트
:: <a href="https://www.spacecloud.kr/">스페이스 클라우드</a></p>
</li>
<li><p>프로젝트 기간
:: 21.08.17 ~ 21.08.27.</p>
</li>
<li><p>프로젝트 참여 인원
:: 프론트(4명) - 이수정, 최호정, 이현준, 심택준
:: 백엔드(2명) - 장이주, 임종성</p>
</li>
<li><p>프로젝트 목표
:: 기능 위주로 구현해보기
:: git rebase 사용
:: Styled component 사용
:: 함수형 컴포넌트 사용</p>
</li>
<li><p>필수 구현 사항
:: 메인 페이지
:: 네비게이션 바
:: 로그인 페이지
:: 리스트 페이지
:: 상세 설명 페이지
:: 예약 기능
:: 공간 등록 기능
:: 리뷰 기능</p>
</li>
<li><p>추가 구현 사항
:: 푸터
:: 검색 
:: 리스트 지도
:: 리스트 필터
:: 찜하기
:: 마이 페이지
:: 예약리스트</p>
</li>
</ul>
<h1 id="오늘-한-일">오늘 한 일</h1>
<ul>
<li>프로젝트 주제 및 팀 공개</li>
<li>프로젝트 진행 방향 설정
:: 프론트/백엔드 간이 미팅(5분 내외) 후 팀 데일리 오전 미팅 진행
:: 오후 6시 30분 프론트/백엔드 간이 미팅 후 데일리 wrap-up 진행</li>
<li>깃허브 초기환경 세팅</li>
<li>Styled Component 설치 및 초기 세팅</li>
<li>벨로그 생성</li>
<li>슬랙 채널 개설</li>
<li>API 정의서 생성하기</li>
<li>상세 페이지 및 예약 컴포넌트 초기 레이아웃 구현</li>
</ul>
<h1 id="끄적">끄적</h1>
<p>PM이 되었다. 하루가 어떻게 갔는지도 모르겠다. 초기 세팅하랴, 미팅 시간과 방법 정하랴, 정신이 없었다. 이번에도 깃 초기환경은 내가 세팅했는데, 역시나 문제가 생겼다.</p>
<p>프로젝트 폴더보다 상위 폴더에 git init을 입력하면서 프로젝트 폴더에 .git폴더가 생성되지 않았다. 이를 모른 채로 push했더니 멘토님께서 수정 리뷰를 남겨주셨다. 알아보니 Create React App을 설치하면 자동으로 해당 폴더에 .git폴더를 생성한다. 그래서 git init을 별도로 입력하지 않아도 된다. 그리고, <code>상위 폴더에 .git폴더가 있는 경우</code> 하위 폴더에서 Create React App을 입력하더라도 .git폴더가 생성되지 않는다.</p>
<ul>
<li><p>결론:  git push할 경우 상위 폴더가 push되면 .git폴더가 어디 위치해있는지 찾아보자.</p>
</li>
<li><p>해결 방법</p>
</li>
</ul>
<ol>
<li>상위 폴더에서 .git 폴더를 삭제하고 원하는 폴더에서 git init 실행한다.</li>
<li>local과 github repository를 새로 연결한다.
:: git remote URL</li>
<li>git add .</li>
<li>git commit -m &quot;first commit&quot;</li>
<li>git push origin master --f
:: --f(force)를 입력하지 않으면 push가 reject된다.
:: force를 입력하면 기존의 내용 위에 강제로 덮어씌여지며 기존 내용이 사라진다.</li>
<li>github에서 업데이트 되었는지 확인</li>
</ol>
<blockquote>
</blockquote>
<p>1차 프로젝트에서 종규님이 팀을 이끌던 기억을 되살려, 회고할 때 세웠던 목표를 이루었으면 한다. <strong>PM 화이팅!!</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[치킨푸드 프로젝트 후기 겸 회고록]]></title>
            <link>https://velog.io/@taekjun_s/%EC%B9%98%ED%82%A8%ED%91%B8%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0-%EA%B2%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@taekjun_s/%EC%B9%98%ED%82%A8%ED%91%B8%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0-%EA%B2%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Mon, 16 Aug 2021 05:28:25 GMT</pubDate>
            <description><![CDATA[<p>위코드에서의 1차 프로젝트가 끝났다. 여러가지 복잡한 감정이 뒤섞여있으니 먼저 간략한 소감으로 감정을 차분히 가라앉힌 다음, 회고록을 남겨보려 한다.</p>
<h1 id="소감">소감</h1>
<p>우선 치킨푸드 팀원들 모두에게 다시 한 번 감사 인사를 하고 싶다. 프로젝트 중간중간에도, 마치고 나서도 인사했지만 내가 프로젝트에 대해 느끼는 긍정적인 감정의 대부분은 팀원들 덕분이라고 생각한다. &#39;갈등이 없어서 이상하다, 이게 맞나?&#39;라는 생각이 들 정도로 소통이 잘 되었고 서로가 서로를 배려하는 마음이 너무 잘 느껴졌다. 2차 프로젝트에서도 다들 큰 고비없이 원하는 바를 이루었으면 하는 바람이다.</p>
<p>마지막으로 우리 팀이 클론한 사이트의 전반적인 flow를 끝으로 소감은 마무리!
<img src="https://images.velog.io/images/taekjun_s/post/14867cdc-5bdc-4a26-9188-96a3d01b1cb3/ezgif.com-gif-maker.gif" alt=""></p>
<h1 id="프로젝트-회고">프로젝트 회고</h1>
<p>처음으로 작성하는 회고록이다보니 막연하기도 했고, 두고두고 읽히는 회고록을 작성하고 싶었다. 그래서 선배 개발자들의 프로젝트 회고록을 참고하여 어떻게 쓸지 방향을 잡았다.</p>
<p>회고록은 프로젝트를 진행하며 겪은 사실을 바탕으로 <code>내가 느낀 점을 정리하여, 우리가 더 나은 방향으로 발전하기 위해 적는 글</code>이다. 그래서 주제를 크게 <code>나</code>, <code>프로젝트</code> 그리고 <code>우리</code>로 나누어 쓰기로 했다.</p>
<h3 id="1-프로젝트">1. 프로젝트</h3>
<p>내가 프로젝트에서 맡은 파트는 <code>로그인 페이지</code>, <code>회원가입 페이지</code>, <code>네비게이션 바</code>, 그리고 <code>마이 페이지</code>까지 총 4가지였다. </p>
<p>위에서 보면 알다시피 로그인 페이지와 회원가입 페이지는 내가 원하는 방향에 맞춰, 구현하려는 기능을 모두 구현하였기에 너무나도 만족스럽게 완성되었다. <code>&#39;재사용성을 높인 코드를 만들겠다&#39;</code>는 개인적인 목표와 팀의 목표를 모두 충족시킨 페이지였다.</p>
<p><strong>반면에 네비게이션 바와 마이 페이지는 아쉬운 점이 많이 남았다.</strong></p>
<p>네비게이션 바는 컴포넌트가 3단계로 구성되어 있어서 동적 라우팅을 연결하려니 경로를 트래킹하기가 거의 불가능에 가까웠다. 애초에 나는 a태그를 활용해 링크를 직접 꽂아줄 계획으로 각각의 상수 데이터를 만들었다. (리액트에 대한 이해도 부족으로 발생한 대참사였다.)</p>
<img src="https://images.velog.io/images/taekjun_s/post/3c6bb4b2-4a1a-45d4-a704-089c5d7c3aad/image.png">

<p>Nav컴포넌트에서 상수데이터를 구역별로 각각 만들어 ListComponent와 연결시켰다. 여기까지는 괜찮았지만 문제는 subNav에서 발생했다.</p>
<p>subListComponent를 새로 만들어서 subCategory_list 상수 데이터를 nav → SubLiComponent → ListComponent로 전달하는 단계를 거치다보니 동적 라우팅의 경로를 지정하기가 힘들었다.</p>
<img src="https://images.velog.io/images/taekjun_s/post/21a5ab8c-bf2d-44ce-b75c-bac0cf4be9f8/image.png" width="300px" />

<p>1-1) SubLiComponent의 코드</p>
<img src="https://images.velog.io/images/taekjun_s/post/e4c7d138-8ae7-458c-8a57-0503bbee3899/image.png" width="300px" />

<p>1-2) subCategory_list 상수 데이터의 코드</p>
<img src="https://images.velog.io/images/taekjun_s/post/0a08c2d5-eeea-487c-ae8a-b5faf6aa6511/image.png" width="300px" />

<p>심지어 동적 라우팅에 익숙하지 않은 데다가, 최종 발표까지 위코드에서 의논할 수 있는 시간이 10시간도 채 남지 않은 상황이었다. 결국 우리는 발표까지 동적 라우팅을 완벽하게 적용하지 못해 몇몇 페이지를 시현하지 못했다. 팀원들이 고생하여 만든 페이지를, 기능을 보여줄 수 없다는 사실에 발표를 하면서도 큰 자괴감이 들었다. 동적 라우팅을 미리 공부했다면..., 최종 머지가 일찍 이루어졌다면..., 돌이킬 수 없는 후회가 머리 속을 한참동안 떠나지 않았다.</p>
<p>지금와서 여유를 가지고 생각해보면 네비게이션 바를 새로 만드는게 오히려 빠를 수도 있었고, 숙소를 잡고 새로운 대안을 찾을 수도 있었다. 문제를 발견했을 당시에 최선의 선택을 하지 못한 이유가 무엇일까?</p>
<p><code>마감이 코앞이라는 생각에 마음이 조급해져 눈앞에 보이는 문제를 해결하기에 급급했다.</code> 생각해보면 마이 페이지도 급하게 만들어지면서 퀄리티가 많이 떨어졌다.  그리고 백신 접종 일정으로 인해 멘토님들께서 바빠지시면서 최종 머지가 지연되는 동안에도, &#39;늦지 않게 해주시겠지&#39;라며 <code>대비책을 마련하지 않고 안일하게 기다리기만 했다.</code> 이 두 가지가 가장 주요한 원인이었다고 생각한다.</p>
<blockquote>
<p>#결론 요약</p>
</blockquote>
<ul>
<li>2차에서는 각각의 모듈을 완성해서 붙이는 방법이 아닌, 우선 기본적인 틀을 만들어 <strong>하나의 온전한 결과물을 만든 후에 기능을 하나씩 덧붙이는 방법</strong>으로 프로젝트를 진행해야겠다. </li>
<li>그리고 <strong>마감기한 하루 전</strong>까지는 완성하는 방향으로 계획을 짜야겠다.</li>
<li>한 가지 더, 1차 때처럼 호흡이 너무 잘맞아 여유가 생기거든 문제가 발생할 수 있는 경우의 수를 충분히 고민하고 그에 대한 <strong>대비책을 미리 마련</strong>해야겠다. </li>
</ul>
<h3 id="2-우리">2. 우리</h3>
<p>우리 팀은 프로젝트를 진행하며 무엇을 소통해야 하는지조차도 몰랐던 나에게, 프로젝트를 하며 소통 해야 하는 내용뿐만 아니라 소통 방법에 대해서도 알려주었다. 그 내용을 앞으로의 프로젝트에서도 활용하기 위해 정리해보았다.</p>
<h4 id="1-api-정의서">1) API 정의서</h4>
<p>프론트와 백엔드가 <code>데이터를 주고 받을 때</code> JSON을 이용할 경우에는 <code>객체의 형태</code>를 이용한다.  </p>
<p>만약 백엔드에서 name이라는 키 값으로 데이터를 전송했는데, 프론트에서는 키 값을 member라고 입력하고 데이터를 받으려고 한다면, 원하는 데이터를 사용할 수 없다. </p>
<p>키 값을 일치시키지 않을 경우 통신하는 과정에서 고생할 것이 분명하기에, 팀원 모두가 동일한 키 값을 사용하는 것이 중요하다. 이를 위해 우리 팀은 <code>시작 단계</code>에서 종규님의 주도 하에 <code>API정의서를 제작</code>했고, <code>트렐로에 업로드</code>하여 프로젝트 기간동안 <code>수시로 확인</code>하며 무난하게 통신할 수 있었다.</p>
<ul>
<li>치킨푸드 팀의 API 정의서
<img src="https://images.velog.io/images/taekjun_s/post/4dc23cf8-74a4-4242-afec-fc379b9e7edd/%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-08-09%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.09.03.png" alt=""></li>
</ul>
<h4 id="2-configjs">2) config.js</h4>
<p>통신을 할 때 반드시 입력해야 하는 것이 하나있다. 바로 <code>서버의 IP주소</code>다. 우리의 서버는 유동IP였기에 매일 IP주소를 갱신해야 하는 불편함이 있었다. 한 두 개를 수정할 때는 그런가보다 했는데 점점 수정사항이 늘어날수록 오타가 증가하는 등 IP주소를 바꾸는 일이 스트레스로 다가왔다. 
이를 한 번에 해결할 수 있는 것이 config.js다. config.js는 <code>IP만을 관리하는 환경 변수 파일</code>인데, IP를 변수에 할당해서 사용하기때문에 일일이 바꿀 필요없이 변수 값만 변경해주면 된다. 심지어 common.scss처럼 <code>공용으로 사용</code>하니 팀원 모두가 사소한 일로 스트레스 받는 일이 줄어들었다.</p>
<h4 id="3-시각-자료">3) 시각 자료</h4>
<p>우리 팀의 경우에는 시각 자료를 다양하게 활용하는 모습을 볼 수 있었다. 
미팅시간이 되면 <code>프론트 멤버들은 노트와 볼펜</code>을 챙겼고, <code>백엔드 멤버들은 노트북</code>을 챙겼다. 프론트가 노트와 펜으로 그려가며 설명했다면, 백엔드는 keynote와 excel을 활용해 데이터를 정리하여 설명했다. 그리고 미팅이 끝나면 PM이 트렐로에 미팅 내용을 정리하여 업로드했다.</p>
<ul>
<li><p>키노트
<img src="https://images.velog.io/images/taekjun_s/post/d3602990-e783-4229-bb41-765b43bcdaa1/image.png" alt=""></p>
</li>
<li><p>노트
<img src="https://images.velog.io/images/taekjun_s/post/8f53b94e-eba2-4a82-9900-bb838d62dfdd/3D693D13-18A0-4722-8B2B-B44A226EF2F8_1_105_c.jpeg" alt=""></p>
</li>
<li><p>정리
<img src="https://images.velog.io/images/taekjun_s/post/d2b14c83-a79d-408e-a6d3-372f3ca0f2fa/%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-08-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.34.16.png" alt=""></p>
</li>
</ul>
<p>이렇듯 우리 팀의 소통은 과정과 끝이 명확했다. </p>
<p>LOVE면담 때까지만 하더라도  원활한 소통을 위해서는 지식이 중요하다고 생각했다. 소통은 구두로만 이루어지는 것이고, 상대방을 이해시키기 위해서는 상대방의 언어로 말해야만 한다고 생각했다. 우리 팀이 소통하는 방법을 관찰하기 전까지는 말이다.</p>
<p>2차 프로젝트에서는 시각 자료를 활용하고, 미팅 내용을 기록했을 때 1차와 달리 다른 문제가 발생하지는 않는지 관찰해봐야겠다.</p>
<blockquote>
<p>#결론 요약</p>
</blockquote>
<ul>
<li><strong>시각 자료 활용</strong>하기</li>
<li><strong>기록으로 남기기</strong></li>
<li>상대방의 말을 정확히 이해한 것이 맞는지, 그 자리에서 <strong>내가 이해한 내용을 상대방에게 얘기</strong>하기</li>
</ul>
<h3 id="3-나">3. 나</h3>
<p>나에 대한 부분은 수정보완하여 업데이트 예정!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[치킨푸드 프로젝트 10일차 그리고 회고]]></title>
            <link>https://velog.io/@taekjun_s/%EC%B9%98%ED%82%A8%ED%91%B8%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A7%88%EC%A7%80%EB%A7%89</link>
            <guid>https://velog.io/@taekjun_s/%EC%B9%98%ED%82%A8%ED%91%B8%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A7%88%EC%A7%80%EB%A7%89</guid>
            <pubDate>Fri, 13 Aug 2021 02:58:33 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-한-일">오늘 한 일</h1>
<ul>
<li>발표 준비</li>
<li>ppt 마무리</li>
<li>최종발표</li>
<li>이력서 작성</li>
<li>회고록 작성</li>
</ul>
<h1 id="끄적">끄적</h1>
<p>페이지 개개인의 완성도는 치차하고 통일성이 가장 아쉬움
원인</p>
<ol>
<li><p>서로의 코드에 대해 살피지 않았다. 코드의 기능이 잘 작동하는지를구두로만 확인</p>
</li>
<li><p>시간이 촉박 (멘토님들의 백신접종 일정으로 인해 머지가 늦어짐)</p>
</li>
<li><p>프론트끼리 머지를 해서 기본 레이아웃을 기반으로 코드를 짜야함</p>
</li>
<li><p>나는 효율적인 코드라고 생각했지만 팀원들이 읽기는 힘들어헸다</p>
</li>
<li><p>리팩토링하며 코드의 재사용성에 대해서만 고려하고 동적 라우팅에 대한 고려를 하지 않았다. (url은 변하지 않기에 상수데이터에 입력 후 link로 연결하려고 했다)</p>
</li>
<li><p>재사용성은 활용할 만큼 활용해볼 수 있어서 익숙해지기도 했고 재밌었다</p>
</li>
</ol>
<p>공통</p>
<ul>
<li>CRA를 사용한 초기 세팅</li>
<li>common.scss 제작</li>
</ul>
<p>네비게이션 바</p>
<ul>
<li>공통 Nav UI 구현</li>
<li>로그인 상태에 따라 버튼 레이아웃 변경</li>
<li>Local Storage에서의 토큰의 여부를 통해 로그인 여부 확인</li>
<li>Local Storage에서 토큰을 삭제로 로그아웃 기능</li>
</ul>
<p>로그인/회원가입 페이지</p>
<ul>
<li>회원가입+로그인 페이지 UI 구현</li>
<li>fetch를 이용해 백엔드와 통신하여 회원가입 페이지에서 아이디 중복체크 및 추천인 확인 기능 구현</li>
<li>필수입력 사항 미입력시 회원가입 불가 기능 구현</li>
<li>회원가입페이지에서 비밀번호 일치 여부 검사 기능 구현</li>
<li>사용자 인증(Authentication) 완료에 따른, Local Storage에서의 access token(JSON Web Tokens) 관리</li>
</ul>
<p>마이페이지</p>
<ul>
<li>마이페이지 UI 구현</li>
<li>사용자 인증(Authentication) 완료에 따른, Local Storage에서의 access token(JSON Web Tokens) 관리</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[치킨푸드 프로젝트 9일차]]></title>
            <link>https://velog.io/@taekjun_s/%EC%B9%98%ED%82%A8%ED%91%B8%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-9%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@taekjun_s/%EC%B9%98%ED%82%A8%ED%91%B8%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-9%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 13 Aug 2021 02:48:18 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-한-일">오늘 한 일</h1>
<ul>
<li>프론트엔드 최종 merge</li>
<li>nav 동적 라우팅</li>
<li>세세한 오류 수정</li>
<li>1차 프로젝트 최종 발표 준비</li>
<li>ppt 작성</li>
</ul>
<h1 id="끄적">끄적</h1>
<p>저녁시간이 다되어 최종 merge가 이루어졌다. 그 전에 각각의 페이지가 백엔드와 통신이 이루어지고 기능이 모두 정상적으로 구현되는 모습을 확인까지 하고 merge를 했다. 물론 라우팅과정에서 문제가 발생할 거라고 예상은 했지만, 예상보다 문제가 컸다. </p>
<p>애초에 네비게이션 컴포넌트는 재사용성을 중심으로, 페이지의 경로를 각각 지정할 계획으로 리팩토링했다. 동적 라우팅의 존재 자체를 몰랐기에, 상수 데이터 파일을 만들어 경로를 직접 지정해줄 계획이었다. 그렇게 리팩토링은 지난 주에 끝났는데, 지난 화요일에 동적 라우팅에 대한 세션이 진행되며 나는 1차 멘붕에 빠졌다. 성훈 멘토님과 상의한 결과, 내 nav코드에서는 경로를 직접 지정해주는게 낫겠다는 결론이 나왔다. 이 때 이 내용을 팀원들과 공유했다면 미리 해결할 수 있었을까.</p>
<p>그렇게 최종 merge가 되고 SubNav(아래 이미지의 동그라미 친 부분)에서 동적 라우팅으로 다른 페이지에 접근하려 하면서 문제가 생겼다. </p>
<p><img src="https://images.velog.io/images/taekjun_s/post/3c6bb4b2-4a1a-45d4-a704-089c5d7c3aad/image.png" alt=""></p>
<p>내 코드는 하나의 ListComponent에 1번, 2번, 3번 각각의 상수 데이터를 연결해 다양한 곳에서 활용할 수 있도록 재사용성을 높이는 데에 초점을 맞췄다.</p>
<ul>
<li>하지만 subCategory_list 상수 데이터를 nav → SubLiComponent → ListComponent로 전달하는 단계를 거치다보니 동적 라우팅의 경로를 지정하기가 힘들었다.</li>
</ul>
<p>간략히 내 코드를 보자면,</p>
<p>1)   nav 컴포넌트(부모)에서 map을 활용해서 SubLiComponent에 subCategory_list의 데이터를 전달하는 코드</p>
<p><img src="https://images.velog.io/images/taekjun_s/post/21a5ab8c-bf2d-44ce-b75c-bac0cf4be9f8/image.png" alt=""></p>
<p>1-1) SubLiComponent의 코드</p>
<p><img src="https://images.velog.io/images/taekjun_s/post/e4c7d138-8ae7-458c-8a57-0503bbee3899/image.png" alt=""></p>
<p>1-2) subCategory_list 상수 데이터의 코드</p>
<p><img src="https://images.velog.io/images/taekjun_s/post/0a08c2d5-eeea-487c-ae8a-b5faf6aa6511/image.png" alt=""></p>
<p>아직 해결이 되지 않아 내일 발표 전까지 수정해보고, 대안에 대해서도 고민해봐야할 듯 하다.</p>
<p>끝❗️</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[치킨푸드 프로젝트 8일차]]></title>
            <link>https://velog.io/@taekjun_s/%EC%B9%98%ED%82%A8%ED%91%B8%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-8%EC%9D%BC%EC%B0%A8-frpnj39a</link>
            <guid>https://velog.io/@taekjun_s/%EC%B9%98%ED%82%A8%ED%91%B8%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-8%EC%9D%BC%EC%B0%A8-frpnj39a</guid>
            <pubDate>Wed, 11 Aug 2021 01:05:11 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-한-일">오늘 한 일</h1>
<ul>
<li>데이터와 토큰 받아서 mypage에 userName 입력하기</li>
</ul>
<h1 id="끄적">끄적</h1>
<ul>
<li>commons.scss의 내용을 다른 scss파일에서 사용하기 위해서는 scss파일에서 common.scss파일을 import해야 한다.</li>
</ul>
<ul>
<li>a태그를 div 태그로 바꾸고 onclick 이벤트 부여하는 방법을 쓸 수도 있다.
:: a태그는 페이지 새로고침이 발생
:: link태그와 a태그, onclick 이벤트 각각 어떤 차이가 있는지 찾아봐야겠다.</li>
</ul>
<p>오늘 처음으로 토큰을 다뤄봤다.</p>
<ul>
<li>주의할 점
1) URL 체크 사항
:: <code>http://</code>
:: <code>:8000</code></li>
</ul>
<blockquote>
</blockquote>
<pre><code>  submitUserInfo = e =&gt; {
    // e.preventDefault();
    fetch(&#39;http://10.58.1.207:8000/members/agreement&#39;, {
      method: &#39;POST&#39;,
      body: JSON.stringify(this.state.userInfo),
    })
      .then(response =&gt; response.json())
      .then(result =&gt; console.log(&#39;결과: &#39;, result));
  };</code></pre><p>로그인 성공 시 토큰 받아서 localStorage에 저장하는 코드</p>
<blockquote>
</blockquote>
<pre><code>fetch(&#39;LOGIN_API&#39;, {
  method: &#39;POST&#39;,
  body: JSON.stringify({
    email: this.state.email,
    password: this.state.password,
  })
})
  .then(res =&gt; res.json())
  .then(res =&gt; {
    if (res.message === &#39;SUCCESS&#39;) {
      localStorage.setItem(&#39;token&#39;, res.access_token);
      this.props.history.push(&#39;/main&#39;);
    } else {
      alert(&#39;다시 입력해주세요!&#39;)
    }
  })</code></pre><p>저장된 토큰 사용하는 방법</p>
<blockquote>
</blockquote>
<pre><code>fetch(&#39;UPDATE_CART_API&#39;, {
  method: &#39;POST&#39;,
  headers: {
    Authorization: localStorage.getItem(&#39;token&#39;),
  }
  body: JSON.stringify({
    cartId: this.state.cartId,  
  })
})
.then()
.then()</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[치킨푸드 프로젝트 7일차]]></title>
            <link>https://velog.io/@taekjun_s/%EC%B9%98%ED%82%A8%ED%91%B8%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-7%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@taekjun_s/%EC%B9%98%ED%82%A8%ED%91%B8%EB%93%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-7%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 10 Aug 2021 02:35:06 GMT</pubDate>
            <description><![CDATA[<h1 id="오늘-한-일">오늘 한 일</h1>
<ul>
<li>signup 아이디 중복체크 기능, 백엔드와 통신 완료</li>
<li>signin 페이지 리팩토링</li>
<li>conflict 해결</li>
</ul>
<h1 id="끄적">끄적</h1>
<p>어제 wrap-up 미팅에서 오늘 멘토님께서 merge해주시면 conflict해결 후에 전반적으로 수정하자는 얘기를 했다. 그런데 멘토님들의 백신 접종 일정때문에 오후 6시까지 merge가 되지 않아 본의아니게 시간이 붕 떠버렸다. 무엇을 해야 할 지 찾아헤매다가 로운님께서 도움을 요청하셔서 한동안 로운님을 도와드렸다. 계획이 틀어진 상태에서 갑자기 개인 공부를 하자니 글이 눈에 들어오지를 않았다. 위코드 기간동안 라운지를 배회한 적이 없었는데....
그런데 나만 그런게 아니라 동기 대부분이 오늘따라 루즈한 것처럼 느껴졌다. 그러다가 wrap-up 미팅 직전에 성훈 멘토님이 merge해주겠다는 말씀을 해주셔서 wrap-up 미팅 때 전반적인 계획을 수정했다. 회원탈퇴 기능까지 구현해보는게 2차 스프린트 목표였는데, 각자 현재 맡은 바를 먼저 끝낸 팀원이 회원탈퇴 기능 구현을 시도하고 수요일(11일)자정까지 구현한 기능만 소개하기로 했다. </p>
<p>미팅 후 간단히 저녁을 먹고 본격적으로 바빠지기 시작했다. conflict를 해결하는 것이 1차 과제였고, SignUp에서 만든 컴포넌트를 활용해 SignIn페이지를 리팩토링 하는 것이 내 2차 과제였다. </p>
<ul>
<li>conflict 해결하기</li>
</ul>
<p>처음에는 master(main)에서 pull을 하지 않고, 브랜치에서만 conflict를 수정했다. 그랬더니  push하더라도 conflict가 제대로 해결되지 않아 merge를 할 수가 없었다.</p>
<p><img src="https://images.velog.io/images/taekjun_s/post/7dd9297e-c2f7-4b2d-9637-d38766159cda/image.png" alt=""></p>
<blockquote>
<p>conflict를 해결하기 위해서는 아래와 같은 절차를 거쳐야했다.</p>
</blockquote>
<p><code>1) git switch master</code>
:: master(main)으로 이동
<code>2) git pull origin master</code>
:: local master에 github master를 내려받기
<code>3) git switch 브랜치명</code>
:: 브랜치로 이동
<code>4) git merge master</code>
:: 브랜치와 master(main) 병합
<code>5) conflict 발생</code>
<code>6) conflict 수정</code></p>
<blockquote>
<p>github master의 내용을 local master와 브랜치에 업데이트하는 과정이 끝났다.</p>
</blockquote>
<p><code>7) git add .</code>
<code>8) git commit</code>
<code>9) git push origin 브랜치명</code></p>
<blockquote>
<p>conflict 해결</p>
</blockquote>
<p>저게 해결되면 merge가 가능하다는 이미지를 볼 수 있다. 만약 merge를 막아놓은 경우 아래와 같은 이미지를 확인할 수 있다.</p>
<p><img src="https://images.velog.io/images/taekjun_s/post/46d276ef-3d30-41ad-a005-35124c73191a/image.png" alt=""></p>
<p>끝❗️</p>
]]></description>
        </item>
    </channel>
</rss>