<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>junejae_1625.log</title>
        <link>https://velog.io/</link>
        <description>개발자가 꿈이에오</description>
        <lastBuildDate>Mon, 18 Apr 2022 06:17:23 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. junejae_1625.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/junejae_1625" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[코드캠프 부트캠프 후기]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Mon, 18 Apr 2022 06:17:23 GMT</pubDate>
            <description><![CDATA[<h3 id="개발회사에서-만든-실무-코딩-부트캠프--codecamp">개발회사에서 만든 실무 코딩 부트캠프 &#39;{ }code.camp&#39;</h3>
<p>비전공자인 나는 개발자가 되기 위해 여러 부트캠프를 찾아보았고 코드캠프를 선택하였다.</p>
<p>그럼 지금부터 코드캠프의 장단점을 적어보도록 하겠다.</p>
<h3 id="장점">장점</h3>
<p>** - 청결하고 온전히 학업에 집중할 수 있는 쾌적한 공간
** 코드캠프는 공유오피스 &#39;FASTFIVE&#39;를 사용하고 있으며, 무료로 이용 가능한 커피머신, 릴렉싱룸(안마의자), 시리얼, 우유를 제공하고 있다.</p>
<p>** - 모든 수강생들에게 각각 모니터, 키보드, 마우스, 노트북 거치대 제공
** 코드캠프에서 수업을 듣기 위해 노트북을 구매했지만, 따로 키보드와 마우스, 노트북거치대를 구매하지 않았다. 하지만 학원에서 모두 제공해주며 수업에 집중할 수 있게끔 모니터를 연결하여 두개의 화면을 사용할 수 있다.</p>
<p>** - PF제도
** 일주일마다 PF(Paring Friends)라 하여 짝을 이뤄준다. 개인공부를 할때나 과제를 하면서 막히는 부분들, 해결하지 못한 오류들이 생길때 같이 고민해주고 서로 격려해주며 의지를 다잡을 수 있었다.</p>
<p>** - 현직 8년차 풀스택 멘토님
** 프론트 앤드 개발자 코스와 백앤드 개발자 코스의 수업을 모두 진행하시는 &#39;노원두&#39; 멘토님!!!!
 풀스택이시다보니 프론트앤드와 백앤드의 고충을 잘 알고 있으며 어떤 부분이 협업을 하는데 있어서 도움이 되는지와 수준높은 강의를 해주셨다.</p>
<p>** - 친절한 멘토님들
** 비전공자인 나는 제로베이스에서 시작하다보니 모든게 낯설고 어색했으며 실수도 많았다. 하지만 그럴때마다 옆에서 차근차근 알려주셨으며 한번도 귀찮아하시지 않으셨다. 아무래도 오프라인의 최대 장점이 아닌가 싶다.</p>
<p>**  - 3개의 포트폴리오
**  코드캠프를 수료하자마자 내 손에는 3개의 포트폴리오가 생겼다. 취업을 위해서 포트폴리오가 필수인만큼 수업을 진행하면서 포트폴리오에 그 날 배운 수업 내용을 적용시키면, 어느샌가 완성되어있는 포트폴리오를 볼 수 있다.</p>
<h3 id="단점">단점</h3>
<p>**  - 아쉬운 html, css 강의
**   정규 수업을 듣기 전 &#39;프리캠프&#39; 교육을 통해 html, css, Javascript를 교육받는다. 하지만 수업 일수 5일밖에 되지 않아 아쉬웠다. 만약 코드캠프 부트캠프의 정규 교육을 받게 된다면 기본적인 html, css, Javascript에 대한 공부는 미리 하고 오는것을 추천한다.</p>
<p>** - 팀프로젝트
** 두달동안 수업듣고 개인 포트폴리오 진행하느라 협업에 대한 경험이 전무하다보니 막막하기만 했다. 디자인부터 기획 데이터의 흐름 등등... 하지만 &#39;팀바팀 (Team by Team)&#39; 이라는거...</p>
<p>** - G-rating 제도
** 학업 성취 및 성실도에 따라 차등으로 적용되는 G-rating이 있다. 점수별로 수료할때의 &#39;Level&#39;이 달라지는데 높았을때의 이점이 부족한 감이 있다. 높은 G-rating을 받게되면 수료증에 &#39;Level5&#39;로 수료할 수 있는데, 딱히..?</p>
<p>**  - 엄청난 학업량
**   일주일동안 배우는 양이 정말 엄청나다. 정말. 하루에 3시간 수업을 듣게 되는데 그 3시간 수업을 나의 포트폴리오에 적용시키고, 과제를 하다보면 정말 하루가 부족하다. 어떻게든 수업을 따라가야 다음날의 진도를 진행할 수 있다보니 매번 밤 늦게 집에 도착하게된다. 만약 코드캠프를 고민중에 있는 사람이 있다면 체력도 잘 비축해 놓길 바란다.</p>
<h3 id="느낀점">느낀점</h3>
<p> 3달이라는 시간이 타 부트캠프에 비해 짧다고 느꼈지만, 수료를 하고나서 드는 생각은 <strong>&#39;아, 3달이라 겨우 버텼구나&#39;</strong> 였다. 만약 더 많은 교육을 위해 3달이 넘었더라면 중간에 풀어지지 않았을까 하는 생각이 든다. 정말 힘든 3달이었다. 잠도 항상 부족했고, 오류 하나 해결하기 위해 이틀을 갈아넣은 적도 있다. 하지만 개발자로 커리어를 전환하는 동기들을 알게되었고 실력도 정말 많이 늘었다.</p>
<blockquote>
<p> 만약 부트캠프를 코드캠프로 생각하는 사람이 있다면 <strong>&#39;프리캠프&#39;</strong> 강의가 무료로 진행되니, 와서 분위기와 강의의 수준을 느껴보시길 바란다.</p>
</blockquote>
<p>  이 글이 부트캠프를 고려하는 사람들에게 도움이 되길 바란다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 30일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-30%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-30%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 24 Feb 2022 05:31:12 GMT</pubDate>
            <description><![CDATA[<h3 id="refereshtoken">refereshToken</h3>
<p>refreshToken의 설명에 앞서 22일차에 남겼던 로그인 프로세스가 기억이 안난다면 다시 한번 읽어보고 오자.</p>
<blockquote>
<p><a href="https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-22%EC%9D%BC%EC%B0%A8">코드캠프 부트캠프 22일차</a></p>
</blockquote>
<p>결론적으로 나온게 JWT인데, JWT는 토큰 자체에 로그인 정보를 저장해놓기 때문에 백엔드에서 DB로 접근할 필요가 없어졌다.
하지만, JWT도 백엔드에 들어가 로그인 유무만 구분하기에 중간에 탈취가 되어도 이 정보가 맞는지 검증이 불가능하다는 한계가 존재하게 되는데, 이를 위해 만료시간을 주어 시간이 지나면 재발급(refreshToken) 시키게 되는 것이다.</p>
<p>로그인을 진행할때 2개의 결과물을 보내주게 되는데 accessToken과 refreshToken을 보내주게 된다.
accessToken은 state에 담아주고, refreshToken은 cookie에 담아준다.
로그인 유무가 필요한 특정 API를 요청을 예로 들어보자.
토큰이 만료가 된 경우에는 브라우저에서 &#39;<strong>UNAUTHENTED</strong>&#39;에러를 반환해주는데, 이 에러를 받게 되면 Browser단에서 app.tsx부분에서 받은 에러가 어떤 에러인지 체크한 후 인가 관련 에러일 경우에는 refreshToken을 가지고 accessToken 재발급 요청을 하게 되고, 새로 발급받은 accessToken을 다시 state에 담아준 후 기존 요청에 실패했던 API를 새 accessToken을 가지고 재요청 하게 된다.</p>
<p>데이터 암호화를 사용하기 위해 http uri를 https로 변경해주고, 쿠키를 포함시켜 보내기 위해 credentials를 include로 변경시켜준다.
또한, onError()를 사용해 errorLink를 만들어주고, onError()안에는 콜백함수를 넣는다.</p>
<h4 id="refreshtoken의-프로세스"><strong>refreshToken의 프로세스</strong></h4>
<blockquote>
<p>API 요청을 했는데,</p>
</blockquote>
<ol>
<li>만약 에러가 있다면</li>
<li>에러를 하나씩 뽑아 해당 에러가 토큰 만료 에러(UNAUTHENTICATED)인지 확인한다.</li>
<li>토큰 만료 에러라면 refreshToken으로 accessToken을 재발급 시켜준다.
(app.tsx에서는 ApolloClient 세팅이 끝나지 않은 시점이기 때문에 graphql-request 라이브러리를 사용하여 mutation, refreshToken을 실행시킨다.)</li>
<li>재발급 받은 accessToken을 state에 다시 저장시킨다.</li>
<li>방금 실패한 쿼리 정보가 담긴 operation 설정을 operation.setContext({})를 활용해 accessToken만 변경하여 forword(operatoin)로 재 요청한다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 29일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-28%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-28%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 23 Feb 2022 05:59:56 GMT</pubDate>
            <description><![CDATA[<h3 id="kakao-map">Kakao-map</h3>
<p>카카오멥은 지도API로 크게 구글지도, 네이버지도, 카카오지도 등이 있다. 이 3가지는 크게 비용적인 차이와 세부적인 기능간 차이가 있다. 오늘은 1일 30만회 무료 요청이 가능한 카카오 지도를 배워보았다.</p>
<p>지도를 적용시키기 전에 개발자 등록을 진행하고 애플리케이션을 추가하여 web플랫폼과 도메인을 등록해주면 사전 준비가 끝이난다.
kakao를 사용하기 위해서는 window에 추가를 해줘야 하는데 추가하는 방법은 다음과 같다.</p>
<blockquote>
<p>declare const window: typeof globalThis &amp; {
  kakao: any;
};</p>
</blockquote>
<p>지도를 넣어서 작성한 코드들을 Gitghub에 그대로 올리게 되면 발급받은 appkey가 그대로 올라가게되어 보안이 좋지 않다는 점이 있다. 프론트엔드에서 사용하는 appkey는 숨길 수가 없으므로 appkey요청을 받아줄 도메인을 적어주어 우리가 지정한 도메인이 아닌 곳에서는 appkey가 작동하지 않도록 설정해 줄 수 있다.</p>
<p>페이지 이동간 router.push를 사용하면 발생하는 오류가 있다. 카카오 기능이 로딩되기 전에 실행되어 발생하는 문제인데 이 문제는 html의 a태그를 통해서 오류를 잡는 방법과 카카오 기능이 로딩이 완료될 때까지 기다리는 방법이 있다.
a태그를 사용하게 되면 페이지를 새롭게 다시 요청하는 것으로 이 방식을 MPA(Multi Page Application)이라고 한다.</p>
<p>Next의 경우에는 처음 사이트 접속 시에 프론트에서 페이지에 필요한 모든 정보를 보내주고, 페이지 이동 시에 새롭게 다시 요청하는 것이 아닌 브라우저 자체에서 페이지가 나타나고 감춰지는 형태로 작동하는 SPA(SinglePageApplication)방식이라 하며, 프론트앤드(서버)에서 랜더링이 되는것이 아닌 브라우저(클라이언트)측에서 렌더링이 된다하여 CSR(Client Side Rendering)이라고 한다.</p>
<p>기다리는 방식으로는 useEffect를 사용하여 직접 다운로드받아 다 받을때까지 기다린 후 그려주면 되는데, useEffect안에 createElement기능을 사용하여 script태그를 만들고, document.head.appendChild(script)를 사용하여 head태그에 넣어준다.
이 후, scipt.onload 내부에 window.kakao.map.load()를 통해 카카오 맵이 전부 다 받아진 후 화면을 그리게 해주면 되는데, 카카오script 부분의 뒤에 autoload=false를 붙여 자동으로 불러오는 기능을 꺼주면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 28일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-27%EC%9D%BC%EC%B0%A8-8f2i06dg</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-27%EC%9D%BC%EC%B0%A8-8f2i06dg</guid>
            <pubDate>Tue, 22 Feb 2022 05:34:05 GMT</pubDate>
            <description><![CDATA[<h3 id="결제프로세스">결제프로세스</h3>
<p><img src="https://images.velog.io/images/junejae_1625/post/33921f4e-93ff-48d6-8847-545f469f7361/%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%202022-02-22%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.50.12.png" alt="">
카드결제를 진행하기 위해서는 수많은 카드사(신한, 국민, 우리...) 앞단에서 결제를 처리해주는 PG(Payment Gateway)사를 거치게 된다. PG사는 결제대행사로 대표적으로는 NHN, NicePay, KG이니시스가 있다. PG사마다 결제를 위해 준비해야하는 양식들이 다 다르다보니 수수료 문제라던지, 다른 어떠한 이유로 PG사를 변경해야 할 때 양식을 다시 맞추는 것도 시간과 노력이 소모된다. 이러한 문제를 해결하기 위해 PG사 앞에 결제 솔루션 회사가 생기게 되었다.
결제 솔루션 회사는 여러 PG사 앞단에서 복잡한 연동을 대신 해주며 대표적으로는 아임포트와 부트페이가 있으며, 아임포트에 대해 알아보도록 하겠다.</p>
<p>아임포트를 연동하면 결제하는 화면이 나오게 되고, 결제를 성공하게되면 받게되는 data중에 결제ID(imp_uid)라는 데이터를 받게 된다. 이렇게 받게 된 imp_Uid를 백엔드에 전송하여 데이터베이스에서 결제 정보를 관리할 수 있게 된다.
하지만, 무통장입금(가상계좌), 모바일 결제를 하는 경우에는 현재 페이지 주소를 잃어버리게 되므로 imp_uid를 받을 수 없게 된다. 이러한 경우에는 &quot;웹훅노티피케이션&quot;을 이용하여 백엔드API를 rest방식으로 하나 만들고 API 주소를 입력해 놓으면, 아임포트에서 결제 완료/취소 되었을 때, 무통장입금에 성공했을 때 등 아임포트가 Backend-API로 결제내역을 보내주게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 27일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-27%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-27%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 21 Feb 2022 05:18:03 GMT</pubDate>
            <description><![CDATA[<h3 id="web-editor">Web-Editor</h3>
<p><img src="https://images.velog.io/images/junejae_1625/post/de857896-47c0-415d-af90-48ee27e93d6e/%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%202022-02-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.56.43.png" alt="">
게시판을 작성할때 글자의 스타일을 줄 수 있는 웹 에디터이다. 글자의 크기, 진하게, 기울기, 밑줄 등 원하는 스타일을 지정해 줄 수 있다.
웹 에디터에는 많은 종류의 라이브러리가 있는데 대표적으로는 React-draft-wyswiyg과 React-quill이 있으며, React-quill을 사용해 보았다.</p>
<blockquote>
<p>yarn add react-quill
import &quot;react-quill/dist/quill.snow.css&quot;;</p>
</blockquote>
<p>React-quill을 다운받고 css또한 import 시켜준다.</p>
<p>React에서 React-quill을 사용한다면 에러가 나지않지만 Next에서 실행할 경우에는 에러가 발생하게 되는데, <strong>Next의 Pre-rendering과정 중에 document, window와 같은 속성이 없기 때문에 발생하는 오류</strong>이다.</p>
<blockquote>
<p>typeof Window !=== &#39;undefined&#39;
useEffect()
process.browser
이 3가지 방법을 써도 오류는 사라지지 않는다.</p>
</blockquote>
<p>왜냐하면 import 자체를 못하기 때문인데, 이를 해결하기 위해서 브라우저 자체에 import를 시켜줘야 하고, 이를 위해 <strong>Dynamic-import</strong>를 이용해야 한다.</p>
<p>dynamic을 &quot;next/dynamic&quot;에서 가져오고, 가져온 dynamic내에서 react-quill을 가져와 ServerSideRendering은 하지 않도록 설정해 준다.</p>
<blockquote>
<p>const ReactQuill = dynamic(() =&gt; import(&quot;react-quill&quot;), { ssr: false });</p>
</blockquote>
<p>Hook-form과 함께 사용할 때는 register로 인식시켜줄 수 없고, 자동으로 onChange인식이 적용되지 않아 setValue()를 사용해 값을 넣어주고, trigger()를 통해 changeEvent를 감지하여 Hook-form에 알려주어야 한다.</p>
<p>웹 에디터의 원리는 작성한 내용 앞 뒤로 </p>
<pre><code>&lt;u&gt; &lt;strong&gt;</code></pre><p>과 같은 태그를 붙여서 데이터베이스에 저장하는 방식이다.
이 내용들을 문자열이 아닌, 태그의 기능 그 자체로 인식하게 만들기 위해서는 <strong>dangerouslySetInnerHTML</strong>이라는 속성을 사용해야 하지만 보안의 문제가 생긴다.</p>
<h3 id="xsscrosssitescript">XSS(CrossSiteScript)</h3>
<p>dangerouslySetInnerHTML에 누군가가 악의적으로 </p>
<pre><code>&lt;script&gt;&lt;/script&gt;</code></pre><p>태그처럼 자바스크립트로 해킹기능을 작성해놨다면, 누군가가 해당 글을 클릭했을때 작성된 자바스크립트 코드가 실행될 것이고, 이를 통해 해킹(ex&gt;토큰 탈취)을 당할 수 있다.
React-quill의 경우에는 태그를 의미하는 단어인 &#39;&gt;&#39; , &#39;&lt;&#39; 등을 &#39;$gt&#39;, &#39;%lt&#39;와 같이 변경하여 문제가 발생하지 않도록 사전에 차단해 주었지만 다른 여러가지 방식으로 취약점을 뚫고 해킹을 시도할 수 있다. 따라서, 이러한 코드를 방지하기 위해 보안을 강화할 부분에 dompurify의 sanitize를 활용하여 막아줄 수 있으며, 이를 시큐어코딩이라 한다.</p>
<h3 id="hydration-issue">Hydration-Issue</h3>
<p>Web-Editor에서 설명했듯이 Next의 경우 Pre-rendering이 실행되고 diffing 과정이 실행되며, 서버와 브라우저 에서의 태그를 비교하고 서버에서 한번 그려준 내용을 브라우저에 그려내는 과정을 Hydration 이라 하는데 이때 발생하는 오류이다. 이를 해결하기 위해서는 브라우저에서 그릴때의 태그 개수와 서버 안의 태그 개수를 맞춰주면 CSS오류를 해결할 수 있다.
방법으로는 Browser가 아닐때 실행되는 조건을 적어주고 해당 조건에 빈 태그를 보여주는 조건을 걸어 태그의 개수를 맞추면 오류를 해결할 수 있따.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 26일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-26%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-26%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 18 Feb 2022 05:44:35 GMT</pubDate>
            <description><![CDATA[<h3 id="generictype">GenericType</h3>
<p>TypeScript를 사용하다보면 우리가 알지 못하는 타입을 표현할 때 종종 any를 사용했다. 이 경우 타입 검사를 하지 않게 되는데 타입의 일부만 알고 전체에 대한 타입을 알지 못할때 유용하다.
unknown의 경우에는 any와 비슷하게 사용하지만 좀 더 개발자에게 도움을 줄 수 있다. 에를들어 받게되는 인자를 unknown으로 지정해주고 해당 타입을 (typeof === &quot;number&quot;)식으로 지정하게 된다면 개발자에게 예상치 못한 오류를 줄여줄 수 있다.</p>
<p>any와 unknown을 사용하지 않고 우리가 직접 타입을 만들어줄수도 있다. &lt;&gt;를 사용하여 매개변수()앞에 타입 변수를 추가하면 된다.
generic 또한 any와 비슷하다. 하지만 any는 함수 반환 시 어떤 타입인지에 대한 정보를 잃게 되어 string 혹은 number를 넣어도 return 타입이 any로 반환되지만, generic의 경우에는 입력 값에 따라 내부 타입이 정의가 된다. 즉, 단일 타입이 아닌 다양한 타입에서 작동하게 작성할 수 있는 장점이 있다.</p>
<h3 id="브라우저-저장소">브라우저 저장소</h3>
<p>변수에 데이터를 넣어두면, 새로고침 시 저장된 데이터가 날아가는 현상이 있다. 이는 HTML, CSS, JS를 다시 화면에 새로 그려주기 때문이다. 따라서, 새로고침을 해도 기존의 데이터가 그대로 남아있어야 하는 상황이라면 쿠키(cookie), 로컬스토리지(localstorage), 세션스토리지(sessionstorage)가 있다. </p>
<blockquote>
<p>쿠키(cooki)의 경우에는 document.cookie
로컬스토리지와 세션스토리지의 경우에는 .setItem() .getItem()을 사용한다.</p>
</blockquote>
<p>쿠키의 경우에는 저장된 데이터가 Backend-API요청치 자동으로 함께 보내지게되어 백엔드와 브라우저 간 데이터를 공유할 때 유용하지만 너무 많은 데이터가 담겨져 있으면 효율성이 떨어지게 되므로, 만료시간을 지정해주어 특정 시간이 지나면 사라지게끔 설정해 줄 수 있다. 또한, httpOnly / secure를 사용하여 보안 옵션을 걸어줄 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 25일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-25%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-25%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 17 Feb 2022 05:52:22 GMT</pubDate>
            <description><![CDATA[<h3 id="비구조화할당-destructuring">비구조화할당 (Destructuring)</h3>
<p>ES6에 추가된 JS 표현식으로 배열이나 객체에서 특정 데이터를 변수로 추출해서 사용할 수 있게 해준다.
자주 사용하는 useState(), useQuery()또한 이러한 형식으로 이루어져있다는 것을 이번 시간을 통해 알게 되었다. 
변수를 선언하고 해당 데이터들을 가져오기 위해서 useState()의 경우에는 []배열로 받아왔으며, useQuery()의 경우에는 {}data로 받아왔다.
객체를 비구조화할당을 할 경우 가져오고자 하는 값의 key를 입력해야 하며, 배열을 비구조화할당을 할 경우에는 순서에 맞게끔 입력을 해야 한다. 
const {data} = useQuery()와 같이 useQuery()의 결과값 중 &#39;data&#39;라는 key값을 입력해야 원하는 데이터를 가져올 수 있으며, const [state, setState] = useState()의 경우에는 이름이 바뀌어도 되지만 순서를 반대로 입력하게 되면 의도한 값을 얻지 못하게 된다.
이러한 비구조화할당을 잘 활용한다면 코드를 짧게 리펙토링 하는데 있어서 매우 유용하게 사용될 것이다.</p>
<h3 id="rest-parameter">Rest-Parameter</h3>
<p>객체에서 특정 값을 지우고 싶을때, delete를 사용할 수 있다. 하지만 delete를 사용한다면 원본의 값에도 영향을 주어 나중에 의도치 않은 결과를 얻을 수 있다. 따라서 원본에 영향을 주지 않게끔 수정을 하는것이 바람직하다.
이렇게 원본을 건들지 않고 값을 삭제하기 위해 rest-parameter를 스프레드연산자(...rest)를 사용한다.</p>
<blockquote>
<p>ex&gt; {지우려는값1, 지우려는값2, ...rest}를 사용한다면 지우려는값1,2를 제외한 새로운 rest라는 객체가 담기게되고 rest는 변수명으로 우리가 원하는 이름으로 설정할 수 있다.</p>
</blockquote>
<h3 id="custom-hooks">Custom-hooks</h3>
<p>Hook이란 함수형 컴포넌트에서 사용되는 state 기술들의 모음이라 할 수 있다. useEffect(), useRef() 등 use로 시작하는 hook들을 우리가 직접 만들어서 사용하는 것을 Custom-hook이라고 한다.
Custom-hook들의 대표적인 예로는 해당 컴포넌트를 실행하기 전에 먼저 실행시켜 우리의 조건에 부합하는지(로그인이 되어있는지) 검증해주는 함수를 컴포넌트로 만들어주고 이렇게 만든 컴포넌트를 실행하고자 하는 컴포넌트에 적용시키면 함수가 먼저 실행되어 검증을 할 수 있게 된다.
또한 페이지 이동을 관리할 수 있는 Hook도 있다. 기존의 페이지 이동 기능 구현과 큰 차이는 없지만, 해당 기능을 Hook으로 따로 관리한다면 코드가 간결해지고 유동적으로 사용이 가능해지며, 유지보수가 용이해진다. 예를들어 페이지 이동 함수를 컴포넌트로 만들고 함수에 전에 있었던 페이지를 state값으로 저장을 해놓는다면 로그인이 필요한 페이지에서 로그인을 하고나서 로그인버튼에 이전페이지가 들어가있는 state를 저장해놓음으로써 로그인 후 전에 있던 페이지로 바로 이동을 시켜주는, 조금 더 유연한 서비스를 제공할 수 있게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 24일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-24%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-24%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 16 Feb 2022 07:15:18 GMT</pubDate>
            <description><![CDATA[<h3 id="useapolloclient">useApolloClient</h3>
<p>쿼리는 컴포넌트가 열리면 실행되는 useQuery,
원하는 시점에 실행 해줄 수 있는 useLazyQuery,
axios처럼 원하는 위치에서 받을 수 있게 도와주고 결과를 내가 원하는 변수에 담아 줄 수 있는 useApolloClient</p>
<p>원하는 시점에 query요청을 보내고 useApolloClient의 특징을 활용한다면 fetch된 데이터의 결과값을 Globalstate에 담아 사용할 수 있다.</p>
<pre><code>      const resultUserInfo = await client.query({
        query: FETCH_USER_LOGGED_IN,
        context: {
          headers: { Authorization: `Bearer ${accessToken}` },
        },
      });</code></pre><p>client.query({})로 요청을 보내고, 어느 정보를 불러올지 인증 정보를 함께 보내야 하기 때문에 client.query의 contextdml headers에 Authorization 정보를 함께 첨부해 주었다.</p>
<h3 id="react-hook-form">React-Hook-Form</h3>
<p>스프레드연산자, onChangeInput, state 등의 폼들을 미리 만들어 놓고, 라이브러리 형태로 제공해 주는 것이 폼 라이브러리 인데, 그 중 최근 함수형 컴포넌트에서 가장 많이 사용되는 폼 라이브러리이다.
React-Hook-Form은 비제어 컴포넌트 방식으로, 제어컴포넌트 방식보다 100% 정확도 보장할 수는 없지만 state값이 바뀌는 상황마다 렌더링 하는 과정이 없기 때문에 빠른 장점이 있다.</p>
<h3 id="yup">yup</h3>
<p>검증 라이브러리로 정규표현식 또는 length를 기준으로 한 최소/ 최대글자수, 이메일 형식 확인 등의 조건을 쉽게 추가할 수 있다. 또한, 검증 라이브러리와 폼 라이브러리는 서로간에 독립적으로 사용될 수 있다.
hookform/resolvers yup을 설치를 하게 되면 react-hook-form과 yup을 함께 사용할 수 있게된다.
yupResolver()를 useForm({}) 내부 resolver에 넣어주고, 규칙들을 schema라는 변수에 지정해주어 yup.object().shape({})설정을 한다면 입력값의 규칙을 정해줄 수 있다.
formState안에 isValid라는 키값이 있는데 조건들을 모두 만족할 경우 참을 반환하므로 formState.isValid를 활용하여 값이 모두 올바르게 입력되었는지 검증할 수 있다.</p>
<h3 id="common-componenet">Common-Componenet</h3>
<p>자주쓰이는 input태그와 button태그의 경우 컴포넌트로 따로 만들어 놓고 import하여 사용하는 것을 공통컴포넌트라고 한다. 이렇게 함으로써 특별한 날, 혹은 다른 이유로 인해 전체적인 화면 분위기를 변경해야할때 Common-Component를 변경한다면 해당 컴포넌트가 포함된 모든 태그들이 모두 변경된 설정으로 적용이 된다.</p>
<pre><code>const schema = yup.object().shape({
  email: yup
    .string()
    .email(&quot;이메일 형식이 아닙니다.&quot;)
    .required(&quot;이메일은 필수입력사항입니다&quot;),
  password: yup
    .string()
    .min(4, &quot;비밀번호는 최소 4자리 이상 입력해 주세요.&quot;)
    .max(15, &quot;비밀번호는 15자리를 넘어갈 수 없습니다.&quot;)
    .required(&quot;비밀번호는 필수입력사항입니다.&quot;),
});

export default function ReactHookFormYupPage() {
  const { register, handleSubmit, formState } = useForm({
    mode: &quot;onChange&quot;,
    resolver: yupResolver(schema),
  });

  const onClickSubmit = (data: FormValues) =&gt; {
    console.log(data);
  };

  return (
    &lt;form onSubmit={handleSubmit(onClickSubmit)}&gt;
      &lt;div&gt;
        &lt;Input01 type=&quot;text&quot; register={register(&quot;email&quot;)} /&gt;
        &lt;div&gt;{formState.errors.email?.message}&lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;Input01 type=&quot;password&quot; register={register(&quot;password&quot;)} /&gt;
        &lt;div&gt;{formState.errors.password?.message}&lt;/div&gt;
      &lt;/div&gt;
      &lt;Button01 type=&quot;submit&quot; isValid={formState.isValid} name=&quot;로그인&quot; /&gt;
    &lt;/form&gt;
  );
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 23일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-23%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-23%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 15 Feb 2022 05:16:57 GMT</pubDate>
            <description><![CDATA[<h3 id="nextjs-렌더링">Next.js 렌더링</h3>
<p>어제 로그인의 역사와 프로세스에 대한 전반적인 이해를 배웠고 로그인을 구현해보는 과정을 거쳤다. 오늘은 로그인을 위한 accessToken을 브라우저가 아닌 브라우저 저장소에 저장하는 법에 대해 알아보자.</p>
<p>대표적인 브라우저 저장소로는 3가지가 있다.
Cookie, localStorage, sessionStorage</p>
<blockquote>
<p>Cookie: 영구저장되지만 만료시간을 지정할 수 있으며, 보안을 강화할 수 있는 옵션들이 존재한다.
localStorage: 영구저장되며, 보안이 좋지 않다.
sessionStorage: 브라우저가 종료시에 저장되어있는 정보들이 사라진다.</p>
</blockquote>
<p>이번 시간에는 보안상 문제가 좋지 않지만, 원할한 개발을 위해 임시로 localStorage에 저장시키는 법을 알아보자. </p>
<p>vsCode에서 accessToken을 얻게 되면 그 값을 localStorage.setItem(&quot;key값&quot;, value값)을 사용하게되면 해당 accessToken이 value에 저장이되고, .getItem(&quot;key&quot;)를 입력하게 되면 value값을 불러올 수 있게된다.
여기서 Next.js의 렌더링과 관련된 이슈가 생긴다.</p>
<p>Next.js의 경우에는 브라우저로부터 요청이 오면 프론트엔드 컴퓨터에서 브라우저에 html, css, js 을 넘겨주는데, 넘겨주기 전에 미리 그려본 후 (Pre-rendering) 브라우저에 그려준 뒤, 비교하고(diffing) 변경사항을 적용(hydration)한다.
프론트엔드 컴퓨터에는 브라우저저장소인 localStorage가 없어서 오류가 뜨게 되는데 3가지 조건을 통해 이 오류를 해결할 수 있다.</p>
<blockquote>
<p>process.browser, typeof window !== &quot;undefined&quot;, useEffect</p>
</blockquote>
<h3 id="hoc--hof">HOC / HOF</h3>
<p>앞서 배운 내용들을 토대로 권한분기를 분리하는데 우리는 로그인을 한 유저와 로그인을 하지 않은 유저를 구분하는 권한 분기를 사용할 수 있다. 대표적으로는 사용자(User) 프론트앤드 서버, 관리자 프론트앤드 서버로 나뉘며 배달의 민족의 경우에는 배민 라이더용 프론트앤드 서버, 구매자용 프론트앤드 서버, 점주 프론트앤드 서버등 최소 3개 이상의 권한분기를 사용한다.
우리는 useEffect를 사용하여 accessToken이 없으면 login을 하게끔 페이지를 이동시켜줬는데 로그인이 필요한 모든 페이지에 로직을 입력해 주어야 한다는 문제가 생긴다. 이를 위해 HOC(Higher Order Component)를 사용한다.
HOC를 알기 위해선 HOF(Higher Order Function)를 알아야하고 HOF를 알기 위해서는 클로저(closure)의 개념을 알아야 하고 클로저(closure)를 알기 위해서는 스택(stack)구조와 스코프(scope) 개념에 대해 알아야 한다. 스택 구조는 First-In/Last-Out구조로 먼저 실행되는 순서대로 쌓이는 구조이다. 스코프 체인을 통해 Local에서 Closure(가장 가까운 외부함수)에서 Global 순으로 변수의 해당 값을 찾기 위해 올라간다. 즉, 클로저는 외부 함수에 접근할 수 있는 내부함수를 의미한다.</p>
<p>HOC와 HOF의 차이는 Component와 Function의 차이로 JSX를 return하면 Component, 그렇지 않으면 Function 이라 할 수 있다.</p>
<p>HOF를 사용하면, event.target.id를 사용하지 않아도 되므로 코드가 짧아지는 장점이 있으며, id가 남용되면서 대규모 서비스에서 예기치 못한 오류를 방지할 수 있다.</p>
<p>HOC는 특정 컴포넌트를 실행하기 전에 상위 컴포넌트를 먼저 실행시켜 주는 것이다. 이렇게 되면 HOC라는 컴포넌트를 하나 만들어놓고, 로그인이 필요한 컴포넌트 앞에 HOC만 붙여주면 간단하게 권한처리가 끝난다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 22일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-22%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-22%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 14 Feb 2022 05:23:18 GMT</pubDate>
            <description><![CDATA[<p>로그인 프로세스</p>
<p>초기의 로그인 프로세스 방식</p>
<blockquote>
<ol>
<li>사용자가 브라우저에서 백엔드로 email과 password를 전송한다.</li>
<li>백엔드 컴퓨터에서 Login API를 받게되면 해당하는 DB를 찾는다.</li>
<li>백엔드 컴퓨터 메모리에 로그인 상태를 저장한다.(Session에 저장한다)</li>
<li>그 후 백엔드 컴퓨터에서 브라우저(유저)한테 암호화된 문자열을 보내준다.</li>
<li>유저가 로그인 권한이 필요한 서비스(결제, 프로필 업데이트 ...)을 실행할 때 백엔드 컴퓨터에 암호화된 문자열을 포함한 email과 password를 보낸다.</li>
<li>백엔드 컴퓨터에서 받은 암호화된 문자열이 상용자가 일치하면 해당 서비스를 진행한다.</li>
</ol>
</blockquote>
<p>하지만 서비스가 많아지고 유저가 증가함에 따라 백엔드 컴퓨터에서 처리해야 하는 api가 점차 증가하게 되면서 백엔드 컴퓨터의 cpu와 memory의 스펙을 높여나갔는데, 이를 <strong>Scale-u</strong>p이라고 한다.</p>
<p>하지만 Scale-up만으로도 서비스가 원활히 진행이 되지 않게되어 같은 api를 가지고 있는 백엔드 컴퓨터를 복사하여 서비스를 진행하는 것을 <strong>Scale-out</strong>이라고 한다.
여기서도 문제가 일어난다. 백엔드 컴퓨터를 복사하더라도 백엔드 컴퓨터의 메모리(Session)에 로그인 여부의 상태가 저장되어 있기 때문에 &#39;철수&#39;라는 사람이 백엔드 A 컴퓨터에 로그인상태가 저장되어 있는데 백엔드 B 컴퓨터에 요청을 하게 될 경우 로그인 후 가능한 서비스들을 이용 못하게 된다.
그래서 메모리(Session)에 로그인 상태를 저장하지 않고, DB컴퓨터에 로그인 상태를 저장하였고 이를 통해 Scale-out을 가능하게 했는데 이를 <strong>Stateless</strong> 되었다고 한다.
하지만 이는 백엔드 컴퓨터로 몰리던 접속량이 DB로 옮겨졌을 뿐, 근원적인 문제가 해결되지 않았다.
DB의 경우에는 복제를 하는데 매우 많은 용량과 비용이 요구되기 때문에 복제하는것이 쉽지 않아 나오게 된 방법이 <strong>데이터 파티셔닝</strong>이다. 테이블 형태의 데이터베이스를 가로로 자르는 것을 수평 파티셔닝(데이터베이스 샤닝)이라 하고 세로로 자르는 것을 수직파티셔닝 이라 한다. DB에 저장한다는 것은 Memory가 아니라 Disk에 저장하게 되는 것으로 안전하지만 속도가 느리다는 단점이 있다. 그래서 DB와 백엔드 컴퓨터 사이에 Memory저장 방식인 Redis를 사용하게 되면 처음에 로그인을 하면서 받은 암호화된 문자열을 브라우저의 cookie, state, localstorage, sessionstorage와 같은 memory에 저장시키고, 문자열이 필요한 서비스를 사용할 때 같이 보내는 방식을 사용하게 된다.</p>
<p>이 후 브라우저에서 이메일, 패스워드를 입력하여 백엔드로 해당 데이터들을 보내고, 백엔드 컴퓨터에서 DB에서 해당하는 데이터가 있는지 확인한 후에 있다면 백엔드 컴퓨터에서 로그인 만료시간을 포함한 자바스크립트의 객체형태의 문자열(JSON)형식으로 저장하고 이를 암호화하여 이 암호화된 문자열을 토큰으로 보내주게 된다. <strong>객체 형태의 문자열로 받은 암호화된 문자열을 JWT토큰</strong>이라고 한다. 이렇게 된다면 백엔드 컴퓨터에서 암호화된 문자열을 복화하 하였을 때 로그인 만료시점이 포함되어 있다면, 이미 로그인이 되어 있는 상태라고 확인을 할 수 있기 때문에 DB가 없어도 로그인 여부를 확인할 수 있게 된다.</p>
<p>로그인을 통해 토큰을 얻는 과정을 인증(Authentication)과정 이라하고 이렇게 얻은 토큰을 활용하여 여러가지 권한을 얻는 것을 인가(Authorization)이라 한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 21일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-21%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-21%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 11 Feb 2022 06:04:45 GMT</pubDate>
            <description><![CDATA[<h3 id="정규표현식">정규표현식</h3>
<p>특정한 규칙을 가진 문자열의 집합을 표현하는데 사용하는 형식 언어이다.</p>
<p><strong>사용법</strong></p>
<blockquote>
<p>/조건/.test(확인하고자 하는 값)</p>
</blockquote>
<p>슬레쉬(/) 안에 들어가는 조건안에서의 기호들은 다음과 같은 규칙을 가지고 있다.</p>
<pre><code>^ : 입력의 시작부분
$ : 입력의 끝부분
+ : 앞의 표현식이 1회 이상 연속으로 반복되는 것을 의미
{3} : 앞의 표현식이 3번 나타나는것을 의미
\w : 밑줄 문자를 포함한 영숫자 문자를 의미. [A-za-z0-9]와 동일
\W : 단어 문자가 아닌 문자에 대응 [^A-za-z0-9_]와 동일
. : 모든을 의미
\ : 원래 가지고 있는 기능을 상실시킴 ex&gt; \. 일 경우에 단순 . 을 의미
? : 앞의 표현식이 0 또는 1을 의미

</code></pre><p>조건을 알맞게 넣고 .test(확인하고자 하는 값)을 실행한 경웨 해당 조건에 부합하면 &#39;true&#39;를 틀리면 &#39;false&#39;를 return한다.</p>
<h3 id="context-api">Context-api</h3>
<p>React 컴포넌트 트리 안에서 <strong>global이라고 볼 수 있는 데이터를 공유할 수 있도록 고안된 방법</strong>으로, context를 이용하면 컴포넌트 하나하나 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다.</p>
<p>일반적인 React에서 데이터는 위에서 아래로 (부모에서 자식으로) props를 통해 전달되지만, 애플리케이션 안의 여러 컴포넌트들에게 전해줘야 하는 props의 경우 이 과정이 매우 번거롭다. context를 이용한다면, 트리 단계마다 명시적으로 props를 넘겨주지 않아도 많은 컴포넌트가 이러한 값을 공유하도록 할 수 있다.</p>
<p><img src="https://images.velog.io/images/junejae_1625/post/fe2ba45f-e0c3-4413-bf04-7452e0c20571/%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%202022-02-11%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.03.26.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 20일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-20%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-20%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 09 Feb 2022 05:47:05 GMT</pubDate>
            <description><![CDATA[<h3 id="검색-프로세스">검색 프로세스</h3>
<p>웹서비스에서의 검색은 Browser에서 검색을 요청하면 Back-end에서 데이터베이스 내부의 데이터들 속에서 요청받은 키워드를 가지고 full-scan하게 되는데, 서비스의 규모가 커짐에따라 데이터가 많아지게되고  데이터가 많아질수록 속도가 느려지게 된다.</p>
<p>이 방법을 개선하기 위해 데이터베이스에 저장할 때, 문장을 키워드 단위로 토크나이징(컴퓨터한테 이해시키기 위해 우리의 언어를 의미가 있는 가장 작은 단어로 나누는 것)하고, 역인덱스를 만들어 저장하게 된다면 특정 키워드에 대한 글들의 검색이 빨라질 것이다.</p>
<p>이런 방식을 쉽게 만들어주는 도구로 <strong>ES(Elastic Search)</strong> 데이터베이스 서비스가 있다.
이는 <strong>디스크 기반의 데이터베이스</strong>로 컴퓨터를 껐다 키더라도 데이터가 유지되므로, 안전하단 장점이 있지만 속도가 느려지게되는 단점이 있다.</p>
<p>서비스가 더 커지게 되면, 무수히 많은 사람들이 검색하는 데이터가 어느정도의 틀에서 크게 벗어나지 않게되는데 이때 검색어와 매칭되는 검색결과를 메모리에 저장한 후에 빠르게 찾아쓸 수 있도록 도와주는 데이터베이스 서비스가 있는데 이를 <strong>Redis</strong>라고 한다.
이는 <strong>메모리 기반의 데이터베이스</strong>로 컴퓨터를 껐다 키면 데이터가 사라지므로 ES(Elastic Search)보다는 덜 안전하지만, 속도가 빠르다는 장점이 있다.
따라서, 검색이 진행될 때, 메모리에 저장되어있다면 Redis를 사용하고 저장되어있지 않다면 ES방식을 사용하면 효율성을 높일 수 있다.</p>
<h3 id="debouncethrottle">Debounce/Throttle</h3>
<p>검색기능을 구현하다보면 검색하기 버튼을 누르지 않아도 해당 관련 검색어들이 검색이 되는것을 볼 수 있다. 이를 구현하는 것은 input태그 안에 onChange함수를 넣어 함수에 event를 인자로 받아 해당 event의 값을 가져오면서 함수를 실행하게끔 하면 된다.
하지만, 이런식으로 기능을 구현하게 된다면 &#39;사자&#39;라는 단어를 치는동안 총 4번 (ㅅ,ㅏ,ㅈ,ㅏ)의 요처을 하게되고 이는 컴퓨터의 효율성 측면에서 매우 떨어지게 된다.</p>
<h3 id="debounce">Debounce</h3>
<p>연이어 발생하는 이벤트를 하나의 그룹으로 묶어 처리하는 방식으로, 주로 그룹에서 마지막 혹은 처음에 처리된 함수를 처리하는 방식으로 사용된다. 즉, 함수를 지연시키고, 지정한 시간 안에 일어난 함수들을 무시하게끔 해준다.
debounce안에 검색어를 입력하는동안 refetch가 지연되게끔 지정해준다면 backend로 보내는 요청을 줄일 수 있다.</p>
<h3 id="throttle">Throttle</h3>
<p>Debounce의 반대의미로, 연이어 발생한 이벤트에 대해 일정한 딜레이를 포함시켜, 연속적으로 발생하는 이벤트를 무시하는 방식으로 사용된다. 즉, 이벤트를 처음에 요청을 하고, 지정한 시간동안은 이벤트를 요청하지 않게끔 해준다.
대표적인 예로는 마우스의 스크롤 기능이 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 19일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-19%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-19%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 08 Feb 2022 05:21:06 GMT</pubDate>
            <description><![CDATA[<h3 id="image-process">Image-process</h3>
<p><img src="https://images.velog.io/images/junejae_1625/post/e734f534-7e66-4caf-8326-6b7e34807b61/123412.png" alt="">
이미지를 데이터베이스에 저장하는 과정은 다음과 같다.
작성자가 input type=&quot;file&quot;에서 파일을 선택하게 되면 그 파일을 Backend컴퓨터에 전송을 하고, Backend에서 검증이 마치면 Storage에 보관을 하게 된다.
이후 Storage에서 해당 이미지파일의 URL값을 Backend컴퓨터로 보내주고, 해당 URL주소를 Backend컴퓨터에서 브라우저로 전송해주고 화면에 띄우게 된다.
이후 해당 주소값을 state에 담아 image 외에 전송해야하는 값들을 포함하여 Backend컴퓨터에 전송하고 Backend컴퓨터에서 DB에 저장하는 과정이 이루어진다.</p>
<h3 id="cloud-storage">Cloud-Storage</h3>
<p>이미지와같이 용량이 큰 데이터의 경우에는 storage에 저장을 하게 되는데, Storage를 제공해주는 서비스 즉, 컴퓨터를 빌려주는 서비스를 Cloud라고 한다.
Cloud 서비스를 제공해주는 Provider의 3대장으로는 Google의 GCP, Amazon의 AWS, Microsoft의 AZURE가 있다.
저장해야할 데이터의 양이 많아질수록 Cloud의 용량을 많이 차지하게되고 이는 곧 비용으로 연결되기 때문에 storage에 저장되는 파일들을 Validation을 할 필요가 있다.</p>
<h3 id="validation">Validation</h3>
<p>말 그대로 검증이라는 뜻으로, 파일을 storage하기 전에 조건들을 걸어놓는 것이다. 예를들어, 파일 용량은 5MB가 넘지 않게끔 한다던지, 확장자 파일은 &quot;jpeg&quot;만 받는다던지 등이 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 18일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-18%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-18%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 07 Feb 2022 06:16:25 GMT</pubDate>
            <description><![CDATA[<h3 id="api만들기">api만들기</h3>
<p>그동안 graphql에서 query와 mutation을 사용하였다. 오늘은 각자 부여받은 포트번호를 활용하여 database에 연결하고 데이터를 직접 조회, 생성하는 법을 알아보자.</p>
<p>우선 apollo-server를 설치하여 요청에 24시간 대기하는 backend서버를 생성한다.</p>
<blockquote>
<p>yarn add apollo-server</p>
</blockquote>
<p>이후 server라는 변수를 만들고 Apolloserver를 새로 만들어준다.
<img src="https://images.velog.io/images/junejae_1625/post/6b35bc18-490a-44c0-b880-cd9e7f2f6f81/%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%202022-02-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.33.32.png" alt=""></p>
<p>연결이 성공되면 실행되는 부분 .then(() =&gt; {})에 server.listn({sever.listen({ port:ㅇㅇㅇㅇ})})를 입력하여 연결 성공시 서버를 실행시킨다. 통상적으로 backend서버는 4000번 혹은 8000번을 사용한다.
<img src="https://images.velog.io/images/junejae_1625/post/004a8b7d-289a-4d6c-93d0-b28d6429bd61/%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%202022-02-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.34.06.png" alt=""></p>
<p>resolvers 안에 자신이 원하는 api를 작성한다.
<img src="https://images.velog.io/images/junejae_1625/post/bbef9a34-4653-4140-9429-4dd0729584d0/%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%202022-02-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.31.36.png" alt=""></p>
<p>작성 혹은 조회가 완료된 후에 실행하게끔 async await를 사용한다.
<img src="https://images.velog.io/images/junejae_1625/post/d3994ae9-28a9-4d04-b562-30c7fd6c8572/%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%202022-02-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.39.53.png" alt=""></p>
<p>타입을 우리가 만들어 적용시켜서 사용하면 해당 값에 예상치 못한 값이 들어오는걸 방지할 수 있기 때문에 타입을 정해준다.</p>
<p>이후 주소창에 연결한 서버주소 localhost:4000 을 실행하여 apollo-server에 들어간 후에 양식에 맞추어 작성을 한다.
<img src="https://images.velog.io/images/junejae_1625/post/fccaddd7-2ac4-4724-a1a8-a80bb81c3f3e/%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%202022-02-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.48.29.png" alt="">
DBeaver를 통해 값이 잘 들어갔는지 확인한다.</p>
<p><img src="https://images.velog.io/images/junejae_1625/post/53346809-61a3-4faf-baea-1d326af50541/%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%202022-02-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.49.55.png" alt=""></p>
<h3 id="firebase">Firebase</h3>
<p>firebase는 backend개발자 없이 frontend개발자가 혼자서 backend서버를 구축하고 database를 관리하할 수 있게끔 도와주는 google에서 지원해주는 BAAS(Backend As A Service)이다. backend개발자가 하는 일 중 하나가 들어오는 데이터들이 안전한지 검증하는 역할이 있는데, firebase 홈페이지에 소스코드를 적어주어 검증을 할 수 있다.
작은사이즈의 프로젝트라면 firebase로도 충분하지만 사이즈가 커지고 무거워질수록 유지보수가 어려워지는 단점이 있다.</p>
<p>firebase 설치</p>
<blockquote>
<p>yarn add firebase</p>
</blockquote>
<p>파이어베이스를 설치한 이후에 파이어베이스의 프로젝트 설정 부분에 들어가면,
<img src="https://images.velog.io/images/junejae_1625/post/1a714e2c-f95e-45ab-a8ca-ce5e98c79f44/%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%202022-02-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.09.13.png" alt="">
부분을 _app.tsx에 넣어준다.</p>
<p>이후 firebase를 사용하고자 하는 페이지에 import한다.</p>
<pre><code>import {
  getFirestore,
  collection,
  addDoc,
  getDocs,
} from &quot;firebase/firestore/lite&quot;;
import { firebaseApp } from &quot;../_app&quot;;



export default function FirebasePage() {
  const onClickSubmit = async () =&gt; {
    // firebase에 한 줄 등록하기

    const board = collection(getFirestore(firebaseApp), &quot;board&quot;);
    await addDoc(board, {
      writer: &quot;철수&quot;,
      title: &quot;제목이라구요&quot;,
      contents: &quot;파이어베이스 너무 어렵당&quot;,
    });
  };
  const onClickFetch = async () =&gt; {
    // firebase에서 데이터 꺼내오기

    const board = collection(getFirestore(firebaseApp), &quot;board&quot;);
    const result = await getDocs(board);
    const docs = result.docs.map((el) =&gt; el.data);
    console.log(docs);
  };
  return (
    &lt;div&gt;
      &lt;h1&gt;파이어베이스 연습 페이지입니다.&lt;/h1&gt;
      &lt;button onClick={onClickSubmit}&gt;등록하기&lt;/button&gt;
      &lt;button onClick={onClickFetch}&gt;조회하기&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>getFirestore, collection, addDoc, getDocs를 firestore/lite에서 import 한다.</p>
<p>onClickSubmit 함수를 버튼에 등록하여 입력해 놓은 값을 버튼을 누르면 firebase의 Firestore Database에 board라는 collection이 생성되고 그 안에 입력한 값들이 들어가있는걸 확인할 수 있다.
<img src="https://images.velog.io/images/junejae_1625/post/e30db919-367e-42cf-a6ef-b708d889a8b2/%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%202022-02-07%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%203.16.03.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 17일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-17%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-17%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 04 Feb 2022 05:30:19 GMT</pubDate>
            <description><![CDATA[<h3 id="database는">DataBase는</h3>
<p><strong>ORM (Object-Relation-Mapping)
ODM (Object-Document-Mapping)</strong>
이 두가지 방식으로 연결할 수 있다.</p>
<p>ORM의 경우에는 데이터를 표(Table) 안에 객체 형태로 행과 열에 담아주며, 데이터들간의 관계를 정해줄 수 있어 관계형 데이터베이스라고 부른다.
대표적으로 <strong>Oracle, MySQL, Postgres</strong>가 있다.</p>
<p>ODM의 경우에는 데이터를 서류봉투(문서)방식으로 담아주며, 표 형식이 아니기 때문에 NotOnlySQL이라 하여 NoSQL이라 한다.
대표적으로 <strong>MongoDB, FireBase</strong>가 있다.
<img src="https://images.velog.io/images/junejae_1625/post/6c024bd5-0657-4ab3-a4ac-24a60c3b5ae5/%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%202022-02-04%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.22.19.png" alt=""></p>
<h3 id="dbeaver">DBeaver</h3>
<p>DataBase를 쉽게 관리할 수 있게 도와주는 관리도구다.
<img src="https://images.velog.io/images/junejae_1625/post/b2b4451d-2033-4101-a918-98d95cb1fb59/%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%202022-02-04%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.25.41.png" alt=""></p>
<p><img src="https://images.velog.io/images/junejae_1625/post/bb4397cf-a022-40b3-bc92-8d36053df422/%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%202022-02-04%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.26.40.png" alt=""></p>
<p>연결하고자 하는 데이터베이스를 선택하고 Host에 해당 IP주소를 입력하고 Password를 입력한 후에 완료를 누르면 해당 데이터베이스들을 볼수 있다.
<img src="https://images.velog.io/images/junejae_1625/post/91a24a43-d8cb-470d-a8cf-687e695242b0/%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%202022-02-04%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.28.31.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 16일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-16%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-16%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 03 Feb 2022 05:37:08 GMT</pubDate>
            <description><![CDATA[<h3 id="useref">useRef()</h3>
<p>React컴포넌트는 기본적으로 state가 setState될때마다 렌더링이 된다. useRef()는 현재 속성을 가지고 있는 객체를 반환하는데, 인자로 넘어온 초기값을 현재 속성에 할당한다. 이 현재 속성은 값을 변경해도 state를 변경할 때 처럼 React컴포넌트가 다시 랜더링되지 않는다.
useRef()는 함수형 컴포넌트에서 사용되며, createRef()는 클래스형 컴포넌트에서 사용된다.
특정 태그를 조작하기 위해 선택할 때 사용하는 도구로, 대표적인 예로는 input태그를 선택하여 커서를 깜빡이도록 하고 싶다면 useRef를 사용하여 input태그를 선택하고, focus() 기능을 활용하여 커서를 깜빡이도록 하면 된다.</p>
<h3 id="useeffect">useEffect()</h3>
<p>React컴포넌트가 렌더링 될 때마다 특정 작업을 실행할 수 있도록 하는 Hook으로, 컴포넌트가 그려진 이후에 실행되는 함수이다.</p>
<p>class형 컴포넌트에서 사용되던 componentDidMount(), componentDidUpdate(), componentWillUnmount()의 기능들을 사용할 수 있게 도와준다.
즉, class형 컴포넌트에서 사용할 수 있었던 생명주기 메소드를 함수형 컴포넌트에서도 사용할 수 있게 해준다.</p>
<blockquote>
<p>useEffect(function, deps)
function: 수행하고자 하는 작업,
deps: 배열 형태이며, 배열 안에는 검사하고자 하는 특정 값 혹은 빈 배열</p>
</blockquote>
<p>useEffect()에서 setState를 사용할 수 있지만 가급적 피하는 것이 좋다.
useEffect()의 경우 컴포넌트가 그려진(마운트된) 이후에 실행되는 함수이다.
컴포넌트가 마운트가 된 이후에 setState를 적용하게 되면, state가 변경되고, 변경된 state로 컴포넌트가 리렌더(다시그려짐)가 되기 때문에 성능에 좋지 않다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 15일차-2]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-15%EC%9D%BC%EC%B0%A8-2</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-15%EC%9D%BC%EC%B0%A8-2</guid>
            <pubDate>Fri, 28 Jan 2022 05:14:36 GMT</pubDate>
            <description><![CDATA[<h3 id="얕은-복사shallow-copy">얕은 복사(Shallow Copy)</h3>
<p>얕은 복사는 주소값을 복사한다. 즉, <strong>원본의 값이나 복사된 값이 변경될 경우 두 값 모두 변경된다.</strong>
<img src="https://images.velog.io/images/junejae_1625/post/1f2016fe-fa97-41fd-bac4-d95683281cf8/%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%202022-01-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.07.52.png" alt="">
b의 one이라는 값을 4로 변경했는데, a의 one까지 4로 변경되는 것을 볼 수 있다.</p>
<h3 id="깊은-복사-deep-copy">깊은 복사 (Deep Copy)</h3>
<p>깊은 복사는 얕은 복사와 달리 주소값을 복사하는 것이 아닌, 전부 복사해 <strong>새 주소에 담아주어 참조를 공유하지 않게 된다.</strong></p>
<p>깊은 복사의 방법으로는 전체를 문자열로 변경한 뒤, 그 문자열을 객체로 되돌리는 방법이 있다.
<strong>JSON.stringify()와 JSON.parse()</strong>를 사용하면 된다.</p>
<p><img src="https://images.velog.io/images/junejae_1625/post/e197b071-4af6-4c19-ada6-41ce91e8697d/%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%202022-01-28%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.13.07.png" alt="">
이렇게 복사를 하게 된다면 원본의 값을 변경하여도 복사된 값에 영향을 주지 않게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 15일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-15%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-15%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 28 Jan 2022 05:01:18 GMT</pubDate>
            <description><![CDATA[<h3 id="무한스크롤-infinite-scroll">무한스크롤 (Infinite Scroll)</h3>
<p>페이지네이션(Pagination)의 다른 방법으로 유튜브 또는 페이스북, 인스타그램과 같이 아래로 스크롤할 때, 계속해서 추가되는 방식의 페이지 처리 방법이다.</p>
<p>라이브러리를 통해서 사용방법을 알아보자.</p>
<blockquote>
<ol>
<li>yarn add react-infinite-scroll</li>
</ol>
</blockquote>
<blockquote>
<ol start="2">
<li>타입스크립트를 사용하기 때문에 타입스크립트 오류를 잡기 위해 yarn add -D @types/react-infinite-scroller를 입력한다.</li>
</ol>
</blockquote>
<blockquote>
<ol start="3">
<li>import InfiniteScroll from &#39;react-infinite-scroller&#39;;</li>
</ol>
</blockquote>
<blockquote>
<p>&lt;InfiniteScroll
    pageStart={0}
    loadMore={loadFunc}
    hasMore={true || false}
    loader={<div className="loader" key={0}>Loading ...</div>}</p>
</blockquote>
<pre><code>{items}</code></pre><p>&lt;/InfiniteScroll</p>
<p> &#39;items&#39; 괄호 안에 보여주고자 하는 코드들을 넣으면 무한스크롤을 통해 화면에 표현할 수 있다.</p>
<p> 윈도우 스크롤을 사용하지 않고 해당 박스 안에서 스크롤을 사용하고자 한다면 박스 태그의 높이를 고정해주고, overflow: &quot;auto&quot;;로 설정해준다.</p>
<p> InfiniteScroll에 useWindow={false} 를 주면 해당 박스 안에 스크롤이 생성된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 14일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-14%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-14%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 27 Jan 2022 05:00:44 GMT</pubDate>
            <description><![CDATA[<h3 id="페이지네이션pagination">페이지네이션(pagination)</h3>
<p>페이지를 처리하는 방법으로는 크게 일반적인 방식과 무한스크롤 방식, 2가지 방법이 있다. 그 중 오늘은 일반적인 방식의 페이지 처리를 알아보자.</p>
<p>일반적이라 하면 페이지 번호를 클릭해서 이동하는 방식의 페이지 처리 방법이다.</p>
<p>우선 시작 페이지 값을 알려줄 state를 생성한다.</p>
<blockquote>
<p>const [startPage, setStartPage] = useState(1);</p>
</blockquote>
<p>페이지 번호를 눌렀을 때 화면을 해당 페이지값으로 재구현 해 줄 함수를 작성한다.</p>
<blockquote>
<p>const onClickPage = (event) =&gt; 
{ if (event.target instaceof Element) 
refetch({page: Number(event.target.id)}); 
};</p>
</blockquote>
<p>한 페이지에 10개씩 보여준다고 했을때 이전 목록으로 이동하게 해주는 함수와 다음 목록으로 이동하게 해주는 함수를 작성한다.</p>
<blockquote>
<p>const onClickPrevPage = () =&gt;{
if (startPage === 1) return;
setStartPage((prev) =&gt; prev -10);
};</p>
</blockquote>
<blockquote>
<p>const onClickNextPage = () =&gt;{
if (startPage + 10 &gt; lastPage) return;
setStartPage((prev) =&gt; prev +10);
};</p>
</blockquote>
<p>여기서 &#39;lastPage&#39;는 게시물이 총 몇개있는지 알려주는 값에 10을 나누고 올림처리를 해서 나오는 수이다. 10을 나누는 이유는 한 페이지에 10개의 게시물을 보여주기 때문이다.</p>
<p>다음으로 .map()을 이용하여 데이터를 뿌려주는 리스트 화면을 만들어준다.</p>
<blockquote>
<pre><code></code></pre></blockquote>
<div>
{data?.해당데이터.map((el) => {
        <div key = {el.id}> {el.뿌려주고자하는 데이터} </div>
})}
</div>
```

<p>다음으로 페이지 이동을 위한 번호와 화살표가 있는 네비게이션을 만들어준다.</p>
<pre><code> &lt;span onClick={onClickPrevPage}&gt; {`&lt;`} &lt;/span&gt;
  {new Array(10).fill(1).map((_, index) =&gt; 
  startPage + index &lt;= lastPage &amp;&amp; (
               &lt;span key={startPage + index}
          onClick={onClickPage}
          id={String(startPage+index)}
          &gt;
          {startPage + index}
  &lt;/span&gt;
  ))}
  &lt;span onClick={onClickNextPage}&gt;{`&gt;`}&lt;/span&gt;</code></pre><p><img src="https://images.velog.io/images/junejae_1625/post/93f32e4e-7598-4946-89b6-01f41c2018c2/%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%202022-01-27%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.59.58.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드캠프 부트캠프 13일차]]></title>
            <link>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-13%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@junejae_1625/%EC%BD%94%EB%93%9C%EC%BA%A0%ED%94%84-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-13%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 26 Jan 2022 05:10:58 GMT</pubDate>
            <description><![CDATA[<h3 id="레이아웃layout">레이아웃(Layout)</h3>
<p>프로젝트 전체의 UI 구조를 의미한다.
즉, Header, Navigation, Menu, Footer, Body 등으로 화면을 분할하는 일을 의미한다.</p>
<p>레이아웃만 잘 잡아도 프로젝트 전체의 유지보수가 쉬워진다. 현재까지 작성했던 각각의 개별 페이지들은 레이아웃의 Body 부분에 모두 넣어주고, 메뉴 등을 클릭하면 Body의 내용만 바꿔주면 깔끔한 구조를 유지할 수 있다.
<img src="https://images.velog.io/images/junejae_1625/post/f300fb5d-26c3-4180-8004-028abec922c7/%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%202022-01-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.54.36.png" alt="">
&#39;props.children&#39;은 우리가 정의를 해준것이 아니라 자동으로 &#39;children&#39;이란 이름으로 props를 받아온 것이다.
<img src="https://images.velog.io/images/junejae_1625/post/faf8259f-ae60-4570-9568-9d4d7a5fb263/%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%202022-01-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.58.59.png" alt="">
헤더영역에는 주황색, 배너부분은 빨강색, 내비게이션 영역엔 하늘색, 사이드바 영역엔 파랑색을 주었다. 이렇게 설정하면 다른 페이지로 이동을 하여도 항상 같은 레이아웃을 유지할 수 있게 된다.</p>
<p>하지만, 특정 페이지에 특정 레이아웃을 보이지 않게 하는 경우가 있을 수 있다. 예를들어 헤더영역에 로그인창이 있었는데 로그인창으로 이동하였을 경우에는 보이지 않게하는 경우가 그럴 때이다.
이럴때는 특정 페이지에서는 레이아웃을 나타내지 않게 하는 조건을 걸어주면 된다.
<img src="https://images.velog.io/images/junejae_1625/post/060685a0-4c30-4974-b797-483dc50ffdc8/%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%202022-01-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.02.07.png" alt="">
이런식으로 사용하게 된다면 &quot;/12-07&quot;페이지와 &quot;/12-09&quot;페이지는 헤더 영역이 보이지 않게 된다.</p>
<h3 id="글로벌-스타일">글로벌 스타일</h3>
<p>글로벌 스타일이란 우리가 만들고있는 모든 컴포넌트에 기본적으로 적용시켜주는 스타일을 의미한다.
기본값으로 font-size: 16px; 혹은 margin: 0px;, box-sizing: border-box; 이런식의 설정을 기본값으로 주어주고자 할때 사용한다.
<img src="https://images.velog.io/images/junejae_1625/post/bdac0565-5208-400d-9f82-a3837fbc2b7e/%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%202022-01-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.06.32.png" alt=""></p>
<p>app.tsx 파일에서 @emotion/react로부터 Global을 import시켜 태그로 사용하고, 속성값으로 styles를 넣어주면 된다.</p>
<p><img src="https://images.velog.io/images/junejae_1625/post/96736e84-31e2-4517-9934-071e5833f757/%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%202022-01-26%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.08.37.png" alt=""></p>
<p>그 다음 @emotion/react로부터 css를 import하여 스타일을 작성해주고, globalstyles를 위의&lt;Global styles={ } /&gt; 안에 넣어주면 css안에 넣어놨던 속성들이 글로벌 스타일로 적용이 완료된다.</p>
]]></description>
        </item>
    </channel>
</rss>