<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>{ dev : Dong }</title>
        <link>https://velog.io/</link>
        <description>일상의 성실이 자존감을 만드는 성취주의자</description>
        <lastBuildDate>Mon, 04 Oct 2021 07:38:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>{ dev : Dong }</title>
            <url>https://images.velog.io/images/dev_bomdong/profile/9a4ae7eb-fd63-42a6-b463-5177ec36f593/ae61c4371df42b13541c045a814673ab.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. { dev : Dong }. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev_bomdong" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[React | Portal을 이용한 Modal 구현]]></title>
            <link>https://velog.io/@dev_bomdong/React-Portal%EB%A1%9C-Modal%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@dev_bomdong/React-Portal%EB%A1%9C-Modal%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Mon, 04 Oct 2021 07:38:16 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/dev_bomdong/post/9d23fdaa-cd70-416a-91c4-5af858df6ff3/%EC%8D%B8%EB%84%A4%EC%9D%BC.PNG" alt=""> 한국인에게 portal이란.. 닥터스트레인지의 마법진같은 포탈만 떠오를 수 있다.
이미 충분히 익숙한 <strong>다른 곳으로 이동시킨다</strong>는 개념을 이어받아, 컴포넌트를 <strong>부모 컴포넌트의 바깥에 렌더링</strong>해주는 신기한 portal을 알아보자.</p>
<br>

<h1 id="🌀-portal이란">🌀 Portal이란?</h1>
<p>React 공식 문서에 따르면, Portal은 <strong>부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링</strong>하는 최고의 방법이다. </p>
<p>위 설명이 쉽게 이해가지 않는다면, 아래를 보면 된다. 
현재 <code>&lt;div id=&quot;root&quot;&gt;</code>와 <code>&lt;div id=&quot;modal&quot;&gt;</code> 은 형제 관계처럼 보이지만 실제로 <code>modal</code>은 <code>root</code> 안에서 보여지는 자식 컴포넌트아고, 렌더링만 <code>root</code>의 바깥에서 이루어지고 있다.
<img src="https://images.velog.io/images/dev_bomdong/post/3744fcb5-573d-4a1c-ae59-062f2c722e0e/image.png" alt=""></p>
<br>

<h2 id="왜-사용할까">왜 사용할까?</h2>
<p>일반적으로 react는 부모 컴포넌트가 렌더링되면 자식 컴포넌트가 렌더링되는 tree 구조를 가지고 있다. 하지만 때때로 이런 tree구조가 불편함을 가져다주기도 한다. 분명 부모-자식 관계를 가지고 있지만 독립적인 위치에서 렌더링을 하면 훨씬 편리한 경우가 있다. </p>
<p>대표적인 예로 modal은 부모 컴포넌트의 스타일링 속성에 제약을 받아 z-index 등으로 번거로운 후처리를 해줘야한다. 이러한 상황에서 portal을 통해 독립적인 구조와 부모-자식 관계를 동시에 유지할 수 있다면, z-index 등 부모 컴포넌트의 제약에서 벗어날 수 있다.  </p>
<br>

<h1 id="🌀-구현-방법">🌀 구현 방법</h1>
<blockquote>
<p>portal을 통해 modal을 구현하는 방법을 알아보자.
불필요한 코드는 생략하며 정리해두었다. </p>
</blockquote>
<h2 id="01--publicindexhtml에-modal이-렌더링-될-위치-심어주기">01 : public/index.html에 Modal이 렌더링 될 위치 심어주기</h2>
<pre><code class="language-html">  &lt;body&gt;
    &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;div id=&quot;modal&quot;&gt;&lt;/div&gt;
  &lt;/body&gt;</code></pre>
<p>portal을 구현할 tree의 부모 컴포넌트를 어디로 설정할지 정하는 것. 
위 코드에선 기존 최상단 요소인 <code>root</code>의 형제관계로 <code>modal</code> 요소를 넣었다.
이 요소에서 modal 컴포넌트가 렌더링되도록 만들 예정!</p>
<br>

<h2 id="02--portaljs-만들기">02 : Portal.js 만들기</h2>
<pre><code class="language-javascript">//Portal.js

import reactDom from &quot;react-dom&quot;;

const ModalPortal = ({ children }) =&gt; {
  const el = document.getElementById(&quot;modal&quot;);
  return reactDom.createPortal(children, el);
};

export default ModalPortal;</code></pre>
<p><code>modal div</code>를 가져와 children으로 넣어주는, Portal역할을 할 <code>Portal.js</code>를 만들어준다. </p>
<br>

<h2 id="03--modaljs-만들기">03 : Modal.js 만들기</h2>
<pre><code class="language-javascript">//Modal.js

import React from &quot;react&quot;;
import ModalPortal from &quot;./Portal&quot;;
import styled from &quot;styled-components&quot;;

const Modal = ({ onClose}) =&gt; {

  return (
    &lt;ModalPortal&gt;
      &lt;Background&gt;
        &lt;Content&gt;
  //  ... modal 안의 contents 코드 ...
         &lt;/ Content&gt;
      &lt;/Background&gt;
    &lt;/ModalPortal&gt;
  );
};

export default Modal;

//아래는 styled-components를 통한 스타일링

const Background = styled.div`
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  left: 0;
  top: 0;
  text-align: center;
`;

const Content = styled.div`
  height: 100%;
  width: 950px;
  margin-top: 70px;
  position: relative;
  overflow: scroll;
  background: #141414;
`;</code></pre>
<p>렌더링시켜줄 <code>modal.js</code> 를 만들어준다.
이 때 <code>&lt;Background&gt;</code>는 실제 modal의 뒷배경 부분이라고 생각하면 되고, 
실제 우리가 생각하는 튀어나오는 modal은 <code>&lt;Content&gt;</code> 라고 생각하면 된다. </p>
<br>

<h2 id="04--modal을-띄울-컴포넌트에-portal-modal-조건부-렌더링">04 : Modal을 띄울 컴포넌트에 Portal, Modal 조건부 렌더링</h2>
<pre><code class="language-javascript">//modal을 띄우려는 컴포넌트 파일

import styled from &quot;styled-components&quot;;
import ModalPortal from &quot;../Components/Modal/Portal&quot;;
import Modal from &quot;./Modal/Modal&quot;;

const Carousel = props =&gt; {
  const [modalOn, setModalOn] = useState(false);

  const handleModal = () =&gt; {
    setModalOn(!modalOn);
  };

  return (
    &lt;&gt;
      &lt;Container&gt;
        &lt;button onClick={handleModal}/&gt;
// ... 코드 생략 ...
        &lt;ModalPortal&gt;
          {modalOn &amp;&amp; &lt;Modal onClose={handleModal} /&gt;}
        &lt;/ModalPortal&gt;
      &lt;/Container&gt;
    &lt;/&gt;
  );
};

export default Carousel;</code></pre>
<p>modal을 렌더링하고자 하는 컴포넌트 파일에서 Portal에 감싸진 형태로 modal을 넣어준다!</p>
<p>물론 계속 떠있으면 그건 진정한 modal이 아니기에 <code>modalOn</code>이라는 state를 만들어주고 (기본값 : false), 이 state가 true일 때 modal이 렌더링되도록 조건을 걸어준다. 
modalOn을 변경해주는 함수 <code>handleModal</code>을 만들고, button에 onClick함수로 걸어주면 button이 클릭될 때마다 modal이 뿅하고 나타나게 된다.</p>
<br>

<h1 id="🌀-적용-예시">🌀 적용 예시</h1>
<p>위의 흐름을 적용해 실제 project에서 구현한 modal은 아래와 같다.
<img src="https://images.velog.io/images/dev_bomdong/post/1094f304-f339-4c10-a610-01949be31985/%EB%AA%A8%EB%8B%AC%EB%AA%A8%EB%8B%AC.gif" alt=""></p>
<br>

<blockquote>
<p><strong>📌 참고 학습 자료</strong>
<a href="https://ko.reactjs.org/docs/portals.html">React 공식 문서 - Portals</a>
<a href="https://blog.bitsrc.io/understanding-react-portals-ab79827732c7">Understanding React Portals and Its Use-Cases - blog.bitsrc.io</a>
<a href="https://yunsuu.github.io/portal/">Portal - yunsuu.github.io</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[넷플릭스 클론코딩 프로젝트 - 회고록]]></title>
            <link>https://velog.io/@dev_bomdong/%EB%84%B7%ED%94%8C%EB%A6%AD%EC%8A%A4-%ED%81%B4%EB%A1%A0%EC%BD%94%EB%94%A9-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@dev_bomdong/%EB%84%B7%ED%94%8C%EB%A6%AD%EC%8A%A4-%ED%81%B4%EB%A1%A0%EC%BD%94%EB%94%A9-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Sun, 03 Oct 2021 09:29:27 GMT</pubDate>
            <description><![CDATA[<h1 id="🎬-project-overview">🎬 Project Overview</h1>
<p>OTT(Over The Top) 서비스 제공 사이트 NETFLIX 클론 프로젝트</p>
<blockquote>
<p> 이 프로젝트는 NETFLIX 사이트를 참조하여 학습목적으로 만들었습니다
✔ <a href="https://www.youtube.com/watch?v=cxjxLiupVy4">결과물 시연 영상</a> 
 ✔ <a href="https://github.com/dev-bomdong/24-2nd-FX-frontend">Front-End Team GitHub</a>
 ✔  <a href="https://github.com/wecode-bootcamp-korea/24-2nd-FX-backend">Back-End Team GitHub</a></p>
</blockquote>
<h2 id="🔨-작업-기간">🔨 작업 기간</h2>
<p>2021.09.13 - 2021.10.01</p>
<h2 id="🔨-인원">🔨 인원</h2>
<p>총 5명 :  Front-End : 3명 | Back-End : 2명</p>
<h2 id="🔨-기술-스택">🔨 기술 스택</h2>
<h3 id="개발-도구">개발 도구</h3>
<p><strong>⚙ Front-End</strong>
HTML/CSS | JavaScript | React.js | styled-components</p>
<p><strong>⚙ Back-End</strong>
Python | Django | MySQL | Aquery</p>
<h3 id="협업-도구">협업 도구</h3>
<p>Trello | Git &amp; Github | Slack | Zoom | POSTMAN</p>
<h2 id="🔨-결과화면-및-주요-구현사항">🔨 결과화면 및 주요 구현사항</h2>
<p>팀원들과 페이지 및 컴포넌트별로 역할을 분담해 기능을 구현했고, 내가 담당한 기능은 ✅ 표시를 해두었다.</p>
<h3 id="회원가입-페이지">회원가입 페이지</h3>
<p>✔ 유효성 검사를 통한 회원가입
<img src="https://images.velog.io/images/dev_bomdong/post/3b652dfc-5a3f-4713-a78c-ac486e85a965/%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85.gif" alt=""></p>
<br>

<h3 id="로그인-페이지">로그인 페이지</h3>
<p>✔ 유효성 검사를 통한 로그인
✔ kakao, google 소셜로그인
<img src="https://images.velog.io/images/dev_bomdong/post/e5043792-b073-4410-8c06-bffb10afbc27/%EB%A1%9C%EA%B7%B8%EC%9D%B8.gif" alt=""></p>
<br>

<h3 id="메인-페이지">메인 페이지</h3>
<p>✔ 메인페이지 및 modal창 내 비디오 스트리밍 구현
(각 영상 컨텐츠에 맞는 비디오 스트리밍)
<img src="https://images.velog.io/images/dev_bomdong/post/7e240f86-dce4-4cec-87bf-8ab770f57282/%EB%A9%94%EC%9D%B8%20%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D.gif" alt=""><img src="https://images.velog.io/images/dev_bomdong/post/72dca8b7-e412-4a38-92c6-211d09e32797/%EB%AA%A8%EB%8B%AC%20%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D.gif" alt=""></p>
<br>

<p>✅ 들어오는 데이터 양에 따라 이동거리가 달라지는 캐러샐 슬라이드
<img src="https://images.velog.io/images/dev_bomdong/post/87044207-4a75-400a-bc6f-d00b21b4a1ba/%EC%BA%90%EB%9F%AC%EC%83%90%20%EC%B5%9C%EC%A2%85.gif" alt=""></p>
<br>

<p>✅ Portal을 통한 modal창
<img src="https://images.velog.io/images/dev_bomdong/post/1094f304-f339-4c10-a610-01949be31985/%EB%AA%A8%EB%8B%AC%EB%AA%A8%EB%8B%AC.gif" alt=""></p>
<br>

<p>✅ (다른 팀원분과 공동진행) 페이지 - carousel card - modal 간 동적 routing 연결</p>
<br>

<h3 id="찜하기">찜하기</h3>
<p>✔ 하트 버튼 클릭을 통한 찜하기 및 찜한 리스트 보여주기
<img src="https://images.velog.io/images/dev_bomdong/post/59f34aea-aea4-45d3-ad76-bfa31aa974e9/%EC%9C%84%EC%8B%9C%EB%A6%AC%EC%8A%A4%ED%8A%B8.gif" alt=""></p>
<h1 id="🎬-project-review">🎬 Project review</h1>
<h2 id="📄-칭찬해주고-싶은-점">📄 칭찬해주고 싶은 점</h2>
<h3 id="새로운-기술을-소화하며-적용해본-경험">새로운 기술을 소화하며 적용해본 경험</h3>
<p>메인 기술 스택으로 처음 접해보는 react Hook, styled-component를 바로 학습하고 적용하며 프로젝트를 진행해야했다. 처음엔 생각보다 이해가 더뎌 마음 고생을 했는데, 그 속상함을 풀 수 있는 방법은 결국 묵묵히 공식 문서를 읽고 구글링을 하고 코드를 쳐보는 것뿐이였다.</p>
<p>현업에 나가서도 새로운 기술을 바로 적용해야 할 일이 많을 테니 좋은 연습을 했다고 생각한다. 메인 기술 뿐만 아니라 기능을 구현하면서 Portal 등의 개념도 새로 접하고 당일에 바로 적용해내기도 했다. 이러한 일련의 과정에서 &#39;내 생각보다 빠르지 못한 나&#39;를 인정하는 태도, 압박감을 견뎌내며 묵묵히 밀고나가는 단단함까지 얻었다.</p>
<br>

<h3 id="단순한-클론이-아닌-문제-인식-후-코드로-해결해본-경험">단순한 클론이 아닌, 문제 인식 후 코드로 해결해본 경험</h3>
<p><a href="https://velog.io/@dev_bomdong/%EC%88%A0%EB%8B%B4%ED%99%94-%ED%81%B4%EB%A1%A0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0">1차 프로젝트</a>와 마찬가지로 본격적인 프로젝트를 시작하기 전, 팀원들과 사이트를 살펴보며 이미 훌륭한 사이트지만 <strong>우리가 좀 더 개선해볼 점은 없을까</strong> 고민했다.  </p>
<p>그렇게 우리가 찾아낸 문제 사항과 나름의 해결방안은 아래와 같았고, 일정이 허락하는 선에서 메인페이지 슬라이드를 제외한 앞 두 가지 개선사항을 구현했다.</p>
<p><strong>✅ 소셜로그인</strong></p>
<ul>
<li>문제사항 : 페이스북 소셜로그인 기능만 지원한다.  </li>
<li>해결방안 : MAU(Monthly Activity User/월간 활성 자)가 더 높은 카카오, 구글로 변경하자.</li>
</ul>
<p><strong>✅ 메인페이지 접근</strong></p>
<ul>
<li>문제사항 : 로그인을 해야만 메인페이지 접근이 가능하다. </li>
<li>해결방안 : 슬라이드를 트렌드(=지금 뜨는 컨텐츠), 장르별로 직관화, 간소화하자. </li>
</ul>
<p><strong>✔ 메인페이지 슬라이드</strong></p>
<ul>
<li>문제사항 : 슬라이드가 지나치게 많고 덜 정리된 느낌이 있어 접근성이 떨어질 수 있다. </li>
<li>해결방안 : 로그인을 하지 않더라도 메인페이지 접근까지는 가능하게 하고, 대신 비디오 스트리밍이 가능한 모달창 접근을 막자. (슬라이드에서 각각의 컨텐츠에 마우스를 대면 자물쇠 모양이 나타나도록 기능 구현)</li>
</ul>
<br>

<h3 id="수박겉핥기-식의-기능-구현이-아닌-숙지하며-구현한-경험">수박겉핥기 식의 기능 구현이 아닌, 숙지하며 구현한 경험</h3>
<p>사실 넷플릭스는 레이아웃이 다양하고 화려한 사이트는 아니다. 캐러샐 슬라이드 컴포넌트만 완성되어도 이를 재사용해 메인 페이지의 절반이 완성되는, 단순해보이기 그지없는 사이트였다. 
다만 이건 그 안에 녹아있는 비디오 스트리밍, 캐러샐, 모달 등의 기능을 포기했을 때의 이야기이고, 이들을 구현해내려면 한없이 어려워졌다.</p>
<p>팀원들간 회의를 할 때 어떻게든 자신이 담당한 기능을 우선 구현하는 것보다 남에게 설명할 수 있을 정도로 숙지하는 걸 목표로 했고,<br>나를 포함한 모든 팀원들이 한 가지 기능을 구현하기 위해 짧게는 하루, 길게는 며칠간 새벽을 지새우며 고민하고 또 고민했다. </p>
<p>Portal을 통한 modal 구현을 하루만에 적용하기위해 눈물훔치며 밤새 공부하던 순간,</p>
<p><img src="https://images.velog.io/images/dev_bomdong/post/c2ab5afb-e8a8-4f3e-a113-a27264f29174/KakaoTalk_20211003_165903394_03.jpg" alt=""><img src="https://images.velog.io/images/dev_bomdong/post/390be4c2-c558-437e-a487-c8b5435e6775/KakaoTalk_20211003_165903394_01.jpg" alt="">데이터 양에 따라 이동거리가 달라지는 캐러샐 슬라이드를 구현하기 위해 집에서 한땀한땀 그려나가던 순간을 잊지못한다. </p>
<p>진득하니 앉아서 기능을 고민할 수 있는 경험은 학습 단계에서 얻을 수 있는 귀하고 소중한 경험으로 남았다.</p>
<br>

<h2 id="📄-개선하고-싶은-점">📄 개선하고 싶은 점</h2>
<h3 id="추가-학습이-필요한-동적라우팅">추가 학습이 필요한 동적라우팅</h3>
<p>React class를 사용한 1차 프로젝트 진행시 동적 라우팅 관련으로 다른 팀에 도움을 주기도 해서 꽤 이해하고 있다고 생각했는데, 이번 프로젝트를 진행하면서 라우팅이 정말 어려웠고 또 오래걸렸다. 다행히 다른 팀원과 협업해 결과물을 완성했지만 코드를 뜯어보며 좀 더 공부해볼 예정이다. </p>
<h3 id="추가-기능구현의-아쉬움">추가 기능구현의 아쉬움</h3>
<p>새로운 기술을 사용하느라 바쁘다는 핑계로 필수 구현사항 외의 추가 구현사항을 수행할 여유가 부족했다. 예를 들어 modal을 종료할 때 x버튼 외에도 modal 바깥쪽을 클릭하면 종료되도록 만든다던지, 캐러샐 슬라이드를 무한 캐러샐로 만든다던지.. 추후 리팩토링을 진행할 때 함께 도전해보고 싶다. </p>
<br>

<h2 id="📄-팀-프로젝트-느낀점">📄 &#39;팀&#39; 프로젝트 느낀점</h2>
<p>연이은 프로젝트로 땅끝까지 떨어진 체력과 강도높은 일정으로 모두가 예민해지기 쉬운 환경에서 시작했던 프로젝트였다. 그럼에도 따뜻하고 유쾌한, 최고의 분위기에서 프로젝트를 수행할 수 있었다. (프로젝트 발표 진행을 맡아주신 멘토분으로부터 다른 분들께 우리팀의 분위기를 본받아서 3차 프로젝트를 진행하길 바란다는 감사한 말씀도 들었다.)</p>
<p>프로젝트 초반 새로운 기술을 소화해나가며 스트레스 받을 때 따뜻하게 격려해준 팀원들은 동기부여의 큰 축이 되었다. 앞으로 시작될 한 달간의 인턴쉽에서 팀장을 맡게 되었는데, 다른 팀원들에게 내가 느낀 것처럼 <em><strong>따뜻한 방식으로 동기부여를 줄 수 있는 팀원</strong></em> 이 되고싶다. </p>
<p>front-end 팀원들이 mock data를 만들지 않도록 하자는 목표를 세워 빠른 진행을 해주시고, 결국 mock data를 만드느라 시간소비하지 않게 해주신 back-end 팀원분들께 깊은 감사를 전한다. (하도 여기저기 자랑하고 다녀서 귀가 간지러우실 수도 있다.) 나도 front의 입장만 고려하는게 아니라, <em><strong>back-end의 편리를 함께 고려하며 작업하는 사람이 되자</strong></em> 는 깊은 깨달음을 얻었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS | revert, unset]]></title>
            <link>https://velog.io/@dev_bomdong/CSS-%EC%86%8D%EC%84%B1%EC%9D%84-%EB%90%98%EB%8F%8C%EB%A6%B4-%EB%95%90-revert-unset</link>
            <guid>https://velog.io/@dev_bomdong/CSS-%EC%86%8D%EC%84%B1%EC%9D%84-%EB%90%98%EB%8F%8C%EB%A6%B4-%EB%95%90-revert-unset</guid>
            <pubDate>Thu, 30 Sep 2021 04:36:48 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>react와 styled-component를 사용하여 프로젝트를 진행할 때 코드를 줄이기 위해 
기본적인 <code>text</code>속성을 정의해두고 <code>H1, H2</code> 등 다른 속성에 상속시켜 사용했다.
그러다보니 몇 가지 속성은 기본적인 <code>text</code>속성과 font-weight 등 한 두가지가 달랐는데, 이를 효과적으로 처리할 수 있는 revert를 알게되어 정리해본다. </p>
</blockquote>
<h1 id="revert란">revert란?</h1>
<p><code>revert</code> 는 현재 엘리먼트에 선언 된 css 속성을 부모 속성 또는 user agent에 따라 default로 선언 된 속성으로 <strong>되돌리는 것</strong>이다.
revert 속성은 각각의 경우의 수에 따라 아래와 같이 적용된다. </p>
<p><strong>1. 사이트의 기본적인 css 속성이 지정되어있는 경우</strong>
: 유저가 지정한 커스텀 스타일로 돌아간다.</p>
<p><strong>2. 사이트의 css속성이 하나만 존재하는 경우</strong>
: user agent의 default 스타일로 돌아간다.</p>
<p>*<em>3. 사용자의 커스텀 스타일을 사용하거나 사용자에 의해서 스타일이 적용되어 있는 경우 *</em>
: user agent의 default 스타일로 돌아간다.</p>
<p><strong>4. user agent default 스타일만 지정되어있는 경우</strong>
: <code>unset</code>과 동일하게 적용된다. (<code>unset</code>의 정의는 하단에 별도 정리)</p>
<h2 id="예제">예제</h2>
<p>스타일 속성에 관한 것이니 눈으로 직접 보는게 빠르다. </p>
<p><strong>HTML</strong> </p>
<pre><code class="language-html">&lt;section&gt;
  &lt;h3&gt;따로 지정되지 않은 h3는 연두색&lt;/h3&gt;
  &lt;p&gt;paragraph의 텍스트는 분홍&lt;/p&gt;
  섹션 안의 요소니까 연두색
&lt;/section&gt;

&lt;section class=&quot;with-revert&quot;&gt;
  &lt;h3&gt;revert로 따로 지정되어있지 않았던 h3는 검정&lt;/h3&gt;
  &lt;p&gt;특성화되어있는 paragraph는 그대로 분홍&lt;/p&gt;
  섹션 안의 요소가 revert 되면서 검정
&lt;/section&gt;</code></pre>
<p><strong>CSS</strong></p>
<pre><code class="language-css">section { color: darkseagreen }
p { color: lightcoral }
section.with-revert { color: revert }</code></pre>
<p>특정한 속성을 가진 부모 요소 <code>section</code>과 revert속성을 가진 부모 요소 <code>section.with-revert</code>에 각각 <code>h3</code>, <code>p</code>, 태그없는 일반 text를 입력해보았다. </p>
<br>

<p><strong>결과화면</strong>
<img src="https://images.velog.io/images/dev_bomdong/post/c04d178c-3ee1-4269-9775-327f7272a209/image.png" alt=""></p>
<p>*<em>부모 요소에 특정 속성이 정의되어 있을 경우 *</em></p>
<ul>
<li><code>&lt;h3&gt;</code> : 부모 요소의 속성을 상속해 연두색이다. </li>
<li><code>&lt;p&gt;</code> : 속성이 특성화 되어있기 때문에 부모 요소의 영향을 받지않고 본연의 색인 분홍색이다.</li>
<li>특정 태그가 없는 text : 부모 요소의 속성을 상속해 연두색이다. </li>
</ul>
<p>*<em>부모 요소에 revert 속성이 정의되어 있을 경우 *</em></p>
<ul>
<li><code>&lt;h3&gt;</code> : revert 부모 요소의 영향을 받아 user agent의 default 스타일인 검정색이다.</li>
<li><code>&lt;p&gt;</code> : 속성이 특성화 되어있기 때문에 부모 요소의 영향을 받지않고 본연의 색인 분홍색이다.</li>
<li>특정 태그가 없는 text : revert 부모 요소의 영향을 받아 user agent의 default 스타일인 검정색이다.</li>
</ul>
<br>

<h1 id="revert-vs-unset">revert vs unset</h1>
<p><code>revert</code> 속성은 <code>unset</code> 과 유사한 성질을 가지지만, 중요한 차이점을 가지고있다. <code>unset</code> 속성이 무엇인지와 둘은 어떤 차이점을 가지고 있는지를 알아보자.</p>
<h2 id="unset">unset</h2>
<p>부모 요소로부터 상속할 값이 존재하면 상속값을 적용 (inherit)
부모 요소로부터 상속할 값이 존재하지 않는다면 초기 값을 적용 (initial) 하는 속성</p>
<h2 id="revert와-unset의-차이">revert와 unset의 차이</h2>
<p>두 속성의 차이는 <strong>user agent에 의한 스타일</strong>로 돌아가느냐 혹은 <strong>유저가 지정한 스타일</strong>로 돌아가느냐의 차이이다.</p>
<h3 id="예제-1">예제</h3>
<p><strong>HTML</strong></p>
<pre><code class="language-html">&lt;p&gt;[ unset ]&lt;/p&gt;
&lt;h3 style=&quot;font-weight: unset; color: unset;&quot;&gt;This will still have font-weight: normal, but color: black&lt;/h3&gt;
&lt;p&gt;[ revert ]&lt;/p&gt;
&lt;h3 style=&quot;font-weight: revert; color: revert;&quot;&gt;This should have its original font-weight (bold) and color: black&lt;/h3&gt;</code></pre>
<p><strong>CSS</strong></p>
<pre><code class="language-css">h3 {
  font-weight: normal;
  color: blue;
}</code></pre>
<p><code>h3</code> 에 font-weight 속성을 normal로 적용해두고, 
<code>unset</code> 속성의 h3과 <code>revert</code> 속성의 h3을 입력해보았다.</p>
<br>

<p><strong>결과 화면</strong>
<img src="https://images.velog.io/images/dev_bomdong/post/b012224f-75d3-4b27-8474-520b594746eb/image.png" alt=""></p>
<ul>
<li><strong>unset</strong> 속성의 h3은 default로 설정된 <code>font-weight : normal</code>을 유지한다. </li>
<li><strong>revert</strong> 속성의 h3은 user-agent 설정값인 <code>font-weight : bold</code>로 돌아간다.</li>
</ul>
<br>

<blockquote>
<p><strong>📌 참고학습자료</strong>
<a href="https://developer.mozilla.org/ko/docs/Web/CSS/revert#revert_vs_unset">MDN - revert</a>
<a href="https://developer.mozilla.org/ko/docs/Web/CSS/unset">MDN - unset</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[React | Styled Components]]></title>
            <link>https://velog.io/@dev_bomdong/React-Styled-Components-icvgyedx</link>
            <guid>https://velog.io/@dev_bomdong/React-Styled-Components-icvgyedx</guid>
            <pubDate>Sun, 19 Sep 2021 06:48:21 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>React로 프로젝트를 진행하면서, CSS스타일링을 SASS에서 Styled Components로 변경해 진행하게 됐다. 처음엔 멘붕의 연속이였지만, 한 파일안에 스타일링까지 모두 관리할 수록 그 편리함에 빠져들고 있어 간단히 개념과 사용예시를 정리해본다.</p>
</blockquote>
<h1 id="💅-styled-components란">💅 Styled Components란?</h1>
<p>현대 웹 앱은 점차적으로 컴포넌트를 기반으로 고안되고 있고, 이에 따라 CSS 스타일링 또한 컴포넌트를 기반으로 재구성되고 있다. 이러한 흐름 속에서 등장한 패러다임이 <em><strong>CSS-in-JS</strong></em> (JS파일 안에서 CSS를 함께 관리하는 것)이고, 그 중 가장 인기 있는 라이브러리가 바로 Styled Components </p>
<h1 id="styled-components을-사용하는-이유">Styled Components을 사용하는 이유</h1>
<p><img src="https://images.velog.io/images/dev_bomdong/post/7e19851c-74cf-42fa-8760-f69b921d6da0/image.png" alt=""></p>
<ul>
<li>위와 같이 클래스명을 해시값으로 자동 생성하므로 클래스명 오염을 방지한다.</li>
<li>CSS 문법을 온전하게 사용할 수 있다.</li>
<li>자바스크립트의 동적인 값들을 온전하게 사용할 수 있다.</li>
<li>컴포넌트와 스타일이 하나의 파일로 결합되어 모듈화가 수월해진다.</li>
</ul>
<h1 id="사용-예시">사용 예시</h1>
<p>컴포넌트 파일의 상단에 아래와 같이 styled-components 라이브러리에서 import 해온 styled라는 객체를 사용하도록 코드를 작성한다. </p>
<pre><code class="language-javascript">import styled from &#39;styled-components&#39;</code></pre>
<br>

<p>컴포넌트가 export되는 부분 <strong>밑에</strong> 스타일링이 시작된다! 
아래 코드를 보면, <code>Arrow</code>라는 button태그의 styled-component를 만들었음을 알 수 있다.  </p>
<pre><code class="language-javascript">...코드 생략...
export default `컴포넌트명`;


const Arrow = styled.button`
  position: absolute;
  top: 100px;
  direction: ${props =&gt; props.direction};
  color: #e5e5e5;
  opacity: 0.5;
  font-size: 60px;
  cursor: pointer;
  z-index: 1;

  &amp;:hover {
    opacity: 1;
  }
`;</code></pre>
<p><code>상속될styled-component명.withComponent(태그명)</code>을 통해 스타일링 상속도 가능하다. 아래 코드를 보면 <code>LeftArrow</code>와 <code>RightArrow</code>라는 styled-component는 Arrow의 스타일링 속성을 상속받았음을 알 수 있다.  </p>
<pre><code class="language-javascript">const LeftArrow = styled(Arrow.withComponent(&quot;button&quot;))`
  left: 0px;
`;

const RightArrow = styled(Arrow.withComponent(&quot;button&quot;))`
  right: 0px;
`;</code></pre>
<blockquote>
<p>📌 <strong>참고 학습자료</strong>
<a href="https://styled-components.com/">styled-components 공식문서</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[TDD (Test Driven Development)]]></title>
            <link>https://velog.io/@dev_bomdong/TDD-Test-Driven-Development</link>
            <guid>https://velog.io/@dev_bomdong/TDD-Test-Driven-Development</guid>
            <pubDate>Sun, 19 Sep 2021 05:47:41 GMT</pubDate>
            <description><![CDATA[<h1 id="tdd란">TDD란?</h1>
<blockquote>
<p>_<strong>TDD(Test Driven Development)</strong>_는 <strong>테스트 주도 개발</strong>이라고도 불리며, 매우 짧은 개발 사이클을 반복하는 소프트웨어 개발 프로세스 중 하나이다. TDD를 적용해 개발을 진행할 경우, 우선 작은 단위의 테스트 케이스를 작성한 뒤 이를 통과하는 코드를 추가하는 과정을 반복하게 된다.
한 마디로, <strong>테스트 코드를 먼저 작성하고 이를 통과하기 위한 코드를 작성해나가는 개발 방식</strong> 이라고 할 수 있다.</p>
</blockquote>
<br>

<h1 id="일반-개발-방식-vs-tdd-개발-방식">일반 개발 방식 vs TDD 개발 방식</h1>
<h2 id="일반-개발-방식">일반 개발 방식</h2>
<p>일반적인 개발 방식은 <strong>요구사항 분석 &gt; 설계 &gt; 개발 &gt; 테스트 &gt; 배포</strong> 형태의 주기로 이루어진다. 
이러한 방식은 아래와 같이 몇 가지 위험요소를 가지고 있다. </p>
<ul>
<li><p>사용자의 요구사항이 명확하지 않거나 변경될 경우 재설계가 필요한데, 이러한 과정에서 불필요하거나 중복되는 코드가 남아 <strong>유지보수가 어려운 코드</strong>가 될 수 있다.</p>
</li>
<li><p>작은 단위의 기능 추가/수정에도 전체적인 테스트가 필요하므로 <strong>테스트 비용이 증가</strong>하고 버그 검출이 어려울 수 있다. </p>
</li>
</ul>
<h2 id="tdd-개발-방식">TDD 개발 방식</h2>
<p>TDD와 일반적인 개발 방식의 가장 큰 차이점은 테스트 코드를 작성한 뒤에 실제 코드를 작성한다는 점이다. TDD 개발 방식은 아래와 같이 Red &gt; Green &gt; Yellow 단계별 프로세스로 진행된다.</p>
<p><img src="https://images.velog.io/images/dev_bomdong/post/9acaea51-37c5-40b3-a1f5-5c1696305686/image.png" alt=""></p>
<p><strong>🔴 Red단계 : 테스트 실패</strong></p>
<ul>
<li>구체적인 하나의 요구사항을 검증하는 테스트 코드를 작성한다.</li>
<li>작성한 테스트가 실패하는지 확인한다. </li>
</ul>
<p><strong>🟢 Green단계 : 테스트 성공</strong></p>
<ul>
<li>테스트 성공을 위한 최소한의 실제 코드를 작성한다. </li>
</ul>
<p><strong>🟡 Yellow단계 : 리팩토링</strong></p>
<ul>
<li>효율적인 코드를 위한 리팩토링을 수행한다. </li>
</ul>
<br>


<h1 id="tdd의-장점">TDD의 장점</h1>
<h3 id="코드의-재사용성-증가">코드의 재사용성 증가</h3>
<p>버그와 같은 예외 사항은 Red 단계에서 우선적으로 고려되어 개선되는 방향으로 설계된다. 이후 테스트가 통과된 코드만 개발 단계에서 사용되므로, 불필요하거나 중복되는 코드가 정리된 <strong>재사용성이 높고 유지보수가 용이한 코드</strong>가 남는다.  </p>
<h3 id="재설계-시간의-단축">재설계 시간의 단축</h3>
<p>개발자는 Red단계에서 다양한 예외사항을 미리 고려해가며 테스트 코드를 작성한다. 이런 시간은 개발자가 실제 개발 단계에서 모든 개발 방향을 다시 재설계하게되는 가능성을 줄여준다.</p>
<h3 id="디버깅-시간의-단축">디버깅 시간의 단축</h3>
<p>TDD는 유닛테스팅을 통해 개발을 진행하므로 특정 버그가 어디의 문제에서 비롯된 것인지 쉽게 찾아낼 수 있다. TDD의 장점이라기보다는 유닛테스팅의 장점이라고도 볼 수 있다. </p>
<h3 id="추가-구현의-용이함">추가 구현의 용이함</h3>
<p>기존 코드에 새로운 기능을 추가하려 할 때 가장 우려되는 점은 추가하려는 기능이 기존 코드에 어떤 영향을 줄지 정확히 알지 못한다는 것. 하지만 TDD로 개발했을 경우 자동화된 유닛 테스팅을 전제하므로 테스트 기간을 획기적으로 단축시킬 수 있다.</p>
<br>


<h1 id="tdd의-단점">TDD의 단점</h1>
<p>앞서 여러가지 장점을 나열했지만 현업에서 TDD가 적용되어야 하는지에 대해서는 논란이 있고, 실제로 잘 사용되지 않는다. 그 치명적인 단점은 아래와 같다.</p>
<h3 id="생산성-저하">생산성 저하</h3>
<p>기존의 개발 프로세스에 테스트 케이스 설계까지 추가되어야 하니 코드 생산 비용이 높아진다는 의견이 많다. 기업별로 테스트를 어떻게 진행할 것이며, 각각의 프로젝트 성격에 따른 테스트 프레임워크 등 여러 부분을 고려해야 하는 것도 코드 생산성을 저하시키는 요인이 될 수 있다. </p>
<h3 id="개발-시간-증가">개발 시간 증가</h3>
<p>위 단점과 연결되는 이야기이지만, 많은 기업들은 전체적인 개발 시간을 줄이는 것보다는 단기적인 기간에 맞추어 성과를 내도록 개발을 진행하기 때문에 TDD 도입이 어렵다. </p>
<br>


<blockquote>
<p>📌 *<em>참고 학습자료 *</em>
<a href="https://ko.wikipedia.org/wiki/%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%A3%BC%EB%8F%84_%EA%B0%9C%EB%B0%9C">위키백과 - 테스트주도개발</a>
<a href="https://media.fastcampus.co.kr/knowledge/dev/tdd/">TDD란? 테스트주도개발에 대한 편견과 실상, 방법론</a>
<a href="https://gmlwjd9405.github.io/2018/06/03/agile-tdd.html">[Agile] TDD(테스트 주도 개발)란
</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[술담화 클론 프로젝트 - 기억에 남는 코드록]]></title>
            <link>https://velog.io/@dev_bomdong/%EC%88%A0%EB%8B%B4%ED%99%94-%ED%81%B4%EB%A1%A0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%EC%96%B5%EC%97%90-%EB%82%A8%EB%8A%94-%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@dev_bomdong/%EC%88%A0%EB%8B%B4%ED%99%94-%ED%81%B4%EB%A1%A0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%EC%96%B5%EC%97%90-%EB%82%A8%EB%8A%94-%EC%BD%94%EB%93%9C</guid>
            <pubDate>Sat, 18 Sep 2021 07:13:45 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>프로젝트가 끝난 후, 코드는 남지만 코드를 생각해내기까지의 고민과 과정은 쉽게 휘발된다. 이를 붙잡기위해 적어보는 <em><strong>기억에 남는 코드록</strong></em></p>
</blockquote>
<h1 id="🍶-fetch-함수-축약">🍶 fetch 함수 축약</h1>
<p>기본적으로 사용되는 fetch 함수 형태는 아래와 같다. 
하지만 위의 fetch함수가 여러 번 반복되어 사용된다면 가독성이 현저히 떨어진다. 
리팩토링의 중요한 원칙 중 하나 = <em><strong>반복되는 요소를 축약시키자</strong></em>
<img src="https://images.velog.io/images/dev_bomdong/post/b526ca2d-c91e-489a-9a4f-885af8e9ec86/image.png" alt=""></p>
<p>위 함수에서 각각의 색으로 테두리친 <span style="background-color:gold">fetch함수, 두 번의 then함수</span>와 <span style="background-color:lightblue">setState</span>부분을 아래와 같이 변수화해서 가독성은 챙기고, 코드의 길이는 줄일 수 있다.
<img src="https://images.velog.io/images/dev_bomdong/post/9ad9c44a-c82d-40b8-978d-466afbe20357/image.png" alt=""></p>
<h2 id="1-setstate-변수화">1. setState 변수화</h2>
<pre><code class="language-javascript">    const updateProducts = data =&gt; this.setState({ products: data.Result });
    const updateMain = data =&gt; this.setState({ main: data.Result });</code></pre>
<p><span style="background-color:lightblue">setState</span> 부분을 살펴보니 state 중 <code>products</code> 혹은 <code>main</code>을 변경하는 것으로 나뉘었다. 이 부분을 각각 변수 한 단어로 설정해 축약했다.</p>
<h2 id="2-fetchapi-setstate함수-변수화">2. fetch(API, setState함수) 변수화</h2>
<p>반복되는 함수가 있다 =&gt; <em><strong>함수의 틀을 만들고, 바꾸어서 재사용하자</strong></em>.
<code>fetch함수 및 두 번의 then 함수</code>를 하나의 함수로 만들었다. 
여기서 변경되는 부분은 API와 setState 부분이니 각각 (setState부분은 callback함수로) 인자로 설정했다. </p>
<pre><code class="language-javascript">handleFetch = (API, callback) =&gt; {
  fetch(API)
    .then(res =&gt; res.json())
    .then(data =&gt; {
      callback(data);
    });
};</code></pre>
<p>위 함수에서의 <code>callback(data)</code>는 변수화해두었던 setState인 <code>updateProducts</code>, <code>updateMain</code> 으로 대체할 수 있다. 
그럼 아래 처럼 정-말 많이 축약된 코드로 같은 기능을 구현할 수 있다! </p>
<pre><code class="language-javascript">//state의 products update
handleFetch(API, updateProducts);

//state의 main update
handleFetch(API, updateMain);</code></pre>
<p>실제로 카테고리 상품 리스트 페이지 내에서 총 3번의 fetch가 이루어져야 했는데, 변수화를 통해 가독성을 높힐 수 있었다. fetch함수는 앞으로 질리도록 쓰게 될테니 잘 기억해두고 두고두고 써먹어야지 <img src="https://images.velog.io/images/dev_bomdong/post/261ea9ca-3774-4452-b6a7-d55019b41071/image.png" alt=""></p>
<br>

<h1 id="🍶-쿼리스트링을-이용한-ordering">🍶 쿼리스트링을 이용한 ordering</h1>
<p><img src="https://images.velog.io/images/dev_bomdong/post/80aa2bc7-faff-4c90-a5c3-73dd8fd63efe/ordering.gif" alt=""></p>
<h2 id="1-각-버튼의-filter-속성에-ordering-기준-텍스트-입력">1. 각 버튼의 filter 속성에 ordering 기준 텍스트 입력</h2>
<pre><code class="language-javascript">const FILTER_BTN_DATA = [
  {
    id: 1,
    filter: &#39;name&#39;,
    text: &#39;이름순&#39;,
  },

  {
    id: 2,
    filter: &#39;updated_at&#39;,
    text: &#39;최신순&#39;,
  },
  {
    id: 3,
    filter: &#39;-grade&#39;,
    text: &#39;인기순&#39;,
  },
  {
    id: 4,
    filter: &#39;price&#39;,
    text: &#39;낮은 가격순&#39;,
  },
  {
    id: 5,
    filter: &#39;-price&#39;,
    text: &#39;높은 가격순&#39;,
  },
  {
    id: 6,
    filter: &#39;dgree&#39;,
    text: &#39;낮은 도수순&#39;,
  },
  {
    id: 7,
    filter: &#39;-dgree&#39;,
    text: &#39;높은 도수순&#39;,
  },
];</code></pre>
<p>위와 같이 상수 데이터에 map함수를 돌려 버튼 컴포넌트를 나타냈는데, 그 중 <code>filter</code> 속성에 쿼리스트링으로 보낼 값들을 적어주었다. (이 때 백엔드 측과 협의 필수) </p>
<h2 id="2-버튼-클릭시-state가-update되는-함수-구현">2. 버튼 클릭시 state가 update되는 함수 구현</h2>
<pre><code class="language-javascript">// 최상위 컴포넌트
// state 중 filter항목을 update하는 handleFilter 함수 구현
  handleFilter = e =&gt; {
    this.setState({
      filter: e,
    });
  };


// 버튼 컴포넌트
// onClick이벤트로 handleFilter 함수 호출.
// 이 때 인자는 이벤트 타겟의 id(=상수데이터에서 받아온 각각의 filter값)이다.
// 따라서 버튼 클릭시 해당 버튼의 filter 값으로 최상위 컴포넌트 state의 filter 값이 바뀌는 셈

    const { currentFilter, filter, handleFilter, text } = this.props;

    return (
      &lt;button
        className={`filter-btn ${
          currentFilter === filter ? &#39;yellow-btn&#39; : &#39;gray-btn&#39;
        }`}
        onClick={e =&gt; {
          handleFilter(e.currentTarget.id);
        }}
        id={filter}
      &gt;
        {text}
      &lt;/button&gt;
    )</code></pre>
<h2 id="3-쿼리스트링으로-ordering-요청">3. 쿼리스트링으로 ordering 요청</h2>
<p>state가 변경되니 componentDidUpdate를 통해 fetch를 해주어야 한다.
이전 filter와 현재 filter가 변경되었을 때를 비교하고, 
값이 서로 다를 경우 앞서 축약해주었던 형태로 fetch를 다시 해준다.</p>
<pre><code class="language-javascript">  componentDidUpdate(prevProps, prevState) {
    const updateProducts = data =&gt; this.setState({ products: data.Result });
    if (this.state.filter !== prevState.filter) {
      this.handleFetch(
        `${API}/products/list?limit=20&amp;order-by=${this.state.filter}&amp;category=${this.props.match.params.id}`,
        updateProducts
      );
    }
  }</code></pre>
<br>

<h1 id="🍶-쿼리스트링을-이용한-검색-기능">🍶 쿼리스트링을 이용한 검색 기능</h1>
<p>실제 사이트엔 없는 기능이지만, 팀원들과 상의한 후 새롭게 추가한 기능인 <strong>안주 검색 기능</strong>
프론트엔드 단에서 구현을 해야할지, 글씨를 입력할 때마다 바로바로 검색되게 해야할지.. 팀원들과 많은 고민을 한 끝에 가장 안정적으로 결과물이 나타난다고 생각되는 쿼리스트링을 통한 구현을 선택했다.  </p>
<p><img src="https://images.velog.io/images/dev_bomdong/post/fe43ceb8-03f5-4293-9924-7bc223d4dd30/%EA%B2%80%EC%83%89.gif" alt=""></p>
<h2 id="1-input값을-state에-저장">1. input값을 state에 저장</h2>
<p><strong>state update 함수 만들기</strong></p>
<pre><code class="language-javascript">  handleSideDishInput = e =&gt; {
    const { name, value } = e.target;
    this.setState({ [name]: value });
  };</code></pre>
<p>위와 같이 이벤트 타겟의 name : value 형태로 state를 update하는 함수를 만들고</p>
<br>

<p><strong>state update 함수를 input에 넘겨주기</strong></p>
<pre><code>        &lt;input
          className=&quot;filter-input&quot;
          placeholder=&quot;어떤 안주와 즐기고 싶으세요?&quot;
          name=&quot;sideDish&quot;
          onChange={this.props.handleSideDishInput}
        /&gt;</code></pre><p>이 함수를 input에 onChange 이벤트로 걸어준다. 
input의 name은 sideDish로 입력해두었다. 결과적으로 input에 입력하는 값은  <code>{sideDish(input의 name):input의 입력값}</code> 형태로 state에 저장된다. </p>
<br>

<h2 id="2-state값을-쿼리스트링으로-전달">2. state값을 쿼리스트링으로 전달</h2>
<p>이제 input의 입력값을 쿼리스트링 안에 넣어 서버로 보내주자! </p>
<p><strong>쿼리스트링으로 검색값을 넘겨주는 함수 만들기</strong></p>
<pre><code class="language-javascript">  handleSideDish = () =&gt; {
    this.handleFetch(
      `${API}/products/list?order-by=${this.state.filter}&amp;category=${this.props.match.params.id}&amp;side-dish=${this.state.sideDish}`,
      data =&gt;
        this.setState({
          products: data.Result,
        })
    );
  };</code></pre>
<p>위 코드에서 우리가 주목해야 할 부분은 <code>side-dish=${this.state.sideDish}</code>
handleSideDish 함수를 통해 우리는 fetch를 할 건데, 이 때 URL의 쿼리스트링에 state의 값을 넘겨준다.</p>
<br>

<p><strong>검색값을 넘겨주는 함수를 버튼에 넘겨주기</strong></p>
<p>검색 기능을 실행시킬 버튼을 클릭할 때마다 해당 함수가 호출되도록 onClick이벤트를 걸어주면 끝! </p>
<pre><code class="language-javascript">&lt;button
className=&quot;filter-side-dish-btn&quot;
onClick={this.props.handleSideDish}
&gt;
안주로 검색하기
&lt;/button&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[술담화 클론 프로젝트 - 회고록]]></title>
            <link>https://velog.io/@dev_bomdong/%EC%88%A0%EB%8B%B4%ED%99%94-%ED%81%B4%EB%A1%A0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@dev_bomdong/%EC%88%A0%EB%8B%B4%ED%99%94-%ED%81%B4%EB%A1%A0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 12 Sep 2021 13:28:27 GMT</pubDate>
            <description><![CDATA[<h1 id="🍶-project-overview">🍶 Project Overview</h1>
<p>국내 최초 전통주 정기 구독 서비스 쇼핑몰 <a href="https://www.sooldamhwa.com/damhwaMarket">술담화</a> 클론 프로젝트
<em>(* 담화마켓 (스토어) 서비스 위주로 진행)</em></p>
<blockquote>
<p> ✔ <a href="https://youtu.be/tThYy28aRaU">결과물 시연 영상</a> 
 ✔ <a href="https://github.com/dev-bomdong/24-1st-RS-frontend">Front-End Team GitHub</a>
 ✔  <a href="https://github.com/wecode-bootcamp-korea/24-1st-RS-backend">Back-End Team GitHub</a></p>
</blockquote>
<h2 id="작업-기간">작업 기간</h2>
<p>총 12일 : 21.08.30 (월) - 21.09.10 (금)</p>
<h2 id="인원">인원</h2>
<p>총 5명 :  Front-End : 3명 | Back-End : 2명</p>
<h2 id="기술-스택">기술 스택</h2>
<h3 id="개발-도구">개발 도구</h3>
<p><strong>⚙ Front-End</strong>
HTML/CSS | JavaScript | React.js | Sass</p>
<p><strong>⚙ Back-End</strong>
Django | MySQL | Aquery</p>
<h3 id="협업-도구">협업 도구</h3>
<p>Trello | Git | Slack | Zoom</p>
<h2 id="결과화면-및-주요-구현사항">결과화면 및 주요 구현사항</h2>
<p>팀원들과 페이지 별로 역할을 분담해 기능을 구현했고, 내가 담당한 페이지는 ✅ 표시를 해두었다.</p>
<p>☑ <strong>메인 페이지</strong>
<img src="https://images.velog.io/images/dev_bomdong/post/63d36515-52cf-4326-b353-f14b89dc4b75/main_final.gif" alt=""></p>
<ul>
<li>배너/제품별 슬라이더 기능 구현</li>
<li>타이머 기능 구현 (localstorage 저장)</li>
<li>카테고리별 리스트 페이지로 연결 구현</li>
</ul>
<br>

<p>✅ <strong>회원가입 페이지</strong>
<img src="https://images.velog.io/images/dev_bomdong/post/50099a12-4a48-4441-b387-b01f2a6a2101/signup_final.gif" alt=""></p>
<ul>
<li>validation에 따른 회원가입 기능 구현</li>
</ul>
<br>


<p>✅ <strong>로그인 페이지</strong>
<img src="https://images.velog.io/images/dev_bomdong/post/864a53c2-acee-437c-adea-16e499e0613f/signin_final.gif" alt=""></p>
<ul>
<li>JWT와 로컬스토리지를 사용한 로그인 기능 구현</li>
</ul>
<br>


<p>✅ <strong>카테고리별 리스트 페이지</strong>
<img src="https://images.velog.io/images/dev_bomdong/post/31a992d3-5910-4346-befa-72ed9d87d759/category1.gif" alt=""></p>
<ul>
<li>query string을 활용한 ordering 기능 구현 : 이름순, 최신순, 인기순, 낮은/높은 가격순, 낮은/높은 도수순</li>
<li>안주로 검색하기 기능 구현 <em>(기존 사이트에 없던 기능)</em></li>
<li>제품 hover시 새로운 데이터 보여주기 기능 구현 <em>(기존 사이트에 없던 기능)</em></li>
<li>query string url 을 사용한 상세페이지 연결 구현</li>
</ul>
<br>


<p>☑ <strong>상세페이지</strong>
<img src="https://images.velog.io/images/dev_bomdong/post/9a1d5a03-dc39-4c6d-8cbb-a30e7786a923/detail.gif" alt=""></p>
<ul>
<li>사용자에게 더 직관적으로 정보가 전달되게끔 레이아웃 변경</li>
<li>수량 변경 기능 구현</li>
<li>버튼 클릭을 통해 장바구니로 연결 구현</li>
</ul>
<br>


<p>☑ <strong>장바구니 (모달창)</strong>
<img src="https://images.velog.io/images/dev_bomdong/post/75f41262-c3e2-44fc-a949-4e393ed685c8/cart.gif" alt=""></p>
<ul>
<li>수량 변경에 따른 총 가격 계산 기능 구현</li>
<li>제품 삭제 기능 구현</li>
</ul>
<br>



<h1 id="🍶-project-review">🍶 Project Review</h1>
<br>

<h2 id="📍-칭찬해주고-싶은-점">📍 칭찬해주고 싶은 점</h2>
<h3 id="1-단순한-클론에서-나아가-기술적으로-문제-해결을-해보는-연습">1. 단순한 클론에서 나아가, 기술적으로 문제 해결을 해보는 연습</h3>
<p>우리 팀은 프로젝트 시작 전 사이트를 살펴보며 <em><strong>이미 사용자들에게 충분히 낯설 각각의 전통주 정보를 좀더 직관적이고 쉽게 보여줄 수는 없을까?</strong></em> 라는 생각을 했다. 함께 발견한 문제에 대해 팀 내 논의를 거쳐 나름의 해결 방안을 생각해냈고, 이를 결과물에 녹여내고자 노력했다. 개발자에게 가장 필요한 역량 중 하나가 문제 해결 역량인만큼, 문제를 발견해내 해결 방안을 기술적으로 녹여낸 경험은 팀원 모두에게 좋은 기억으로 남았다.</p>
<p>✅ <strong>우리 팀이 생각해낸 해결방안</strong>
: 사람들은 술을 고를 때 <strong>(1) 도수 (2) 함께 곁들일 안주</strong>를 중요시하므로, 각각의 상품에 대한 두 정보를 사용자에게 더 직관적으로 보여주자</p>
<br>

<p><img src="https://images.velog.io/images/dev_bomdong/post/35a10277-4ff3-4702-85b9-acbb1992c108/hover.gif" alt=""><strong>hover 시 도수/안주 나타내기</strong>
각 상품에 마우스를 올리면(hover) 각 상품의 데이터에서 (1) 도수 (2) 함께 곁들이면 좋은 안주 이미지/텍스트 를 받아와 보여지도록 했다.</p>
<br>

<p><img src="https://images.velog.io/images/dev_bomdong/post/397aaa8f-8468-40b8-9115-ef90fddaa3a4/%EA%B2%80%EC%83%89.gif" alt=""><strong>안주 검색기능</strong>
input에 입력된 값을 state에 저장하고, 그 값을 query string으로 서버에 보내 &#39;연어&#39;를 검색하면 &#39;연어초밥&#39; 등 관련된 값도 모두 나타나도록 백엔드 측과 협업하여 구현했다. </p>
<br>

<h3 id="2-프론트-백의-소통을-위한-노력">2. 프론트-백의 소통을 위한 노력</h3>
<p>처음으로 프론트 팀원들과 백엔드 팀원들이 한 팀이 되어 프로젝트를 진행한 만큼, 원활한 소통을 위해 모든 팀원들이 많은 노력을 기울였다. 모두가 마음을 쓴 만큼 유연하고 탄탄한 분위기 속에서 원할하게 프로젝트를 진행할 수 있었다.</p>
<h4 id="trello를-활용한-daily-meeting">Trello를 활용한 daily meeting</h4>
<p>우리 팀은 Trello를 활용해 일정 관리를 진행했는데, 나름의 rule을 세워 (Done으로 옮기는 기준을 미리 정하는게 정말 중요하다!) 이를 기반으로 서로의 진행상황을 더욱 정확하게 공유할 수 있었다.
<img src="https://images.velog.io/images/dev_bomdong/post/203d9da7-428b-4483-ac65-503b641a6ea9/image.png" alt=""></p>
<br>

<p>매일 오전 10시 스탠드업 미팅을 진행하며 <code>한일</code>, <code>할일</code>, <code>blocker</code> 위주로 진행상황을 공유했다. 미팅 시간 전까지 해당 사항을 미리 댓글로 작성해 누락되는 사항 없이 알찬 회의를 진행할 수 있었다. 아래 사진은 유달리 적을 것이 많았던 날의 agenda
<img src="https://images.velog.io/images/dev_bomdong/post/5ac836a7-c3d5-4ea4-b250-094ef7e86637/image.png" alt=""> </p>
<br>

<h4 id="api-document">API document</h4>
<p>이건 내가 잘한 일이 아니라, 우리 팀 백엔드 팀원분들을 칭찬해주고 싶은 요소!
내가 담당한 로그인/회원가입/카테고리 상품리스트 페이지는 로그인/회원가입을 구현할 때의 key값부터 수많은 쿼리스트링 규칙까지.. 프론트-백 간에 소통이 필요한 사항이 정말 많았지만 API document 덕분에 그런 문제에서 벗어날 수 있었다. 
각각의 상황에 맞는 API document가 있어 key값이나 데이터 형태를 미리 맞춰보며 프로젝트를 진행할 수 있었고, 시행착오 시간도 줄어들어 다른 곳에 시간을 투자할 수 있었다.</p>
<p><img src="https://images.velog.io/images/dev_bomdong/post/aa0fbe79-0931-4bd6-ba3c-e4bf43eec785/image.png" alt=""></p>
<br>



<h2 id="📍-개선하고-싶은-점">📍 개선하고 싶은 점</h2>
<h3 id="미진했던-코드-리팩토링">미진했던 코드 리팩토링</h3>
<p>애증의 그 이름 리팩토링.. 끝날 때 까지 끝난게 아니다 
중간중간 코드 리뷰를 받으며 리팩토링을 진행한 구간도 있지만, 반복되는 코드를 더 가독성있게 축약할 수 있는 부분이 아직 많이 남아있다. 
본 프로젝트는 팀원들과 한 달 정도 뒤 다시 리팩토링을 하기로 스케쥴이 잡혀있으므로, 그 때 더 가독성 있고 간결한 코드로 바꾸는 작업을 진행해 볼 예정이다. </p>
<h3 id="회원가입로그인-추가-기능-구현">회원가입/로그인 추가 기능 구현</h3>
<p>2주동안 (1)회원가입 (2)로그인 (3)카테고리별 리스트, 총 세 페이지의 레이아웃/기능 구현을 하는데에는 시간이 부족했다. 특히 카테고리별 리스트 페이지의 추가 구현 기능이 자꾸만 추가되어서 회원가입/로그인 페이지는 필수 기능만 alert메세지로만 구현하고 빠르게 지나갔다. validation 실패 시 input 아래에 경고 메세지가 표시되고 input 내의 아이콘을 넣어 색상도 함께 바꾸는 등 이런 저런 요소들을 더 추가해보고 싶다. </p>
<br>

<h2 id="📍-느낀-점">📍 느낀 점</h2>
<p>처음부터 끝까지 작은 트러블 하나 없이 부드럽고 유쾌한 팀 분위기 속에서 프로젝트를 진행할 수 있었던 건 큰 행운이라고 생각한다.  <em><strong>더 탄탄하고 원활한 협업을 위해 팀원들과 회의 방식을 고민하고, 에러를 해결하기 위해 5명 모두 옹기종기 모여서 의견을 나누던 순간</strong></em> 은 개인 프로젝트가 아닌 협업 프로젝트에서만 얻을 수 있는 소중한 기억으로 남았다. </p>
<p>프로젝트를 진행하며 수면 시간이 확 줄어들어 체력이 다소 약해지기는 했지만 혼자 공부할 때 보다 웹 개발에 대한 재미가 극대화되어 진로를 바꾸길 잘했다는 생각도 들었다.</p>
<p>사람은 자신이 성공을 이루었거나 행복을 느꼈던 패턴을 반복적으로 수행한다고 한다. 
잘 해낼 수 있을까 걱정하며 시작한 2주의 프로젝트
프로젝트 내내 느꼈던 기쁨과 성취감을 토대로 당장 내일부터 시작될 2차 프로젝트에도, 앞으로 개발자로서 수십,수백번 진행할 프로젝트에도 잘 해낼 수 있다 생각하며 풍덩 뛰어들 수 있는 확신이 생겼다. 😊   </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS | 쿼리스트링을 객체로 변환하기]]></title>
            <link>https://velog.io/@dev_bomdong/%EC%BF%BC%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%A7%81-%EA%B0%9D%EC%B2%B4%EB%A1%9C-%EB%B3%80%ED%99%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_bomdong/%EC%BF%BC%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%A7%81-%EA%B0%9D%EC%B2%B4%EB%A1%9C-%EB%B3%80%ED%99%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 12 Sep 2021 09:49:35 GMT</pubDate>
            <description><![CDATA[<h1 id="쿼리스트링이란">쿼리스트링이란?</h1>
<blockquote>
<p>쿼리 파라미터(Query Parameter)라고도 하며, 사용자가 URL 주소 뒤에 입력 데이터를 전달하는 방법 중 하나이다. 해당 웹 페이지의 엔드포인트에 대해 질의문(query)를 보내는 요청으로, 사용자가 특정한 값을 URL 주소로 쉽게 전달할 수 있다.<br>
예를 들어 <code>localhost:8000/product?limit=20&amp;order-by=grade</code>에서 <code>?limit=20&amp;order-by=grade</code>부분이 쿼리스트링이다. </p>
</blockquote>
<br> 

<h1 id="왜-쿼리스트링을-객체로-변환하는가">왜 쿼리스트링을 객체로 변환하는가?</h1>
<p>한 마디로 말하면, <em><strong>쉽게 수정하려고 !</strong></em></p>
<p>예를 들어 쿼리스트링이 아래와 같고 여러 번 반복되어 사용된다고 하자.
아래 쿼리스트링에서 category의 값 수정이 필요하다면, 긴 쿼리에서 category의 값 부분을 찾고 다른 값에 영향을 주지않게 한땀 한땀.. 번거로운 과정을 거쳐 수정해야 한다.</p>
<pre><code class="language-javascript">const query = &quot;order-by=${this.state.filter}&amp;category=${this.props.match.params.id}&amp;limit=20&quot;;</code></pre>
<p>하지만 위의 쿼리스트링을 아래와 같이 객체로 변환한다면?</p>
<pre><code class="language-javascript">const queryObj = {
&#39;order-by&#39;: &#39;${this.state.filter}&#39;,
category: &#39;${this.props.match.params.id}&#39;,
limit: &#39;20&#39;,
}</code></pre>
<p><code>queryObj.category = 수정값</code> 형태로 손쉽게 수정할 수 있다! </p>
<br>

<p>어떻게 쿼리스트링을 객체로 변환할 수 있는지, 또 객체로 변환해 수정한 다음 어떻게 합쳐 다시 사용할 수 있는지 차근차근 정리해보자.</p>
<br> 


<h1 id="첫-번째-방법--객체와-배열-속성-이용">첫 번째 방법 : 객체와 배열 속성 이용</h1>
<h2 id="1-문자열--객체-변환">1. 문자열 =&gt; 객체 변환</h2>
<pre><code class="language-javascript">const query = &quot;order-by=${this.state.filter}&amp;category=${this.props.match.params.id}&amp;limit=20&quot;;</code></pre>
<p>위 쿼리스트링을 객체로 변환하는 함수 <code>queryToObj()</code>를 구현해보자.</p>
<h3 id="step-1">Step. 1</h3>
<p><code>&amp;</code> 로 텍스트를 나눈 배열을 만들어준다.
큰 배열(list)안의 값은 아래와 같이 각각의 배열로 반환된다.</p>
<pre><code class="language-javascript">[order-by=${this.state.filter}],
[category=${this.props.match.params.id}],
[limit=20]</code></pre>
<h3 id="step-2">Step. 2</h3>
<p>이중 배열 안의 값을 map 함수를 통해 <code>=</code>로 나누고, 이후 작업을 위해 이 값을 <code>[key, val]</code> 라고 할당한다. 아래에서 key는 이중 배열 안의 전자 값, val은 이중 배열 안의 후자 값이라고 생각하면 된다. </p>
<pre><code class="language-javascript">[order-by, ${this.state.filter}], 
[category, ${this.props.match.params.id}],
[limit, 20]</code></pre>
<h3 id="step-3">Step. 3</h3>
<p>각각의 key, val 값을 <code>{property:key, value:val}</code> 값으로 반환해준다.
여기까지가 map함수 끝!</p>
<pre><code class="language-javascript">{property: order-by, value: ${this.state.filter}}, 
{property: category, value: ${this.props.match.params.id}}, 
{property: limit, value: 20}</code></pre>
<h3 id="step-4">Step. 4</h3>
<p>map함수의 결과값인 각각의 객체를 <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce">reduce(콜백함수,초기값)</a> 를 통해 하나의 결과값으로 축약해준다. 그러면 객체 형태로 변환된 값이 나온다.</p>
<pre><code class="language-javascript">{
&#39;order-by&#39;: &#39;${this.state.filter}&#39;,
category: &#39;${this.props.match.params.id}&#39;,
limit: &#39;20&#39;,
}</code></pre>
<p>위의 과정을 한 눈에 보기 위한 코드 전문은 아래와 같다. </p>
<pre><code class="language-javascript">const queryToObj = query =&gt; {

// 1. &quot;&amp;&quot; 로 텍스트를 나눈 배열을 만들어준다.
  const list = query.split(&quot;&amp;&quot;);

// 2. 배열 값을 map 함수를 통해 &quot;=&quot;로 다시 나눈 뒤 이걸 [key, val] 형태라 하자. 
// 3. 각각의 key, val 값을 {property:key, value:val} 값으로 반환해준다.
// 4. map함수의 결과값인 각각의 객체를 reduce를 통해 하나의 결과값으로 축약해준다. 

  const objQuery =  list.map(item =&gt; {
    const [key, val] = item.split(&quot;=&quot;)
    return {property:key, value: val}
  }).reduce(
    (acc,cur) =&gt; {acc[cur.property]=cur.value;
                 return acc;},{})

  return objQuery
};

//   반환값 = {
//  &#39;order-by&#39;: &#39;${this.state.filter}&#39;,
//  &#39;category&#39;: &#39;${this.props.match.params.id}&#39;,
//  &#39;limit&#39;: &#39;20&#39;,
//  }</code></pre>
<h2 id="2-객체--문자열-변환">2. 객체 =&gt; 문자열 변환</h2>
<p>쿼리스트링을 객체로 변환했다면, 다시 문자열로 합쳐주어야 사용할 수 있다. 
이 과정은 지금껏 해왔던 과정을 반대로 다시 해준다고 생각하면 쉽다.</p>
<h3 id="step-1-1">Step. 1</h3>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/entries">Object.entries()</a>를 통해 객체를 이중 배열의 형태로 만들어준다. </p>
<pre><code class="language-javascript">[ [&#39;order-by&#39;, &#39;${this.state.filter}&#39;],
[&#39;category&#39;, &#39;${this.props.match.params.id}&#39;],
[&#39;limit&#39;, &#39;20&#39;] ]</code></pre>
<h3 id="step-2-1">Step. 2</h3>
<p>map 함수를 통해 각각의 이중 배열 안의 배열 값을 <code>=</code>로 연결한 스트링으로 합쳐준다.</p>
<pre><code class="language-javascript">[ &#39;order-by=${this.state.filter}&#39;, &#39;category=${this.props.match.params.id}&#39;, &#39;limit=20&#39; ]</code></pre>
<h3 id="step-3-1">Step. 3</h3>
<p><code>join(&quot;&amp;&quot;)</code>으로 각각의 값을 합쳐주면 정말 끝! 
문자열 =&gt; 객체 변환 때 처음에 <code>&amp;</code>으로 스트링을 분리했던 걸 생각하면 정말 모든 과정을 거꾸로 거슬러왔구나 느낄 수 있다.</p>
<pre><code class="language-javascript">&#39;order-by=${this.state.filter}&amp;category=${this.props.match.params.id}&amp;limit=20&#39;</code></pre>
<p>위의 과정을 한 눈에 알 수 있는 코드 전문은 아래와 같다.</p>
<pre><code class="language-javascript">  const objToQuery = objQuery =&gt; {
  stringQuery = Object.entries(objQuery).map(([key, value]) =&gt; `${key}=${value}`).join(&quot;&amp;&quot;);
  return stringQuery;
}</code></pre>
<br>

<h1 id="두-번째-방법--urlsearchparams">두 번째 방법 : <a href="https://developer.mozilla.org/ko/docs/Web/API/URLSearchParams/URLSearchParams">URLSearchParams()</a></h1>
<p>긴 풀이가 무색하게도.. 첫 번째 방법의 모든 과정은 하나의 메서드로 해결 가능하다 ^^.. 참 좋아진 세상~
하지만 배열과 객체의 속성을 제대로 공부할 수 있기에 학습 과정에선 첫 번째 방법을 추천하고, 실제 적용할 땐 두 번째 방법을 추천한다. 원리를 알고 사용하는 것과 모르고 사용하는 건 하늘과 땅 차이이니까 😎</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS | 계산된 속성명 (computed property name)]]></title>
            <link>https://velog.io/@dev_bomdong/%EA%B3%84%EC%82%B0%EB%90%9C-%EC%86%8D%EC%84%B1%EB%AA%85-computed-property-name</link>
            <guid>https://velog.io/@dev_bomdong/%EA%B3%84%EC%82%B0%EB%90%9C-%EC%86%8D%EC%84%B1%EB%AA%85-computed-property-name</guid>
            <pubDate>Mon, 06 Sep 2021 15:42:35 GMT</pubDate>
            <description><![CDATA[<h2 id="계산된-속성명이란">계산된 속성명이란?</h2>
<blockquote>
<p>Javascript ES6부터 지원되는 속성으로, 객체 속성명을 <strong>동적으로</strong> 결정하는 것.
<code>[ ]</code> 안에 식을 넣고, 그 결과가 속성명으로 사용된다.
구조분해 할당과 세트로, React에서도 매우 유용히 활용된다. </p>
</blockquote>
<p>하지만 구조분해 할당도 그렇고 계산된 속성명도 그렇고.. 
이름만 들으면 도통 감이 잘 오지 않는다. 실제 프로젝트를 진행하다 만난 코드로 정리해본다. </p>
<h2 id="예시">예시</h2>
<p>React에서 <code>API</code>와 <code>statename</code>을 인자로 받는 함수 <code>handleFetch</code>를 통해</p>
<p><strong>(1)</strong> API의 데이터를 json 형태로 가져오고
<strong>(2)</strong> 이 데이터를 인자 statename의 state에 저장하고 싶다고 하자.</p>
<br>
우선 fetch 함수를 통해 API를 받아와 첫 번째 .then으로 json으로 넘겨주는 **(1)**까진 쉽다. 
그럼 이제 **(2)** 차례. statename이란 state에 어떻게 데이터를 저장할까?

<p>이 때 필요한게 바로 <em><strong>계산된 속성명 (computed property name)</strong></em>
<br></p>
<p>객체의 속성명을 동적으로 결정할 땐 <code>[ ]</code> 안에 넣어, 계산된 속성명을 이용하자. 
아래 코드와 같이 state객체의 속성명은 인자에 따라 동적으로 변경되므로, <code>[ ]</code> 안에 넣어 계산된 속성명을 사용한다.</p>
<pre><code class="language-javascript"> handleFetch = (API, statename) =&gt; {
    fetch(API)
      .then(res =&gt; res.json()) // (1)
      .then(data =&gt; {
        this.setState({
          [statename]: data.Result, // (2)
        });
      });
  };</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React | 로그인 후 token 저장, 서버에 전달하기]]></title>
            <link>https://velog.io/@dev_bomdong/React-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%84%B1%EA%B3%B5%EC%8B%9C-token-%EC%84%9C%EB%B2%84%EC%97%90-%EB%B3%B4%EB%82%B4%EA%B8%B0</link>
            <guid>https://velog.io/@dev_bomdong/React-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%84%B1%EA%B3%B5%EC%8B%9C-token-%EC%84%9C%EB%B2%84%EC%97%90-%EB%B3%B4%EB%82%B4%EA%B8%B0</guid>
            <pubDate>Sun, 05 Sep 2021 07:39:47 GMT</pubDate>
            <description><![CDATA[<p>유투브 프리미엄은 로그인을 해야 광고를 보지 않을 수 있고, 
인스타그램에선 로그인을 해야 내 피드로 갈 수 있다. </p>
<p>이러한 인가 과정에 필요한 <strong>token</strong>
로그인 후 발생되는 token을 localStorage에 저장하고, 특정 사이트에서 필요할 때 서버에 보내는 것까지 알아보자.</p>
<h1 id="token-왜-필요한가"><em>token</em>, 왜 필요한가?</h1>
<p>HTTP는 단기기억상실과 같은 stateless 특성을 가지고 있기 때문에 한 번 로그인을 한다고 그 사실을 계속 기억하지 못한다. 따라서 원래대로라면 로그인을 했더라도 마이페이지 등 로그인이 필요한 사이트에 접속할 때마다 로그인을 진행해야 한다. </p>
<p>이러한 상황을 막기 위한 것이 <em><strong>token !</strong></em> </p>
<p>먼저 로그인을 완료하면 인증 스티커와 같은 token을 전달받고, 마이페이지 등 로그인이 필요한 사이트를 접속할 때마다 서버에 token을 보내며 나는 로그인했다! 권한있다! 라고 알려주니 다시 로그인할 필요가 없다.</p>
<h1 id="어떻게-저장하고-서버에-보내는가">어떻게 저장하고, 서버에 보내는가?</h1>
<p>기존 세팅 : 로그인 버튼을 누르면 <code>handleLogin()</code> 함수 호출</p>
<h3 id="1-로그인-성공시-localstorage에-token-저장">1. 로그인 성공시 localStorage에 token 저장</h3>
<p>1) 백엔드 측에서 설정한 로그인 성공시 response.MESSAGE와
2) 토큰의 발급 유무에 따라 로그인 성공 여부를 알 수 있다.</p>
<p>token이 true이면(있으면) localStorage에 <code>login-token</code>이라는 키 값으로 token을 저장했다.
(localStorage에 저장할 경우 해당 도메인에 영구저장)</p>
<pre><code class="language-javascript">//아래 부분을 fetch 함수의 두 번째 .then()에 작성

if (response.ACCESS_TOKEN) {
    localStorage.setItem(&#39;login-token&#39;, response.ACCESS_TOKEN);
}


//참고 : 코드 전문

handleLogin = () =&gt; {
    fetch(`${signinAPI}/login`, {
      method: &#39;POST&#39;,
      body: JSON.stringify({
        email: this.state.email,
        password: this.state.password,
      }),
    })

      .then(response =&gt; response.json())

      .then(response =&gt; {
        if (response.ACCESS_TOKEN) {
          localStorage.setItem(&#39;login-token&#39;, response.ACCESS_TOKEN);
        }
      });
  };</code></pre>
<h3 id="2-인가authorization가-필요한-사이트에서-token-전달">2. 인가(Authorization)가 필요한 사이트에서 token 전달</h3>
<p>이제 마이페이지, 장바구니 등 인가 과정이 필요한 사이트에서 데이터를 요청할 때, 아래의 방법으로 localStorage에 저장해두었던 token을 쏙쏙 꺼내 함께 전달하면 된다!</p>
<p>fetch함수의 두 번째 인자는 조건 부분이므로, 이 부분의 headers에 아래 부분을 작성한다. </p>
<ul>
<li><code>&#39;Content-Type&#39;: &#39;application/json&#39;</code> : 데이터를 json형태로 전송</li>
<li><code>Authorization: localStorage.getItem(&#39;login-token&#39;)</code> : localStorage에 login-token key로 저장한 값을 HTTP Authorization 요청 헤더로 전달</li>
</ul>
<pre><code class="language-javascript">  fetch(`${API}/login`, {
      method: &#39;GET&#39;,
      headers: {
        &#39;Content-Type&#39;: &#39;application/json&#39;,
        Authorization: localStorage.getItem(&#39;login-token&#39;),
      },
      body: JSON.stringify({
          //생략
      })</code></pre>
<br>

<blockquote>
<p><strong>📌 학습참고자료</strong>
<a href="https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage">MDN - Window.localStorage</a>
<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Authorization">MDN - Authorization</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[React | 회원가입 기능 구현하기]]></title>
            <link>https://velog.io/@dev_bomdong/React-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_bomdong/React-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 30 Aug 2021 00:26:00 GMT</pubDate>
            <description><![CDATA[<p>현재 email창엔 &#39;@&#39;가 포함되어야 하고, password는 5자리 이상이어야 버튼이 활성화되는 초기상태에서 회원가입을 진행해보고자 한다. </p>
<h2 id="step1--state-설정">Step.1 : state 설정</h2>
<p><strong>최상위 컴포넌트의 state/fetch 함수 부분</strong> (중요 부분만 발췌)</p>
<pre><code class="language-javascript">
// state 부분
constructor(props) {
    super(props);
    this.state = {
      first_name: &#39;Donghee&#39;,
      last_name: &#39;Kim&#39;,
      email: &#39;&#39;,
      password: &#39;&#39;,
      phone_number: &#39;01011111111&#39;,
      gender: &#39;w&#39;,
      birth: &#39;1995-12-27&#39;,
    };
  }

//fetch 함수 부분 (then 함수 부분은 생략)
    fetch(&#39;API주소&#39;, {
      method: &#39;POST&#39;,
      body: JSON.stringify({
        first_name: &#39;Donghee&#39;,
        last_name: &#39;Kim&#39;,
        email: this.state.email,
        password: this.state.password,
        phone_number: &#39;010-1111-1111&#39;,
        gender: &#39;w&#39;,
        birth: &#39;1995-12-27&#39;,
      }),
    }</code></pre>
<p>최상위 컴포넌트의 state에 빈 문자열로 email, password를 주고, 
fetch함수를 통해 API주소가 들어올 경우 각각의 state값은 현 state의 email, password값으로 업데이트 되도록 했다. </p>
<h2 id="step2--input값을-저장하는-함수-활용">Step.2 : input값을 저장하는 함수 활용</h2>
<p><strong>email, password input에 준 속성들</strong></p>
<pre><code class="language-javascript">          &lt;input
            type=&quot;text&quot;
            className=&quot;id loginInput&quot;
            placeholder=&quot;전화번호, 사용자 이름 또는 이메일&quot;
            name=&quot;email&quot;
            onChange={this.handleInput}
          /&gt;
          &lt;input
            type=&quot;password&quot;
            className=&quot;password loginInput&quot;
            placeholder=&quot;비밀번호&quot;
            name=&quot;password&quot;
            onChange={this.handleInput}
          /&gt;</code></pre>
<p><strong>input의 값을 저장하는 handleInput 함수</strong></p>
<pre><code class="language-javascript">  handleInput = e =&gt; {
    const { value, name } = e.target;
    this.setState({ [name]: value });
  };</code></pre>
<p>email, password input에 각각 email, password로 <em><strong>name 속성</strong></em> 을 주고, 
onChange이벤트로 handleInput 함수를 주었다. (원래 handleId, handlePw으로 나뉘어져있었는데 리팩토링하는 과정에서 하나로 합쳤다.)</p>
<p>handleInput함수에선 <em><strong>구조분해할당</strong></em> 활용! 
input의 name 값(email, password)에 input에 입력된 값이 할당되도록 했다. 결과적으로 state의 email, password에 input에 입력된 값이 할당되는 셈이다. 아직 구조분해할당이 익숙치않아서 그런지 조금 힘들었던 구간. </p>
<h2 id="step3--api로-받아온-데이터와-비교">Step.3 : API로 받아온 데이터와 비교</h2>
<pre><code class="language-javascript">  handleJoin = () =&gt; {
    fetch(&#39;API주소&#39;, {
      method: &#39;POST&#39;,
      body: JSON.stringify({
        first_name: &#39;Donghee&#39;,
        last_name: &#39;Kim&#39;,
        email: this.state.email,
        password: this.state.password,
        phone_number: &#39;010-1111-1111&#39;,
        gender: &#39;w&#39;,
        birth: &#39;1995-12-27&#39;,
      }),
    })
      .then(response =&gt; response.json())
      .then(response =&gt; {
        if (response.MESSAGE === &#39;SUCCESS&#39;) {
          return alert(&#39;회원가입 성공!&#39;);
        }

        if (response.MESSAGE === &#39;EMAIL ALREADY EXISTS&#39;) {
          alert(&#39;이미 존재하는 이메일입니다&#39;);
        }
      });
  };</code></pre>
<p>외부 데이터의 응답메세지를 활용해 성공할 경우 &#39;회원가입 성공!&#39; 창을, 이메일이 이미 존재할 경우 &#39;이미 존재하는 이메일입니다&#39; 창이 뜨도록 했다. 이 때 백엔드 측과 사전에 아래 사항을 꼭 확인해보아야한다. </p>
<h3 id="➕-프론트-백엔드-사전-확인사항">➕ 프론트-백엔드 사전 확인사항</h3>
<p><strong>1. 각각의 데이터에 걸어둔 조건 **
(ex. 이메일엔 &#39;@&#39;가 포함되어야 한다 등) 
**2. key값</strong> 
(실습 요건 상 이미 완성된 작업물을 가지고 다시 맞추어봤는데, key값이 달라 변경하느라 애를 먹었다.)
<strong>3. 프론트-백엔드 측이 같은 와이파이를 사용하고 있는지</strong>
*<em>4. 백엔드 측의 서버가 올바른 branch에서 잘 열려있는지 *</em></p>
<p>이렇게 회원가입 기능 마무리! 실제로 백엔드 페어의 데이터를 가지고 회원가입-로그인 실습까지 완료했다.</p>
<h2 id="코드-전문">코드 전문</h2>
<p>전체적인 흐름을 보기 위한, 해당 회원가입을 진행한 페이지의 코드 전문은 아래와 같다.</p>
<pre><code class="language-javascript">
class LoginDonghee extends Component {
  constructor(props) {
    super(props);
    this.state = {
      first_name: &#39;Donghee&#39;,
      last_name: &#39;Kim&#39;,
      email: &#39;&#39;,
      password: &#39;&#39;,
      phone_number: &#39;01011111111&#39;,
      gender: &#39;w&#39;,
      birth: &#39;1995-12-27&#39;,
    };
  }

  handleJoin = () =&gt; {
    fetch(&#39;API주소&#39;, {
      method: &#39;POST&#39;,
      body: JSON.stringify({
        first_name: &#39;Donghee&#39;,
        last_name: &#39;Kim&#39;,
        email: this.state.email,
        password: this.state.password,
        phone_number: &#39;010-1111-1111&#39;,
        gender: &#39;w&#39;,
        birth: &#39;1995-12-27&#39;,
      }),
    })
      .then(response =&gt; response.json())
      .then(response =&gt; {
        if (response.MESSAGE === &#39;SUCCESS&#39;) {
          return alert(&#39;회원가입 성공!&#39;);
        }

        if (response.MESSAGE === &#39;EMAIL ALREADY EXISTS&#39;) {
          alert(&#39;이미 존재하는 이메일입니다&#39;);
        }
      });
  };

  handleInput = e =&gt; {
    const { value, name } = e.target;
    this.setState({ [name]: value });
  };

  render() {
    return (
      &lt;div class=&quot;LoginDonghee&quot;&gt;
        &lt;span className=&quot;logo&quot;&gt;Westagram&lt;/span&gt;
        &lt;form class=&quot;loginBox&quot;&gt;
          &lt;input
            type=&quot;text&quot;
            className=&quot;id loginInput&quot;
            placeholder=&quot;전화번호, 사용자 이름 또는 이메일&quot;
            name=&quot;email&quot;
            onChange={this.handleInput}
          /&gt;
          &lt;input
            type=&quot;password&quot;
            className=&quot;password loginInput&quot;
            placeholder=&quot;비밀번호&quot;
            name=&quot;password&quot;
            onChange={this.handleInput}
          /&gt;
          &lt;button
            type=&quot;button&quot;
            onClick={this.handleJoin}
            className={
              this.state.email.includes(&#39;@&#39;) &amp;&amp; this.state.password.length &gt; 5
                ? &#39;activeBtn&#39;
                : &#39;inactiveBtn&#39;
            }
          &gt;
            로그인
          &lt;/button&gt;
        &lt;/form&gt;
        &lt;a href=&quot;#&quot;&gt;비밀번호를 잊으셨나요?&lt;/a&gt;
      &lt;/div&gt;
    );
  }
}

export default withRouter(LoginDonghee);
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React | 검색 기능 구현하기]]></title>
            <link>https://velog.io/@dev_bomdong/React-%EA%B2%80%EC%83%89-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_bomdong/React-%EA%B2%80%EC%83%89-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 29 Aug 2021 23:43:44 GMT</pubDate>
            <description><![CDATA[<p>React로 외부 API를 받아온 뒤, 검색창에 입력하면 관련 데이터가 나오는 기능을 구현해보았다. </p>
<p>참고로, 해당 사이트는 아래의 3단 구조 컴포넌트로 되어있다.
<code>Monsters(최상위) &gt; CardList &gt; Card</code>
아래엔 Monsters Class 코드 위주로, 또 import 부분 등은 생략하고 적어볼 예정</p>
<h2 id="step1--state-설정">Step.1 : state 설정</h2>
<pre><code class="language-javascript">  componentDidMount() {
    fetch(&quot;API주소&quot;)
      .then((res) =&gt; res.json())
      .then((data) =&gt; {
        this.setState({
          monsters: data,
          userInput: this.state.userInput,
        });
      });
  }

  // SearchBox 에 props로 넘겨줄 handleChange 메소드 정의
  handleSearch = (e) =&gt; {
    const inputValue = e.target.value;

    this.setState({
      userInput: inputValue,
    });
  };</code></pre>
<p>componentDidMount를 이용해 외부 API를 fetch함수로 불러와 그 데이터를 monsters의 value에 담고, userInput엔 state의 userInput값을 담는다.</p>
<p>검색창 input엔 onChange 이벤트를 주어서 변화가 생길 경우 state에 input값을 저장하는 함수 <code>handleSearch</code>가 실행되도록 했다.</p>
<h2 id="step-2--filter-includes-활용">Step. 2 : filter, includes 활용</h2>
<p>이제 검색 기능의 핵심, <code>filter</code>와 <code>includes</code> 활용 !
외부 API로 받은 데이터 배열 monsters의 값은 각각의 카드다. 따라서 배열의 값에 <code>filter</code>를 걸어서, <em><strong>name값에 input값을 포함하는 카드를 반환하는 배열</strong></em> 을 data 변수에 넣었다.</p>
<pre><code class="language-javascript">const data = this.state.monsters.filter(
  (card) =&gt; card.name.toLowerCase().includes(this.state.userInput));</code></pre>
<h2 id="step-3--props-넘겨주기">Step. 3 : props 넘겨주기</h2>
<p>필터링된 data를 newData라는 props로 CardList 컴포넌트에 넘겨주었다. 이제 CardList 컴포넌트에서 넘겨받은 newData를 잘 활용해 각각의 카드를 불러와주면 된다! </p>
<p><strong>Monsters 컴포넌트 코드</strong></p>
<pre><code class="language-javascript">  render() {
    const data = this.state.monsters.filter(
      (card) =&gt; card.name.toLowerCase().includes(this.state.userInput));
    return (
      &lt;div className=&quot;Monsters&quot;&gt;
        &lt;h1&gt;컴포넌트 재사용 연습!&lt;/h1&gt;
        &lt;SearchBox 
          handleChange={this.handleSearch} /&gt;
        &lt;CardList newData={data} /&gt;
      &lt;/div&gt;
    );
  }</code></pre>
<br>

<p><strong>CardList 컴포넌트 코드</strong></p>
<pre><code class="language-javascript">class CardList extends Component {
  render() {
    return (
      &lt;div className=&quot;card-list&quot;&gt;
        {this.props.newData.map((card) =&gt; {
          return &lt;Card key={card.id} id={card.id} name={card.name} email={card.email} /&gt;;
        })}
      &lt;/div&gt;
    );
  }
}</code></pre>
<hr>
<p>로그인/회원가입 기능 만큼이나 자주 사용하게 될 검색기능
핵심인 <code>filter</code>, <code>includes</code>, <code>map</code>을 항상 기억하자! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ CSS로 요소 가운데 위치시키기]]></title>
            <link>https://velog.io/@dev_bomdong/CSS%EB%A1%9C-%EC%9A%94%EC%86%8C-%EA%B0%80%EC%9A%B4%EB%8D%B0-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_bomdong/CSS%EB%A1%9C-%EC%9A%94%EC%86%8C-%EA%B0%80%EC%9A%B4%EB%8D%B0-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 29 Aug 2021 06:59:47 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>?</strong> : CSS 코드를 작성할 때, 요소를 가운데 정렬하는데 어려움을 겪은 적이 있나요?
<strong>나</strong> : 🙋‍♀️...</p>
</blockquote>
<p>그래서 정리해본다. CSS로 요소를 가운데 정렬하는 방법!
아래 방법 중 한 가지만 적용해도 가로, 세로 가운데 정렬이 가능하다.</p>
<h1 id="기존-세팅">기존 세팅</h1>
<p><img src="https://images.velog.io/images/dev_bomdong/post/daab14a9-7dcd-4121-80c7-c905350ca9c5/image.png" alt=""></p>
<p><strong>HTML</strong>
HTML 코드는 아래에서 변함이 없다.</p>
<pre><code class="language-html">&lt;html&gt;
  &lt;body&gt;
    &lt;div class=&quot;outerDiv&quot;&gt;
      &lt;div class=&quot;innerDiv&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p><strong>CSS</strong>
html,body 태그에 height: 100%를 준다</p>
<pre><code class="language-css">html, body {
  height:100%
}

.outerDiv {
  background-color:darkseagreen;
  width:250px;
  height:250px;
}

.innerDiv {
  background-color:teal;
  width:100px;
  height:100px;
}
</code></pre>
<h1 id="1-부모요소에-flex-속성-부여">1. 부모요소에 flex 속성 부여</h1>
<p>부모 요소에 한 방향 레이아웃 시스템인 flex 속성을 주고, 
가로 세로 모두 center에 정렬되도록 했다. </p>
<pre><code class="language-css">  display: flex;
  justify-content:center; 
  align-items : center;</code></pre>
<p><img src="https://images.velog.io/images/dev_bomdong/post/5bd211cf-51fe-4ed1-a8ad-753491452ea0/image.png" alt=""></p>
<pre><code class="language-css">html, body {
  height:100%
}

.outerDiv {
  background-color:darkseagreen;
  width:250px;
  height:250px;

  //아래 부분을 추가했다.
  display: flex;
  justify-content:center; 
  align-items : center;
}

.innerDiv {
  background-color:teal;
  width:100px;
  height:100px;

}</code></pre>
<h1 id="2부모요소에-grid-속성-부여">2.부모요소에 grid 속성 부여</h1>
<p>부모 요소에 가로세로 양방향 레이아웃 시스템인 grid 속성을 주고, 
place-items: center속성을 주었다. </p>
<pre><code class="language-css">display:grid;
place-items: center;</code></pre>
<p><img src="https://images.velog.io/images/dev_bomdong/post/5bd211cf-51fe-4ed1-a8ad-753491452ea0/image.png" alt=""></p>
<pre><code class="language-css">html, body {
  height:100%
}

.outerDiv {
  background-color:darkseagreen;
  width:250px;
  height:250px;

  //아래 부분을 추가했다.
  display:grid;
  place-items: center;
}

.innerDiv {
  background-color:teal;
  width:100px;
  height:100px;

}</code></pre>
<h1 id="3-position-transform-속성-이용">3. position, transform 속성 이용</h1>
<p>우선 <strong>부모 요소</strong>에 <code>position:relative</code> 속성을 부여하고, 
<strong>자식 요소</strong>에 부모 요소에 따라 위치가 결정되도록 <code>position:absolute</code> 속성을 부여했다. </p>
<p>자식 요소에 <code>top, left:50%</code> 속성을 부여하면 자식요소의 좌측상단(top+left)이 부모 요소의 중앙에 위치하게 된다.</p>
<p><img src="https://images.velog.io/images/dev_bomdong/post/fd83b719-7514-47bb-b66d-d9935b85c224/image.png" alt=""></p>
<p>우리의 목적은 자식요소를 정중앙에 위치시키는 것이기 때문에, 자식요소에<code>transform:translate(-50%, -50%)</code>을 추가로 적용한다.</p>
<p>transfrom은 대상의 형태를, translate는 대상의 위치를 변경한다.
translate의 첫 값은 x축, 두 번째 값은 y축을 의미한다.
-50%은 대상 요소 (여기선 자식요소) 크기의 절반만큼을 의미한다. 
따라서 <code>transform:translate(-50%, -50%)</code>은 자식요소 크기의 절반씩을 빼내 x축,y축 음의 방향으로 움직이라는 것.</p>
<p><img src="https://images.velog.io/images/dev_bomdong/post/5bd211cf-51fe-4ed1-a8ad-753491452ea0/image.png" alt=""></p>
<p>코드를 반영하면 짜잔 - 가운데 정렬 완료! </p>
<pre><code class="language-css">html, body {
  height:100%
}

.outerDiv {
  background-color:darkseagreen;
  width:250px;
  height:250px;
  // 아래 부분을 추가했다.
  position:relative
}

.innerDiv {
  background-color:teal;
  width:100px;
  height:100px;
  // 아래 부분을 추가했다.
  position:absolute;
  top:50%;
  left:50%;
  transform:translate(-50%, -50%);
} </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹 개발 공부 한 달차 회고록]]></title>
            <link>https://velog.io/@dev_bomdong/1%EB%8B%AC-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@dev_bomdong/1%EB%8B%AC-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Sat, 28 Aug 2021 16:37:50 GMT</pubDate>
            <description><![CDATA[<h1 id="🌎--week-1-4--주차별-회고">🌎  Week 1-4 | 주차별 회고</h1>
<h2 id="✔️-week-1-2--pre-course"><a href="https://velog.io/@dev_bomdong/%EC%9C%84%EC%BD%94%EB%93%9C-Pre-Course2%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0%EB%A1%9D">✔️ Week 1-2 | Pre-Course</a></h2>
<h2 id="✔️-week-3--foundation">✔️ Week 3 | Foundation</h2>
<h3 id="◻-react-영접">◻ React 영접</h3>
<ul>
<li>state와 props의 티키타카가 중요한 리액트를 드디어 만났다.
사실 처음엔 개념 이해가 잘 되지않아 많이 힘들었는데, 세션에서 멘토 준식님이 본인은 리액트를 처음 배울 때 자괴감에 찌들어 매일 한 시간씩 샤워를 하며 고민했다고 하셨었다. 의외로 그 이야기가 정말 큰 힘이 됐다. 나만 힘든거 아니였구나..!</li>
</ul>
<h3 id="◻-첫-팀-프로젝트---westagram">◻ 첫 팀 프로젝트 - Westagram</h3>
<ul>
<li><p>개인별로 Javascript를 활용해 완성했던 인스타그램 클론 페이지를 팀을 나누어 공통 컴포넌트를 만들며 react로 바꾸는 프로젝트를 진행했다.</p>
</li>
<li><p>팀원들 각자의 개인 작업물을 이미 가지고 있는 상태에서 공통 컴포넌트를 만들고 컨벤션을 정해야 하니, 지극히 당연하게도 의견 차이가 생겼다. 그 차이를 잘 좁혀나가기위해 깊은 고민을 했고, 소통 방식에 대해 배운 점이 정말 많았다. 결과적으로 우리 팀은 의견도 잘 정리되고 이후 진행된 팀 내 peer review까지 성공적으로 해냈다! 🎉</p>
</li>
<li><p>팀별로 git을 통해 파일을 관리했는데, 이 때 시행착오를 너무 많이 겪어서 git을 확실히 배울 수 있었다. 이 때 함께 비슷한 이슈로 고생한 철진님과 둘이서 종일 오히려 좋아~! 외치고 다닌 기억이 생생하다.</p>
</li>
</ul>
<h2 id="✔️-week-4--foundation">✔️ Week 4 | Foundation</h2>
<h3 id="◻-첫-프론트-백엔드-통신">◻ 첫 프론트-백엔드 통신</h3>
<ul>
<li>백엔드 페어의 API로 회원가입, 로그인을 진행해봤다. 
성공하는 순간 박수치고 환호하던 그 순간을 잊지못한다 (ㅋㅋㅋㅋㅋㅋㅋ) 
물론 성공하기까지 몇 번의 시행착오가 있기도 했다.
key값부터 각자 걸어두었던 조건까지.. 내 생각보다 더 백엔드 측과 맞춰봐야할게 많구나 배웠다.</li>
</ul>
<h3 id="◻-팀-프로젝트-peer-review">◻ 팀 프로젝트 peer review</h3>
<ul>
<li>처음으로 다른 사람의 코드를 읽어내며 리뷰하는 시간을 가졌다. 
내가 작성하지 않은 코드를 읽어내는 게 생각보다 어려웠고, 내 코드에 달린 리뷰를 보면서 아하 싶었던 순간도 여러 번이었다. 코드 리뷰 문화가 잘 되어있는 회사의 구성원이 되고싶은 내게 참 소중했던 시간. </li>
</ul>
<br>

<h1 id="🌎--한-달을-보내고-떠오르는-생각들">🌎  한 달을 보내고 떠오르는 생각들</h1>
<h2 id="📝-배우고-협업하는-순간을-온전히-즐겼다">📝 배우고 협업하는 순간을 온전히 즐겼다.</h2>
<p>어려운 순간도 기꺼이 즐기며 보낸 것은 스스로에게 긍정적으로 지내자 다짐한 덕분이기도,동기분들의 긍정적인 영향 덕분이기도 했다. </p>
<p>남들보다 웃음 장벽이 낮아 평소에도 잘 웃는 편이긴 하지만, 지난 한 달간 정말 많이 웃으며 즐겁게 생활했다. 낯선 개념을 이해하는 동시에 적용하느라 뇌에 쥐가 나는 순간에도, 의견 차이를 잘 풀어나가기위한 방법을 고민하던 순간에도 <em><strong>이렇게 또 하나를 배운다~</strong></em> 라는 마음가짐으로 즐겁게 임했다. </p>
<p>가끔 심란해지려하면 동기들과 웃음 폭발하는 쉬는 시간을 보내며 리프레쉬했다. 덕분에 슬럼프에 빠질 새도 없이 차곡차곡 지식과 경험을 쌓아나갔다. </p>
<p><img src="https://images.velog.io/images/dev_bomdong/post/ce1dfc1b-2267-48e4-8c27-be1545465f1b/image.png" alt="">운영체제 재설치 때문에 저녁도 거르고 한참 고생할 때, 현재님이 사다주신 도너츠 🍩</p>
<br>

<p><img src="https://images.velog.io/images/dev_bomdong/post/ece43024-d936-47a4-bd5c-c8ea141e7a30/image.png" alt="">문화의 날, 동기분들과 함께 산책한 선정릉</p>
<br>

<p><img src="https://images.velog.io/images/dev_bomdong/post/52048805-19f0-4915-a62c-797092edcd93/image.png" alt="">소소한 행복이 되어준 해피밀 도라에몽 장난감</p>
<br>


<p><img src="https://images.velog.io/images/dev_bomdong/post/379b52b2-f142-4fb8-9dec-d32b1f217363/image.png" alt="">모니터가 없는 날 위해 중고거래 글이 올라오자마자 뛰어와 알려주신 현재님과 영현님👍 덕분에 드디어 모니터가 생겼다.</p>
<br>




<h2 id="📝-내-보폭을-지키며-최선을-다했다">📝 내 보폭을 지키며 최선을 다했다.</h2>
<p>리액트를 처음 접한 3주차, 관련 과제는 쏟아지는데 아직 state와 props를 어떻게 연결해야하는지 감이 오지않아 너무 혼란스러웠다. 특히 Javascript로 완성했던 인스타그램 클론 페이지를 리액트로 다시 바꾼 뒤 코드를 리팩토링할 때 내가 이렇게 멍청했나 자괴감이 들기도했다.(feat. map과 state, props의 향연..)  </p>
<p>동기 분의 도움으로 기능 구현에 성공하거나, 이것저것 시도해보다 얻어걸려 기능이 잘 돌아가도, 원리가 확실히 이해되지 않을 땐 오케이 다시~(꼭 소리내서 말해야한다)하며 처음부터 한 단계씩 짚어가며 꼭 이해하고 넘어갔다. </p>
<p>기능 구현 결과에만 치중하지 않고 내가 이해할 수 있는 선에서 최선을 다했고, 덕분에 목표로 했었던 필수 기능 외에 추가 기능까지 구현해냈다. 내 보폭을 지키며 꾸준히 걸어나간 덕분이라고 생각한다. </p>
<br>


<h2 id="📝-기록을-강점으로">📝 기록을 강점으로</h2>
<p>취미 중 하나가 필사이기도 하고, 몇 년간 블로그에 주간 일기를 작성해온 것처럼 생각을 정리해 기록하는걸 좋아하는 편이다. 이게 개발자로서의 강점이 될 수 있을까 싶었는데, 될 수 있었다!
<img src="https://images.velog.io/images/dev_bomdong/post/4b0e4cdb-64ee-4541-a0c2-c1304c2dd220/image.png" alt=""></p>
<p>과제 진행 후 작성한 PR에서 멘토님께 PR 내용과, 커밋 메세지를 잘 작성했다는 피드백을 받았다. (좋은 말은 두고두고 보도록 박제. . ) 하지만 아직 이 강점은 코드에까지 옮겨지진 않았다. 잘 정리해 작성하는 습관을 코드 위에도 옮겨서 <em><strong>시맨틱하고 가독성 좋은 코드</strong></em> 를 작성하는 습관을 기르자.</p>
<br>

<h1 id="🌎-그래서-어떤-개발자가-되고-싶은가">🌎 그래서, 어떤 개발자가 되고 싶은가?</h1>
<p>예전에는 그저 <em>함께 일하고 싶은 개발자</em> 가 되고 싶다고 생각했는데 그래서 함께 일하고 싶은게 어떤건지 구체적으로 말하긴 어려웠다. 한 달 동안 나는 어떤 개발자가 되고싶은지 꾸준히 고민해보았고, 결과적으로 나는 <em><strong>유연한 개발자</strong></em> 가 되고 싶다. 개발자로서도, 인간적으로도 말이 통하는 동료가 되고싶다. 예상치못한 환경에 봉착해도 흐름을 파악해 적응해내고, 팀원들간의 의사소통을 더 부드럽게 만드는 그런 개발자! 목표를 정했으니 이제 두 번의 프로젝트를 진행하며 한발 두발 가까이 다가가야지 😎  </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React | map 함수 적용시 key props를 부여하는 이유]]></title>
            <link>https://velog.io/@dev_bomdong/React-map-%ED%95%A8%EC%88%98-%EC%A0%81%EC%9A%A9%EC%8B%9C-key-props%EB%A5%BC-%EB%B6%80%EC%97%AC%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@dev_bomdong/React-map-%ED%95%A8%EC%88%98-%EC%A0%81%EC%9A%A9%EC%8B%9C-key-props%EB%A5%BC-%EB%B6%80%EC%97%AC%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Thu, 26 Aug 2021 11:27:28 GMT</pubDate>
            <description><![CDATA[<p>React에선 기존에 한땀한땀 작성해야했던 배열을 map()함수를 이용해 element list로 반복실행할 수 있다. </p>
<p>예를 들어 div안에 feed의 데이터가 담긴 배열(this.state.feeds)에서 배열 값이 하나씩 나타나도록 map()함수를 이용할 때, 아래의 코드를 작성했다.
(실제 코드에서 일부분을 빼내온 터라 보충 설명을 해보자면, 배열 값 feed는 comments, feedContents의 속성을 가지고있다.)</p>
<pre><code class="language-javascript">&lt;div className=&quot;feeds-wrap&quot;&gt;
  {this.state.feeds.map(feed =&gt; {
    return (
      &lt;Feeds
       comments={feed.comments}
      feedsContents={feed}
      /&gt;
    );
  })}
&lt;/div&gt;</code></pre>
<p>위 코드를 실행시키면 console에 아래와 같이 <code>list의 모든 child요소는 unique key 속성을 가져야 한다</code>는 메세지가 출력된다. </p>
<p><img src="https://images.velog.io/images/dev_bomdong/post/8bd5348a-a795-4e71-8c3f-9002ee80f009/image.png" alt=""></p>
<p>그럼 여기서 key는 무엇이고, 왜 필요한 걸까?</p>
<h1 id="what-is-key-in-react-">What is Key in React ?</h1>
<blockquote>
<p>Key는 React에서 element list를 만들 때 포함해야 하는 문자열 속성으로, 어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕는다.</p>
</blockquote>
<h2 id="key엔-어떤-값을-써야할까">key엔 어떤 값을 써야할까?</h2>
<blockquote>
<p>Key 값은 list에서 해당 항목을 고유하게 식별할 수 있는 문자열이 가장 좋다. 
대부분의 경우 <strong>데이터의 ID</strong>를 key로 사용한다.</p>
</blockquote>
<p>💥 <strong>주의 : 배열의 index를 사용하는 건 지양하자</strong>
key값을 배열의 index로 지정할 경우, 배열의 순서가 바뀌면 component의 state와 관련된 문제가 발생할 수 있다. component는 key를 기반으로 갱신/재사용되는데 index를 key로 사용하면, 항목의 순서가 바뀌었을 때 key도 변경된다. 따라서 state까지 의도치않게 변경될 수 있다.</p>
<p>명시적으로 key를 지정하지 않을 경우 React는 기본적으로 인덱스를 key로 사용하니, 가급적이면 별도로 key값을 지정하자.</p>
<p>Key값은 위 주의사항을 유념하고 중복되지 않는값을 사용하면 된다. 
개인적으로는 밀리초를 포함한 현재시각을 나타내는 <code>Date.now()</code>를 자주 사용한다. 
<em>(다만 적은 양의 mock Data를 구성할 경우 하드코딩으로 1,2,3.. 등으로 주기도 했다.)</em></p>
<br>

<h1 id="map함수-적용시-key-props를-사용하는-이유는">map함수 적용시 Key props를 사용하는 이유는?</h1>
<p>아래와 같이 key값이 없는 element로 이루어진 트리에서 새로운 element가 추가될 경우, React는 <code>&lt;ul&gt;</code>의 모든 자식요소를 다시 변경하므로 비효율적이고 성능이 좋지 않다.</p>
<pre><code class="language-javascript">//변경 전 트리
&lt;ul&gt;
  &lt;li&gt;딸기&lt;/li&gt;
  &lt;li&gt;바나나&lt;/li&gt;
&lt;/ul&gt;

//변경 후 트리: &lt;ul&gt;의 모든 자식요소를 다시 변경한다.
&lt;ul&gt;
  &lt;li&gt;복숭아&lt;/li&gt;
  &lt;li&gt;딸기&lt;/li&gt;
  &lt;li&gt;바나나&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>*<em>key를 이용하면 앞서 말한 비효율성을 해결할 수 있다. *</em>
자식요소들이 key를 가지고 있다면, React는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 확인하므로 트리의 변환이 효율적으로 이루어진다.</p>
<pre><code class="language-javascript">//변경 전 트리
&lt;ul&gt;
  &lt;li key=&quot;2019&quot;&gt;딸기&lt;/li&gt;
  &lt;li key=&quot;2020&quot;&gt;바나나&lt;/li&gt;
&lt;/ul&gt;

//변경 후 트리: &lt;key=&quot;2018&quot;?&gt; 값만 이동시킨다.
&lt;ul&gt;
  &lt;li key=&quot;2018&quot;&gt;복숭아&lt;/li&gt;
  &lt;li key=&quot;2019&quot;&gt;딸기&lt;/li&gt;
  &lt;li key=&quot;2020&quot;&gt;바나나&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<h1 id="느낀-점">느낀 점</h1>
<p>React를 공부하며 느낀 점은, 여러개의 component를 렌더링하며 잘 연결시키는 게 정말 중요하다. 그럴 때마다 정말 자주 쓰이는 map함수.
key값도 직접적인 숫자 등을 입력하는 게 아니라 다른 component에서 받아오는 경우가 많다. 사실 console에 경고 메세지만 뜰 뿐 페이지는 잘 돌아가길래 없어도 되나? 싶었는데.. 정확한 연결을 위해선 key값을 꼭 넣어주자 다짐하게된다.</p>
<blockquote>
<p>📌 <strong>참고 자료</strong>
<a href="https://ko.reactjs.org/docs/lists-and-keys.html">React 공식문서 - 리스트와 Key</a>
<a href="https://ko.reactjs.org/docs/reconciliation.html#recursing-on-children">React 공식문서 - 재조정 (Reconciliation)</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[숫자배열에서 가장 자주 등장한 숫자를 인자만큼 반환하기]]></title>
            <link>https://velog.io/@dev_bomdong/%EC%88%AB%EC%9E%90%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-%EA%B0%80%EC%9E%A5-%EC%9E%90%EC%A3%BC-%EB%93%B1%EC%9E%A5%ED%95%9C-%EC%88%AB%EC%9E%90%EB%A5%BC-%EC%9D%B8%EC%9E%90%EB%A7%8C%ED%81%BC-%EB%B0%98%ED%99%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_bomdong/%EC%88%AB%EC%9E%90%EB%B0%B0%EC%97%B4%EC%97%90%EC%84%9C-%EA%B0%80%EC%9E%A5-%EC%9E%90%EC%A3%BC-%EB%93%B1%EC%9E%A5%ED%95%9C-%EC%88%AB%EC%9E%90%EB%A5%BC-%EC%9D%B8%EC%9E%90%EB%A7%8C%ED%81%BC-%EB%B0%98%ED%99%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 26 Aug 2021 05:15:10 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p>nums는 숫자로 이루어진 배열입니다. 가장 자주 등장한 숫자를 k 개수만큼 return해주세요.</p>
<blockquote>
<p><strong>예제 1</strong>
nums = [1,1,1,2,2,3]
k = 2 
return [1,2] 
<br>
<strong>예제 2</strong>
nums = [1]
k = 1 
return [1]</p>
</blockquote>
<br>

<h1 id="풀이">풀이</h1>
<p>(페어 풀이에서 풀이방안의 흐름을 제시하는 네비게이터 역할을 맡으신, 현재님의 풀이를 기반으로 공부했다 👍 )</p>
<h2 id="사고의-흐름">사고의 흐름</h2>
<h3 id="step1--객체를-활용해-숫자의-등장-횟수-구하기">Step.1 : 객체를 활용해 숫자의 등장 횟수 구하기</h3>
<p>우선 숫자 배열에서 가장 자주 등장한 숫자를 찾아내야한다. 
*<em>배열 값끼리의 비교가 필요할 땐, 객체를 만들어 비교하는게 편하다. *</em></p>
<p>비어있는 객체 obj를 만들고,  for문으로 값을 넣어준다.</p>
<pre><code class="language-javascript">  const obj = {};

  for (let i=0; i&lt;nums.length; i++){
    (nums[i] in obj)
    ? obj[nums[i]] += 1
    : obj[nums[i]] =1
  }</code></pre>
<p>for문은 삼항연산자를 사용했는데, 자세히 해석해보자면 
배열의 i번째 값이 객체에 없으면 value에 1을 넣고, 
배열의 i번째 값이 객체에 있으면 value에 1을 더한다. </p>
<p>따라서 <code>nums = [1,1,2,2,2,3]</code> 이라 하면 <code>obj</code>는 <code>{1:2, 2:3, 3:1}</code> 의 형태가 된다. 이 형태는 결국 <code>{배열의 숫자값 : 그 숫자가 배열에서 등장한 횟수}</code>를 뜻하고, 여기서 가장 자주 등장한 숫자는 2가 된다. </p>
<br>

<h3 id="step2--가장-자주-등장한-값-찾아내기">Step.2 : 가장 자주 등장한 값 찾아내기</h3>
<p><code>{배열의 숫자값 : 그 숫자가 배열에서 등장한 횟수}</code> 형태의 객체에서 우리가 원하는 건 가장 자주 등장한 배열의 숫자값이다. </p>
<p>객체의 value 기준으로 key를 내림차순 정렬하면 자주 등장한 순서대로 key값이 정렬된다.</p>
<pre><code class="language-javascript">  let newArr = Object.keys(obj).sort((a,b) =&gt; {
    return obj[b] - obj[a]
 })</code></pre>
<p><code>Object.keys(객체명)</code> 을 하면 객체의 key값만 배열로 반환해준다. 
여기에 sort()메서드를 이용해 value값을 기준으로, key값의 배열을 내림차순 정렬했다. </p>
<p><code>sort(a,b) =&gt; {return obj[b] - obj[a]}</code> 부분이 sort()메서드로 내림차순 정렬을 한 부분! </p>
<p><code>obj = {1:2, 2:3, 3:1}</code>일 경우 위 과정을 진행하면 <code>[2,1,3]</code>이 반환된다.</p>
<br>

<h3 id="step3--자주-등장한-값을-k갯수-만큼-반환하기">Step.3 : 자주 등장한 값을 k갯수 만큼 반환하기</h3>
<p>이제 정말 거의 다 왔다! 
가장 자주 등장한 순서대로 정렬된 key값의 배열에서, 인자 k갯수 만큼 값을 반환해주면 된다.  </p>
<pre><code class="language-javascript"> const result = newArr.slice(0,k).map(item =&gt; parseInt(item));
 return result;</code></pre>
<p><strong>(1)</strong> slice()메서드를 이용해 배열의 첫 index(0)부터 index(k) 전까지의 값을 반환한다. slice메서드의 인자는 <code>(첫 시작 index, 직전까지의 값을 반환하는 index)</code>이므로 가능한 풀이. </p>
<p>💥 <strong>주의 :</strong> 반환되는 값은 string이다.</p>
<p>예를 들어 <code>[2,1,3].slice(0,2) = [&#39;2&#39;,&#39;1&#39;]</code> </p>
<p><strong>(2)</strong> 값이 나오면 지금은 string이기 때문에 숫자로 바꿔주어야 한다.
배열의 값을 바꿔 새로운 배열로 만들어주는 <strong>map</strong> 메서드를 사용하고, 그 안에 각각의 값을 숫자로 바꾸는 건 <strong>parseInt</strong> 메서드를 사용했다.</p>
<p>위 값을 result 변수에 담고, 이를 return 해주면 풀이 완성!</p>
<br>

<h2 id="정답-코드">정답 코드</h2>
<pre><code class="language-javascript">function topK(nums, k) {
  const obj = {};

  for (let i=0; i&lt;nums.length; i++){
    (nums[i] in obj)
    ? obj[nums[i]] += 1
    : obj[nums[i]] =1
  }

  let newArr = Object.keys(obj).sort((a,b) =&gt; {
    return obj[b] - obj[a]
  })

  const result = newArr.slice(0,k).map(item =&gt; parseInt(item));

  return result;  
}</code></pre>
<br>

<h2 id="느낀-점">느낀 점</h2>
<ul>
<li><p>배열의 값을 서로 비교할 땐 더이상 for문 안에 i번째, (i+1)번째 값을 돌려보는 것만 떠올리지말고, <strong>조건을 객체에 넣어서 비교하는 패턴</strong>을 머릿속에 저장하자</p>
</li>
<li><p>객체의 속성을 조금 더 많이 알아두어야겠다. 
예를 들어 <strong>객체의 key값만 배열로 반환</strong>해주는 <code>Object.keys(객체명)</code> 라던지~</p>
</li>
<li><p>알고리즘 문제는 배열을 많이 활용하다보니 <strong>오름차순, 내림차순으로 정렬</strong>해주는 <code>sort()</code> 메서드를 잘 알아둘 필요가 있다. 이것도 함께 저장!  </p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React | State와 Props]]></title>
            <link>https://velog.io/@dev_bomdong/React-State%EC%99%80-Props</link>
            <guid>https://velog.io/@dev_bomdong/React-State%EC%99%80-Props</guid>
            <pubDate>Thu, 26 Aug 2021 02:37:36 GMT</pubDate>
            <description><![CDATA[<h1 id="state와-props">State와 Props</h1>
<p><code>state</code> 와 <code>props</code> (properties)는 JavaScript의 객체이다. 
두 객체 모두 렌더링 결과물에 영향을 주는, 속성을 가진 데이터이다.</p>
<h1 id="state와-props의-차이점">State와 Props의 차이점</h1>
<ul>
<li><p><code>state</code> : (함수 내에 선언된 변수처럼) <strong>컴포넌트 안에서 관리</strong>되는 데이터.
자식 컴포넌트 입장에서 보면 <strong>쓰기 전용</strong>이라고 할 수 있다.</p>
</li>
<li><p><code>props</code> : (함수의 매개변수처럼) 상위 계층의 컴포넌트에서 자식 컴포넌트로 <strong>전달</strong>되는 데이터.
자식 컴포넌트 입장에서 보면 <strong>읽기 전용</strong>이라고 할 수 있다.</p>
</li>
</ul>
<h1 id="어떤-데이터가-state가-되어야-할까">어떤 데이터가 state가 되어야 할까?</h1>
<ol>
<li>부모로부터 props를 통해 전달되는가?</li>
<li>시간이 지나도 변하지 않는가?</li>
<li>컴포넌트 안의 다른 state나 props를 가지고 계산 가능한가?</li>
</ol>
<p>위 질문에 하나라도 yes가 나오면 state가 아니다. 
다르게 말해보면,** 아래의 데이터가 state가 되어야한다. **</p>
<blockquote>
<ol>
<li>부모로부터 props를 통해 전달되지 않는다.</li>
<li>변화되는 값이다.</li>
<li>컴포넌트 안의 다른 state나 props를 가지고 계산할 수 없다. </li>
</ol>
</blockquote>
<h1 id="어떤-컴포넌트가-어떤-state를-가져야-할까">어떤 컴포넌트가 어떤 state를 가져야 할까?</h1>
<p>React는 항상 상위 =&gt; 하위 컴포넌트로 내려가는 단방향 데이터 흐름을 따른다.
이 특성을 이용해서, 어떤 컴포넌트가 어떤 state를 가질지 헷갈릴 때 체크해볼 수 있다. </p>
<blockquote>
<ol>
<li>state를 기반으로 렌더링하는 <strong>모든 컴포넌트</strong>를 찾는다.</li>
<li>컴포넌트 계층 구조에서 최상위에 위치한 <strong>공통 오너 컴포넌트</strong>(common owner component)를 찾는다. (특정 state가 있어야 하는 모든 컴포넌트들의 최상위에 있는 컴포넌트).</li>
<li>최상위에 위치한 공통 오너 컴포넌트가 state를 가져야 한다.</li>
<li>state를 소유할 적절한 컴포넌트를 찾지 못하였다면, <strong>해당 state를 소유하는 컴포넌트를 새로 만들어서 최상위의 공통 오너 컴포넌트에 추가</strong>한다.</li>
</ol>
</blockquote>
<blockquote>
<p>📌 <strong>참고 자료</strong>
<a href="https://ko.reactjs.org/docs/faq-state.html">React 공식문서 : 컴포넌트 State</a>
<a href="https://ko.reactjs.org/docs/thinking-in-react.html#step-4-identify-where-your-state-should-live">React 공식문서 : React로 사고하기</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[인증(Authentication) & 인가(Authorization)]]></title>
            <link>https://velog.io/@dev_bomdong/%EC%9D%B8%EC%A6%9DAuthentication-%EC%9D%B8%EA%B0%80Authorization</link>
            <guid>https://velog.io/@dev_bomdong/%EC%9D%B8%EC%A6%9DAuthentication-%EC%9D%B8%EA%B0%80Authorization</guid>
            <pubDate>Tue, 24 Aug 2021 03:15:48 GMT</pubDate>
            <description><![CDATA[<h1 id="인증-authentication">인증 (Authentication)</h1>
<blockquote>
<p>유저의 identification을 확인하는 절차</p>
</blockquote>
<p>이 때 인증에 필요한 게 뭐가 있을까? 바로 ID, PW, E-mail등이다. 
따라서 인증을 한 마디로 쉽게 말하면 <strong>로그인</strong> </p>
<h2 id="span-stylecolordarkgreen절차span"><span style="color:darkgreen">절차</span></h2>
<ol>
<li>user의 ID / PW 생성</li>
<li>user의 PW 암호화 후 DB에 저장</li>
<li>user가 ID / PW 입력</li>
<li>user가 입력한 PW를 암호화한 값과, DB에 저장되어있던 암호화된 PW가 일치하는지 비교</li>
<li>두 값이 일치하면 로그인 성공!</li>
<li>로그인 성공시 user에게 <code>access token</code>을 발급 (로그인 인증 증명서 같은 느낌)</li>
<li>이후 user는 server에 <code>access token</code>을 첨부해 request를 보내기 때문에, 계속해서 로그인을 하지 않아도 된다. </li>
</ol>
<br>

<h2 id="span-stylecolordarkgreen비밀번호-암호화span"><span style="color:darkgreen">비밀번호 암호화</span></h2>
<p>user의 비밀번호는 해킹, 보안 이슈로 인해 암호화된 후 DB에 저장된다. </p>
<h3 id="비밀번호-암호화-방법">비밀번호 암호화 방법</h3>
<p>일반적으로 단방향 해쉬 함수(one-way hash function)가 쓰인다.</p>
<h4 id="단방향-해쉬-함수">단방향 해쉬 함수</h4>
<ul>
<li>입력값인 원본 메세지를 변환해 암호화된 메시지(다이제스트)를 생성한다. </li>
<li>단방향으로 진행되어 원본 메시지를 알면 암호화된 메시지를 쉽게 알 수 있지만, 암호화된 메시지에서 원본 메시지를 알아낼 수 없다. 따라서 해킹을 막기 위한 암호학적 용도로 사용된다.</li>
</ul>
<br>

<h2 id="span-stylecolordarkgreensalting--keystretchingspan"><span style="color:darkgreen">Salting &amp; KeyStretching</span></h2>
<p>단방향 해쉬 함수는 미리 해쉬값들을 계산해 놓은 테이블(Rainbow Table)을 활용해 해킹될 수 있다는 단점이 있다. 이러한 단점을 보완하기 위한 것이 Salting과 KeyStretching! </p>
<h3 id="salting">Salting</h3>
<blockquote>
<p>입력한 비밀번호에 임의로 생성한 문자열(Salt)를 합쳐서 해싱하고, 이 해시값을 저장하는 방법</p>
</blockquote>
<p><img src="https://images.velog.io/images/dev_bomdong/post/1efa7f8b-25ba-4452-b234-96957609d828/image.png" alt=""></p>
<p>ex. pw를 <code>아자아자123</code> 이라고 생성한다면, salt가 합쳐진 해시값 
<code>asdfghjkl아자아자123</code> 이 DB에 저장된다.</p>
<h3 id="keystretching">KeyStretching</h3>
<blockquote>
<p>단방향 해쉬값을 계산 한 후 그 해쉬값을 또 해쉬 하고, 또 이를 반복하는 것</p>
</blockquote>
<p>ex. <code>asdfghjkl아자아자123</code> 를 여러 번 해쉬한다! </p>
<br>


<h2 id="span-stylecolordarkgreenbcryptspan"><span style="color:darkgreen">Bcrypt</span></h2>
<blockquote>
<p>Salting &amp; Key Stretching을 도와주는 대표적인 라이브러리</p>
</blockquote>
<br>


<h2 id="span-stylecolordarkgreenjwtjson-web-tokensspan"><span style="color:darkgreen">JWT(JSON Web Tokens)</span></h2>
<p>HTTP의 특징 중 하나인 stateless (이전 상태를 기억하지않는다)에 의하면 user는 로그인이 성공한 뒤에도 매번 로그인을 다시 반복해야한다. </p>
<p>앞쪽의 인증 절차를 소개할 때, 위 문제가 일어나지 않도록 인증이 완료되면 증명서와 같은 <code>access token</code>(암호화된 유저정보)을 발급한다고 했다. server는 이 <code>access token</code>을 복호화해서 유저정보를 얻게된다.</p>
<p><code>access token</code>을 생성하는 기술중 가장 널리 이용되는 것이 <strong>JWT(JSON Web Tokens)</strong>이다. 유저 정보가 담긴 JSON 데이터를 암호화 해서 클라이언트와 서버간에 주고 받는 것을 뜻한다.</p>
<h3 id="구조">구조</h3>
<p><code>header. payload. Signature</code></p>
<ul>
<li>header(헤더) : 암호화X 토큰의 타입과 해시 암호화 알고리즘이 담겨있다.</li>
<li>payload(내용) : 암호화X  어떤 유저의 토큰인지, 만료일이 담겨있다.</li>
<li>signature(서명) : 유일하게 암호화O 이 토큰이 해당 사이트에서 만든것이라는 것을 확인할 때 사용된다.</li>
</ul>
<br>


<h1 id="인가-authorization">인가 (Authorization)</h1>
<blockquote>
<p>request를 요청하는 user가 권한이 있는지를 확인하는 절차
ex. 넷플릭스 유료회원만 영화를 볼 수 있다 / 회원만 특정 페이지에 접근할 수 있다. </p>
</blockquote>
<h2 id="span-stylecolordarkgreen절차span-1"><span style="color:darkgreen">절차</span></h2>
<ol>
<li>user 정보를 확인할 수 있는 정보를 포함한 <code>access token</code>을 생성한다.</li>
<li>user가 request를 보낼때 생성한 <code>access token</code>을 첨부해서 보낸다.</li>
<li>server에서 user로부터 받은 <code>access token</code>을 복호화 하고, user 정보(ID, PW 등)를 얻는다.</li>
<li>user 정보를 활용해 DB에서 해당 user의 권한(permission)을 확인하다.</li>
<li>user가 권한을 가지고 있음이 확인되면 해당 request를 처리한다.</li>
<li>user가 권한을 가지고 있지 않으면 Unauthorized Response(401) 혹은 다른 에러 코드를 보낸다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[로마자에서 숫자로 바꾸기]]></title>
            <link>https://velog.io/@dev_bomdong/%EB%A1%9C%EB%A7%88%EC%9E%90%EC%97%90%EC%84%9C-%EC%88%AB%EC%9E%90%EB%A1%9C-%EB%B0%94%EA%BE%B8%EA%B8%B0</link>
            <guid>https://velog.io/@dev_bomdong/%EB%A1%9C%EB%A7%88%EC%9E%90%EC%97%90%EC%84%9C-%EC%88%AB%EC%9E%90%EB%A1%9C-%EB%B0%94%EA%BE%B8%EA%B8%B0</guid>
            <pubDate>Mon, 23 Aug 2021 12:45:19 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p>로마자에서 숫자로 바꾸기</p>
<p>1~3999 사이의 로마자 s를 인자로 주면 그에 해당하는 숫자를 반환해주세요.
로마 숫자를 숫자로 표기하면 다음과 같습니다.</p>
<pre><code class="language-javascript">Symbol       Value
I             1
V             5
X             10
L             50
C             100
D             500
M             1000</code></pre>
<p>로마자를 숫자로 읽는 방법은 로마자를 왼쪽부터 차례대로 더하면 됩니다.
III = 3
XII = 12
XXVII = 27
입니다.</p>
<p>그런데 4를 표현할 때는 IIII가 아니라 IV 입니다.
뒤의 숫자에서 앞의 숫자를 빼주면 됩니다. 
9는 IX입니다.</p>
<p>I는 V와 X앞에 와서 4, 9
X는 L, C앞에 와서 40, 90
C는 D, M앞에 와서 400, 900</p>
<br>

<h1 id="풀이">풀이</h1>
<h2 id="사고의-흐름">사고의 흐름</h2>
<h3 id="step1--입력값로마자을-숫자로-변환하기">Step.1 : 입력값(로마자)을 숫자로 변환하기</h3>
<pre><code class="language-javascript">// (1) 로마자:숫자 객체 변수는 romeNum
const romeNum = {
  &#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
}

// (2) 로마자를 한 글자씩 배열로 만든다
const romeArr = s.split(&#39;&#39;);

// (3) 입력값을 로마자 -&gt; 숫자로 변환한다.
const numArr = romeArr.map(num =&gt; romeNum[num]);</code></pre>
<p><strong>(1)</strong> 주어진 <code>로마자 : 숫자</code> 조합을 <code>romeNum</code>객체에 넣어 두었다. </p>
<p><strong>(2)</strong> 입력값(로마자)이 s라면, <code>split</code>을 이용해 한 글자씩 분리된 로마자 배열<code>romeArr</code>을 만들어두었다. </p>
<p><strong>(3)</strong> 한 글자씩 분리된 로마자(<code>romeArr</code>의 값)는 <code>romeNum</code> 객체의 key에 해당한다.
<code>romeArr</code>에 <code>map()</code>을 적용해 배열값(로마자)이 객체 <code>romeNum</code>의 key(로마자)로 작용하는 <strong>value(숫자)</strong>를 배열 <code>numArr</code>에 담는다.  </p>
<h3 id="step2--for문으로-양-옆의-값을-비교해-결과값-반환하기">Step.2 : for문으로 양 옆의 값을 비교해 결과값 반환하기</h3>
<pre><code class="language-javascript">//인접값끼리 비교해 값을 반환하는 반복문
let result = 0;

for (let i=0; i&lt;numArr.length; i++){
  if(numArr[i]&lt;numArr[i+1]){ 
      result -= numArr[i];
    } else {
      result += numArr[i] 
    }  
  }
  return result;
}</code></pre>
<p>문제를 보면 로마자에 따라 반환값의 조건이 있다.</p>
<ul>
<li><strong>로마자의 앞 값 &gt;= 뒷 값</strong> 이면 <strong>앞 값</strong> 을 더한다.
(ex. III = 3, XII = 12, XXVII = 27)</li>
<li><strong>로마자의 앞 값 &lt; 뒷 값</strong> 이면 <strong>-앞 값</strong> 을 더한다.
(ex. IV)</li>
</ul>
<p>따라서 위 과정을 for문을 통해 반복하면, 정답이 반환된다!
이 부분이 참 까다로웠는데, 뒷 값이 더 큰 예제(IV 등)를 통해 실제로 진행해보며 이해할 수 있었다.</p>
<h2 id="정답-코드">정답 코드</h2>
<pre><code class="language-javascript">function romanToNum(s) {

//로마자:숫자 객체 변수는 romeNum
const romeNum = {
  &#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
}

//로마자를 한 글자씩 배열로 만든다
//text배열 : romeArr
const romeArr = s.split(&#39;&#39;);

//입력값을 나눠서 로마자 -&gt; 숫자로 변환한다.
// 숫자배열 : numArr
const numArr = romeArr.map(num =&gt; romeNum[num]);


//인접값끼리 비교해 값을 반환하는 반복문
let result = 0;

for (let i=0; i&lt;numArr.length; i++){
  if(numArr[i]&lt;numArr[i+1]){ 
      result -= numArr[i];
    } else {
      result += numArr[i] 
    }  
  }
  return result;
}</code></pre>
<h1 id="느낀점">느낀점</h1>
<p>배열의 i번째 값과 (i+1)번째 값을 비교하며 새로운 값을 반환하는 형태의 풀이가 자주 보인다. 이번 풀이에도 해당 형태를 떠올리긴 했지만, 까다로운 조건이 있는 탓에 for문에서 잠시 무너졌었다.🤢 그래도 필요한 곳에 적절한 형태의 풀이 방법을 꺼내쓴 건 잘했다! 필요할 때 꺼내쓸 수 있는 패턴을 머릿속에 더 많이 저장하고자 다짐   </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React | What is React?]]></title>
            <link>https://velog.io/@dev_bomdong/What-is-React</link>
            <guid>https://velog.io/@dev_bomdong/What-is-React</guid>
            <pubDate>Sat, 21 Aug 2021 05:58:55 GMT</pubDate>
            <description><![CDATA[<h1 id="why-react">Why React?</h1>
<p>웹의 규모가 커지면서 동시접속자 수와 데이터의 양이 폭발적으로 증가했고, 이 결과로 웹 3세대의 시대가 도래하게 된다. 이러한 흐름속에서 기존의 DOM, jQuery만으로는 새로운 웹 애플리케이션을 개발하고 코드를 유지보수 하는 것이 어려워졌다.</p>
<p>규모가 커지고 복잡해진 웹 애플리케이션의 데이터 관리 / 코드 유지 보수를 편리하게 하기 위해 다양한 Frontend Framework 및 Library가 등장한다. React는 이 중 Frontend Library에 해당한다. </p>
<br>

<h1 id="what-is-react-">What is React ?</h1>
<blockquote>
<ul>
<li>사용자 인터페이스(UI)를 만들기 위한 JS <strong>라이브러리</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>컴포넌트</strong> 단위로 이루어진 UI <strong>라이브러리</strong></li>
</ul>
<p>위 단어에서 생소하게 느껴졌던 단어, 라이브러리와 컴포넌트
아래로 각각 정리해본다.</p>
<br>

<h2 id="프레임워크-vs-라이브러리">프레임워크 vs 라이브러리</h2>
<h4 id="프레임워크">프레임워크</h4>
<ul>
<li>다른 사람들이 만들어놓은 코드 안에 내가 들어가는 것</li>
<li>집의 구조/철제물이 완성된 완성품</li>
<li>다양한 기능들이  한 번에 묶어져서 제공이 되므로 정해진 골격 안에서 원하는 기능을 구현해야 함</li>
<li>배우는 데 시간이 오래 걸림</li>
<li>ex. 앵귤러</li>
</ul>
<h4 id="라이브러리">라이브러리</h4>
<ul>
<li>다른 사람들이 만들어놓은 것을 내가 가져와서 쓰는 것</li>
<li>우리가 원하는 재료들을 골라서 입맛에 맞게 집을 지을 수 있음.</li>
<li>작은 단위, 작은 도메인 안에서 자신의 원하는 작은 부분을 구현. 따로 정해진 골격이 없다.</li>
<li>배우는 시간이 상대적으로 짧다.</li>
<li>ex. 리액트</li>
</ul>
<br>

<h2 id="component">Component</h2>
<blockquote>
<p>한 가지의 기능을 수행하는 UI 단위</p>
</blockquote>
<h3 id="구조">구조</h3>
<ul>
<li>데이터를 가진 state</li>
<li>사용자에게 어떻게 보여줄 지를 결정하는 render 함수<br>  (상태가 변할 때마다 render 함수가 호출된다.)</li>
</ul>
<h3 id="특징">특징</h3>
<ul>
<li>독립적이고 재사용이 가능하다.</li>
<li>최상위의 컴포넌트 : Root</li>
<li>리액트 내부에 가상돔(Vitrual Dom)이 있어 UI를 빠르게 업데이트한다.
가상돔(Virtual Dom)
  : 이전 UI상태를 메모리에 유지해서, 변경될 UI의 최소 집합을 계산하는 기술</li>
</ul>
<br>

<h2 id="jsx">JSX</h2>
<blockquote>
<p>리액트에서 사용하는 자바스크립트 확장 문법</p>
</blockquote>
<h3 id="특징-1">특징</h3>
<ul>
<li>HTML마크업 + JS로직구현을 함께 할 수 있다.</li>
<li>하나의 부모 태그가 필요하다. </li>
<li>Self closing가능</li>
<li>camelCase property (ex.className)</li>
</ul>
<h3 id="사용법">사용법</h3>
<ul>
<li>JS코드를 기재할 땐 겉에 {}로 감싸주어야 한다.</li>
<li>JSX 안에서 컴포넌트를 표시할 땐 대문자로 시작하게 적어야한다. </li>
</ul>
<br>

<h2 id="settings">Settings</h2>
<h3 id="nodejs">Node.js</h3>
<p>JS가 브라우저 밖에서도 동작하게 하는 실행환경</p>
<h3 id="npm">npm</h3>
<p>package : node로 실행할 수 있는 어플리케이션</p>
<h3 id="cra">CRA</h3>
<p>리액트 프로젝트를 시작하는데 필요한 개발 환경을 세팅해주는 도구(toolchain)
여러 파일이 생성되는데, 그 중 특히 생소했던 파일 몇 개를 추려서 정리해본다.</p>
<ul>
<li><p>node.modules</p>
<p>  : CRA를 구성하는 모든 패키지 소스 코드</p>
</li>
<li><p>package.json</p>
<p>  : 프로젝트에 대한 정보를 담고 있는 파일</p>
<p>  &#39;dependency : 패키지 이름/버전&#39; 이 중요</p>
</li>
<li><p>gitignore</p>
<p>  : git에 올리고 싶지 않은 파일</p>
</li>
</ul>
<hr>
<p>본격적으로 React 공부를 시작하기 전에 그래서 이게 왜 쓰이기 시작한 건지, 어떤 특징을 가지고 있는지 알고 시작하는 것이 중요하다고 생각했다. 간단히나마 개념을 정리해보았으니 이젠 기쁜 마음으로 React에 발을 푹 담구어 보자 🎉 </p>
]]></description>
        </item>
    </channel>
</rss>