<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>pro-yeong.log</title>
        <link>https://velog.io/</link>
        <description>안녕하세요!</description>
        <lastBuildDate>Sat, 27 Jul 2024 04:20:25 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>pro-yeong.log</title>
            <url>https://velog.velcdn.com/images/pro-yeong/profile/80d4813c-5fa3-4c2b-91f3-fc92fccbeb4a/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. pro-yeong.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/pro-yeong" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[개발 생산성을 높이는 git hooks와 husky]]></title>
            <link>https://velog.io/@pro-yeong/%EA%B0%9C%EB%B0%9C-%EC%83%9D%EC%82%B0%EC%84%B1%EC%9D%84-%EB%86%92%EC%9D%B4%EB%8A%94-git-hooks%EC%99%80-husky</link>
            <guid>https://velog.io/@pro-yeong/%EA%B0%9C%EB%B0%9C-%EC%83%9D%EC%82%B0%EC%84%B1%EC%9D%84-%EB%86%92%EC%9D%B4%EB%8A%94-git-hooks%EC%99%80-husky</guid>
            <pubDate>Sat, 27 Jul 2024 04:20:25 GMT</pubDate>
            <description><![CDATA[<h1 id="git-hook이란">git hook이란</h1>
<p>git hook은 git에서 특정 이벤트가 발생했을 때 자동으로 특정 스크립트를 실행할 수 있도록 해주는 기능이다. git hook은 <code>git init</code> 을 진행하면 생성되는 .git디렉토리 하위의 hooks디렉토리에 저장된다. 실제로 확인해보면 이미 .git/hooks 디렉토리에는 샘플훅들이 등록되어있다.
<img src="https://velog.velcdn.com/images/pro-yeong/post/fab39ef0-3a9b-4c99-849f-93ec0c301c4e/image.png" alt=""></p>
<h2 id="git-hook의-종류">git hook의 종류</h2>
<p>훅은 크게 클라이언트 훅과 서버훅으로 나뉘는데 그 중 내가 사용하고자 하는 것은 클라이언트 훅 그중에서도 커밋과 관련된 훅으로  <code>pre-commit</code> ,  <code>prepare-commit-msg</code>, <code>commit-msg</code>, <code>post-commit</code> 이렇게 네가지가 있다.
순서대로 설명하자면</p>
<p><code>pre-commit</code> : 커밋할 때 가장 먼저 호출되는 훅으로 커밋 메시지를 작성하기 전에 호출된다. 커밋할 때 반드시 지켜야할 사항을 이 훅으로 검사한다. 
<code>prepare-commit-msg</code> : git이 커밋메시지를 생성하고 나서 편집기를 실행하기 전에 실행된다. 일반 커밋보다는 커밋 메시지를 자동으로 생성하는 경우에 유용하다.
<code>commit-msg</code> : 커밋 메시지가 들어있는 임시 파일의 경로를 받아 최종 커밋 상태를 반환하는 스크립트를 실행한다. 이 훅이 0이 아닌 값을 반환하면 커밋되지 않는다.
<code>post-commit</code> : 커밋이 완료될 때 실행되는 훅이다. 일반적으로 커밋을 다른 프로그램에게 알릴 때 사용된다.</p>
<p>그 외에도 
<code>pre-push</code>(git push 명령 실행 시 동작하며  remote 정보를 업데이트 하고 난후 remote로 데이터를 전송하기 전에 동작), <code>pre-rebase</code>, <code>post-merge</code> 훅들과 서버 훅들이 존재한다.</p>
<h2 id="git-hook-생성하기">git hook 생성하기</h2>
<p>우선 테스트를 위해 <code>pre-commit</code> 훅을 등록하여 커밋 시 스크립트를 실행되도록 설정해보았다. .git/hooks 디렉토리에 <code>pre-commit</code>파일을 생성한다. 이미 .sample확장자의 파일이 존재하지만 sample 확장자의 파일을 실행되지 않는다.</p>
<p><img src="https://velog.velcdn.com/images/pro-yeong/post/e6bf6614-1530-468a-9bc1-10b46d7e63c8/image.png" alt=""></p>
<p><code>pre-commit</code> 파일은 간단하게 echo을 사용하여 문자열을 출력하게 하였다.
<img src="https://velog.velcdn.com/images/pro-yeong/post/9a101a1f-0961-4f76-bd49-76ee8f7a012b/image.png" alt=""></p>
<p>파일 생성을 완료하였다면,<code>chmod</code> 명령어를 이용하여 파일 실행권한을 부여한다. </p>
<p><img src="https://velog.velcdn.com/images/pro-yeong/post/ef567ba9-0c91-49e9-b5a4-d10dfaf61bcc/image.png" alt="">
이제 commit을 시도하면 등록한 문자열이 잘 출력되는 것을 확인 할 수 있었다.
<code>pre-commit</code> 훅은 exit코드가 0이 아닌 경우 commit이 취소되기 때문에 실제로 commit은 진행되지 않은것 까지 확인할 수 있다!</p>
<h2 id="husky">husky</h2>
<p>위에서 설명한 git hook은 매우 유용하지만 설정하기 번거롭고 이그노어되어있는 파일들을 프로젝트로 관리하기도 상당히 까다롭다.
이러한 git hook의 설정을 도와주는 npm 패키지가 바로 <a href="https://typicode.github.io/husky/">husky</a>이다.</p>
<p>husky는 git hook설정을 도와주며 프로젝트 단위로 git hook을 편리하게 관리하도록 지원한다.</p>
<h3 id="husky-설정하기">husky 설정하기</h3>
<p>husky 설정방식은 매우 간단하다.<code>npm install --save-dev husky</code> 로 허스키를 설치 후 <code>husky init</code> 명령어로 프로젝트에 husky를 설정한다. 
<code>husky init</code> 을 실행하면 package.json에 <a href="https://docs.npmjs.com/cli/v10/using-npm/scripts">prepare 스크립트</a>가 추가되며 초기설정으로 <code>pre-commit</code> 스크립트 파일이 생성된다.</p>
<blockquote>
<p>prepare : 패키지가 패킹되기 전, 즉 npm 게시 및 npm 패킹 중 혹은 로컬 npm install 실행시 실행되는 스크립트.</p>
</blockquote>
<h3 id="lint-설정-추가하기">lint 설정 추가하기</h3>
<p>husky설정이 다 되었다면 실제로 사용할 훅을 등록해볼 차례다.
commit시 자동으로 린트 검사를 실행하기 위해 package.json내 스크립트에 lint 스크립트를 추가한 후 <code>pre-commit</code> 파일에 린트 명령어를 추가하였다. </p>
<p>새로운 훅을 등록할 때 아래 명령어를 실행하면 간편하게 훅 등록이 가능하다.
<code>echo &quot;npm run lint&quot; &gt; .husky/pre-commit</code></p>
<p>이제 다시 commit을 시도하면 lint명령어가 실행되며 잘못된 코드들이 있는 경우 오류가 발생하며 commit이 진행되지 않음을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/pro-yeong/post/df823e7d-7efa-4231-8c25-a581b1ff3184/image.jpg" alt=""></p>
<h2 id="정리하며">정리하며</h2>
<p>husky와 git hook을 설정하며 생각보다 간단한 설정에 놀랐고 좋은 툴을 미리 활용하지 못한점에 아쉬움이 남았다. git hook과 husky을 잘 활용한다면 팀원들과 유용한 훅들을 등록하고 공유하며 자유롭게 설정할 수 있어 유용할것이라 생각이 든다.</p>
<h2 id="참고">참고</h2>
<p><a href="https://git-scm.com/book/ko/v2/Git%EB%A7%9E%EC%B6%A4-Git-Hooks">Git Hooks</a>
<a href="https://naamukim.tistory.com/18">git hooks 설정으로 팀 효율 높이기</a>
<a href="https://typicode.github.io/husky/">husky</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트에서 다중 상속이 가능할까?]]></title>
            <link>https://velog.io/@pro-yeong/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%97%90%EC%84%9C-%EB%8B%A4%EC%A4%91-%EC%83%81%EC%86%8D%EC%9D%B4-%EA%B0%80%EB%8A%A5%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@pro-yeong/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%97%90%EC%84%9C-%EB%8B%A4%EC%A4%91-%EC%83%81%EC%86%8D%EC%9D%B4-%EA%B0%80%EB%8A%A5%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Tue, 11 Jun 2024 01:31:02 GMT</pubDate>
            <description><![CDATA[<p>커뮤니티를 구경하다 &quot;자바스크립트에서 다중 상속이 가능한가?&quot;라는 질문에 대한 글을 보게 되었다.</p>
<p>사실 &quot;예&quot;, &quot;아니요&quot;로도 답할 수 있는 간단한 질문이지만 자바스크립트를 사용하면서도 클래스를 자주 사용하지 않았기 때문에 해당 질문이 낯설게 느껴졌다.
프로토타입을 비롯해 자바스크립트의 기본 개념을 많이 잊어버렸다는 반성의 시간을 가지며 다시 하나하나 정리해 보고자 한다.</p>
<hr>
<p>우선, 다중 상속이란 어떤 클래스가 두개 이상의 클래스를 상속받는 것을 말한다. 위키백과에 따른 정의는 아래와 같다.</p>
<blockquote>
<p>다중상속(Multiple inheritance)이란 객체 지향 프로그래밍의 특징 중 하나이며, 어떤 클래스가 하나 이상의 상위 클래스로부터 여러 가지 행동이나 특징을 상속받을 수 있는 것을 말한다.</p>
</blockquote>
<p>클래스의 다중 상속이라는 문장을 처음 보았을때 과거 자바에서  클래스를 하나만 상속하였던 것과 타입스크립트 선언 시 extends 로 여러개의 인터페이스를 연결하였던 것이 떠올랐다. </p>
<h3 id="1-자바에서-클래스-상속은-하나만-가능한가">1. 자바에서 클래스 상속은 하나만 가능한가?</h3>
<p>자바스크립트의 클래스 상속을 찾아보기 전에, 다른 객체 지향 프로그래밍 언어인 자바를 우선 찾아보았다. 결론부터 말하자면 Java는 클래스로부터 다중 상속을 허용하지 않는다. 다중 상속의 가장 큰 문제인 <a href="https://f-lab.kr/insight/solving-java-diamond-problem">다이아몬드 문제</a> 가 발생할 수 있기 때문이다.
반면, 파이썬,C++등은 다중상속울 지원한다. 파이썬은 다이아몬드 상속에 대한 해결책으로 메서드 탐색순서(MRO)를 통해 클래스 순서에 따라 메서드를 사용한다.</p>
<h3 id="2-타입스크립트의-interface는-여러개를-상속할-수-있다">2. 타입스크립트의 interface는 여러개를 상속할 수 있다?</h3>
<p>그렇다. 타입스크립트의 인터페이스는 다중 상속이 가능하다. 그리고 자바의 인터페이스 모두 다중 상속이 가능하다. 이유는 인터페이스는 기능에 대한 선언만 해두는 것이기 때문에 다이아몬드 상속으로 인한 오류가 발생하지 않기 때문이다. 다만 각 인터페이스에 속성 명이 동일한 속성의 타입이 동일하지 않은 경우에는 오류가 발생한다. </p>
<h3 id="3-자바스크립트에서-클래스-다중-상속을-시도하면-어떻게-될까">3. 자바스크립트에서 클래스 다중 상속을 시도하면 어떻게 될까?</h3>
<p>당연히 오류가 발생한다. 다만 어떠한 방식으로 어떤 오류 메시지가 출력되는지 궁금하여 다중상속을 테스트해보았다.</p>
<pre><code>class Person {
  talk(){}
}
class Student {
 talk(){}
}
class Me extends Student, Person{} 
//SyntaxError: Unexpected token &#39;,&#39;
</code></pre><p>실행 결과는 역시 오류가 발생하였지만 런타임에서 오류가 발생할 것이라는 예상과 다르게 문법 오류가 발생하였다. </p>
<h3 id="4-그렇다면-자바스크립트에서-다중-상속은-절대-불가능한가">4. 그렇다면 자바스크립트에서 다중 상속은 절대 불가능한가?</h3>
<p>문법상으로는 그러하나, 다른 방법으로 구현이 가능하다. 믹스인을 사용하여 다중상속처럼 구현이 가능하다. 
믹스인은 다른 클래스를 상속받을 필요 없이 이들 클래스에 구현되어 있는 메서드를 담고 있는 클래스라고 정의된다. 
믹스인을 활용하면 특정 클래스를 상속받는 동시에, 다른 믹스인의 메서드도 사용할 수 있다.</p>
<hr>
<p>출처</p>
<p><a href="https://ko.wikipedia.org/wiki/%EB%8B%A4%EC%A4%91_%EC%83%81%EC%86%8D">위키백과 - 다중 상속</a></p>
<p><a href="https://f-lab.kr/insight/solving-java-diamond-problem">자바의 다이아몬드 문제와 인터페이스를 통한 해결 방법
</a></p>
<p><a href="https://ko.javascript.info/mixins">javascript-ifno - 믹스인
</a></p>
<p><a href="https://jake-seo-dev.tistory.com/697">제이크서 위키 블로그- 타입스크립트 타입, 인터페이스 상속과 오버라이딩
</a></p>
<p><a href="https://www.linkedin.com/posts/%EB%AC%B8%EB%8C%80%EC%8A%B9_%EB%A9%B4%EC%A0%91-%EB%95%8C-%EC%9E%98%EB%AA%BB-%EB%A7%90%ED%95%9C-%EA%B8%B0%EC%88%A0-%EC%A7%88%EB%AC%B8-%EB%8B%B5%EB%B3%80%EB%93%A4-%EC%9D%B4%EC%A0%9C%EB%B6%80%ED%84%B0%EB%8A%94-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EB%8B%B5%EB%B3%80%ED%95%98%EC%9E%90-activity-7203154039369269249-KOG_?utm_source=share&amp;utm_medium=member_desktop">면접 때 잘못 말한 기술 질문 답변들 - 이제부터는 제대로 답변하자
</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[폴더 구조 정리하기]]></title>
            <link>https://velog.io/@pro-yeong/react-%EA%B5%AC%EC%A1%B0-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@pro-yeong/react-%EA%B5%AC%EC%A1%B0-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 15 Jan 2023 14:17:08 GMT</pubDate>
            <description><![CDATA[<p>이번에 프리온보딩 챌린지를 진행하며 1주차에 관심사의 분리에 대한 세션을 진행하였다.
항상 프로젝트를 진행하며 많은시간을 폴더의 구조 고민에 할애하지만 막상 크게 마음에 드는 구조를 적용한적은 없었다.</p>
<p>이번 기회에 앞으로도 계속 사용할 수 있도록 적절한 구조를 정하자고 마음 먹었다.</p>
<h3 id="가장-좋은-방법을-찾자">가장 좋은 방법을 찾자?</h3>
<p>구조를 잡기 위해 여러 오픈소스, 그리고 같이 챌린지에 참여한분들의 git ,구글링등등을 모두 뒤져보고 느낀것은 구조의 정답은 없다는 것이다.
코드가 작성된 시기에 따라 유행한 구조는 있는것 같지만, 그 사이에서도 어느정도 차이가 존재하였다. </p>
<p>이것저것 찾아보다 내린 결론은 여러 리소스를 참고하되, 내가 편한 구조를 잡는 것이었다.
우선 directory가 많아지고, depth가 깊어지고 등등의 문제를 고민하기보다 내가 알아보기 쉬운 구조를 잡고 그 이후 수정을 거쳤다.</p>
<h3 id="최종적으로-잡은-구조는">최종적으로 잡은 구조는</h3>
<p>아래 이미가 현재 사용중인 구조이다.
<img src="https://velog.velcdn.com/images/pro-yeong/post/2aba98a2-15fb-4f1b-8b65-ffc9105adc6b/image.png" alt=""></p>
<p>사실 해당 구조에도 확신은 없지만, 어떤것이 어디에 있는지 가장 정리가 잘되는 구조였다.
흔히 사용되는 구조와 유사하고 엄격히 지키기 보다 유연하게 사용하고자하였다.</p>
<h3 id="비즈니스-로직의-분리은-신경쓰자">비즈니스 로직의 분리은 신경쓰자</h3>
<p>대부분의 구조는 상황에 따라(ex styles 폴더 분리여부?)유연하게 사용하려 하지만, 비즈니스 로직 분리는 꼭 일정한 규칙을 가져가려고 한다.
예전에는 props를 이용해 하위컴포넌트로 비즈니스 로직을 분리하고 처리하는것을 선호하였는데,  최근 커스텀 hook을 이용해 비즈니스로직들을 분리할 수 있다는것을 알게되어서 아주 잘 활용중이다.
다만 이렇게 특정 도메인에 국한된 커스텀훅을 lib 하위로 빼는것이 아니라 사용되는 component 하위에 위치시켜서 도메인 별로 로직파악이 용이하게 하였다.</p>
<h3 id="import-는-절대경로">import 는 절대경로</h3>
<p>폴더를 정리 후, pages 컴포넌트내에서 하위 컴포넌트를 호출할때, 상대경로 사용시에는 import 코드가 지저분하다는 생각이 들었다.
또한 ../../로 연결되는 구조는 구조 파악에도 어려움이 있었다.
다행히도 typeScript로 간단히 해결할 수 있었다. 
typeScript 설정으로 baseUrl을 src로 설정하고 path를 지정해, src 하위 폴더명으로 호출이 가능하게 되었다.</p>
<p><img src="https://velog.velcdn.com/images/pro-yeong/post/22716062-623b-4bec-abc1-b8a18db295db/image.png" alt=""></p>
<p>드라마틱한 변화는 아니지만 import가 많을 수록 빛을 발할것이라 믿는다...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[제너레이터 함수]]></title>
            <link>https://velog.io/@pro-yeong/%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@pro-yeong/%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%95%A8%EC%88%98</guid>
            <pubDate>Sun, 17 Jul 2022 16:06:26 GMT</pubDate>
            <description><![CDATA[<p>redux-saga를 사용방법을 보다보면 제너레이터 문법이 등장한다.
현재는 redux thunk만을 사용하고 있지만 saga로 전환을 고민하고 있기에 제너레이터 문법에 대해 우선 학습하고자 한다.</p>
<p>그렇다면 </p>
<h2 id="제너레이터-문법이란">제너레이터 문법이란?</h2>
<p>제너레이터 문법이란 제너레이터 함수 라는 특별한 문법으로 생성되는 객체이다. </p>
<h3 id="제너레이터-함수란">제너레이터 함수란?</h3>
<p>제너레이터 객체를 반환하는 특별한 함수로 <code>function*</code> 이라는 문법을 사용해서 정의되는 함수이다.
내부에서 yield 라는 특별한 키워드를 사용한다. </p>
<p>일반적으로 함수는 하나 또는 아무값도 반환하지않는다(void).  그러나 제너레이터함수와 그 반환 객체 제너레이터를 활용하면 여러개의 값을 순차적으로 반환할 수 있다.</p>
<p>예를들어 </p>
<pre><code>function* generateSomething(){
    yield 1;
    yield 2;
    return 3;
}
const generator = generateSomething();</code></pre><p>위 코드를 실행하면 generator 변수에 제너레이터 객체가 담기게 된다. </p>
<h3 id="제너레이터--객체">제너레이터  객체</h3>
<p>제너레이터 객체는 각각 next()라는 메서드를 가지고 있다. 이 next메서드를 실행하면 원본 함수에서 아직 미실행된 yield중 가장 가까운 yield문을 만날때까지 함수가 실행된다. 그리고 yield를 만나면 함수 실행이 중단되고 yield에 해당하는 반환된다. 
정확히는 value , done의 키값을 가진 객체가 반환된다.</p>
<p>우리는 이러한 형태(next메서드와 value,done객체)를 많이 봐았다. 바로 이터레이터 객체이다. 
간단하게 이터레이터 객체를 복습하자면</p>
<blockquote>
<p>이터레이터 객체
:  Symbole.iterator가 호출되었을때 반환되는 객체로서 next()라는 메서드를 키값으로 가진다. 각각의 next는 value와 done을 반환하며 done 이 true일 때 반복이 종료됨을 의미한다.</p>
</blockquote>
<p>위와 같은 이터레이터 객체를 보았을때 제너레이터 객체는 이터레이터 객체와 거의 유사함을 알 수 있다. </p>
<p>또한 next메서드를 가진 가진 제너레이터 객체를 통해 반복이 가능하므로 이터러블이라고도 표현할 수 있다.</p>
<h2 id="제너레이터-사용하기">제너레이터 사용하기</h2>
<p>그렇다면 이러한 제너레이터 객체를 어떻게 사용할 수 있을까. 
위에 서술했듯이 제너레이터 객체는 next메서드를 가졌으며 이를 통해 함수의 반환값을 얻을 수 있다. 
위에 예시로 든 코드에서 <code>generateSomething</code> 함수를 대상으로 예시를 보자.</p>
<pre><code>const generator = generateSomething();
let first  = generator.next();
console.log(first) // {value : 1 , done : false}

let second  = generator.next();
console.log(second) // {value : 2 , done : false}

let third = generator.next();
console.log(third); // {value : 3 , done : true}

let fourth = generator.next();
console.log(fourth); // {value : undefined, done : true}
</code></pre><p>처음으로  <code>generaotr.next()</code> 를 실행한다면 가장 첫번째 값 1이 반환 될 것이다. 그리고 다른 yield가 남아있으므로  <code>done:false</code>이다.
현재 함수는 첫번째 줄에 멈춰있는 상태이다. 
다음으로  <code>generaotr.next()</code>를 실행하면 두번째 반환값인 2가 반환되며  아직 함수가 종료되지않아서 <code>done:false</code>이다. 
다음 <code>generaotr.next()</code>는 3이 반환되며 함수가 종료되고 <code>done:true</code>가 된다.</p>
<p>함수가 완전히 종료되었으므로 이제 <code>generaotr.next()</code>를 실행해도  <code>value : undefined , done:true</code>가 반환된다.</p>
<h3 id="forof">for~of</h3>
<p>이터러블을 배우며 이터러블 객체는 for-of로 이터러블 객체를 실행하면 next()메서드가 자동으로 호출되며 done:true일때까지 반복 실행됨을 배웠다.
제너레이터 객체도 이터러블 객체이므로 for-of로 반복이 가능하다. 
단 for-of는 done:true일때 value를 무시하므로 마지막 값을 제대로 출력하기 위해서는 마지막값을 return이 아닌 yield로 표현하는등의 처리가 별도로 필요하다.</p>
<h2 id="제너레이터-컴포지션">제너레이터 컴포지션</h2>
<p>제너레이터 컴포지션이란 제너레이터 안에 제너레이터를 임베딩하는 특별 기능이다.
쉽게 설명하면, 제너레이터 안에 또다시 제너레이터를 정의함으로서 제너레이터안에 제너레이터를 끼워넣을 수 있다. 이렇게 제너레이터를 끼워넣으면 중첩된 제러네이터 ( = 끼워넣어진 제너레이터)로 실행자가 위임된다. 즉 외부 제너레이터를 순서대로 호출하더라도 첫번째 yield가 가진 제너레이터가 차례대로 호출되며 첫번째 yield가 가진 제너레이터가 모두 호출되고 나서야 외부 제너레이터의 다음 yield가 실행된다. </p>
<p>사실, 중첩된 제너레이터의 외부 제너레이터에 작성하여도 똑같은 결과가 나타나나 중첩을 통해 조금 더 깔끔하게 코드를 작성할 수 있으며 중간 결과 저장용도의 메모리 사용이 줄어든다. </p>
<h2 id="값-전달하기">값 전달하기</h2>
<p>제너레이터의 이터레이터 객체와 가장 큰 차이 중 하나는 외부에서 객체 안으로 값을 전달할 수 있다는 것이다.
<code>generator.next(value)</code>를 사용해서 직전 호출된 yield의 결과값을 할당 할 수 있다.</p>
<p>위에 작성한 코드를 조금 수정해서 예시를 보자.</p>
<pre><code>function* generateSomething() {
  let first = yield 1;
  let second = yield 2;
  console.log(first, second); //first call! second call!
}
const generator = generateSomething();
let first = generator.next();
let second = generator.next(&quot;first call!&quot;);
let third = generator.next(&quot;second call!&quot;);</code></pre><p>우선 가장 처음에 첫번째 반환값을 조회한다. 이때는 next에 아무리 값을 전달해도 제너레이터 내부로 전달되지않는다. 
두번째 값 호출 시 next에 값을 전달하면, 해당값을 첫번째 yield의 반환값이 된다. 
서로 다른 순서의 호출임에도 가능한 이유는 첫번째 yield 를 호출 후 실행자가 첫번째 yield 줄에서 대기를 하다가, 다음  next가 호출되면 next에 들어온 매개변수를 첫번째줄에 할당하고 다음 yield로 이동하기 때문이다. </p>
<h3 id="에러-전달">에러 전달</h3>
<p>값을 전달할 수 있기 때문에 오류도 전달이 가능하다. 일반적인 값 전달과 다른점은 next메서드 대신 generator.throw 메서드를 사용해서 명시적으로 에러임을 알려주어야한다.
generaotr객체 내부에 에러가 전달되면 해당 객체는 더이상 실행되지 않는다.(에러처리를 하지않으면 스크립트가 죽으므로 try..catch등 에러 핸들링은 필수이다!.. )</p>
<h2 id="정리">정리</h2>
<p>사실, 모던 자바스크립트에서는 제너레이터를 잘 사용하지 않는다고 한다. 그렇기도 한게, 난수를 생성할때를 제외하고는 위와 같은 방식으로 상태값이 드러나지 않는 함수를 순차적으로 호출할 경우는 많지 않을것이라 본다. </p>
<p>다만 이터레이터 객체가 필요할 경우 제너레이터를 사용하면 편리하게 사용할 수 있으며 함수를 실행중에 데이터를 주고받을 수 있다는 장점이 있다.</p>
<p>비동기 이터레이터를 사용하면 더 유용하게 사용할 수 있다. </p>
<p>reference : <a href="https://ko.javascript.info/generators">자바스크립트 인포</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Webpack]]></title>
            <link>https://velog.io/@pro-yeong/webpack%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@pro-yeong/webpack%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Fri, 01 Jul 2022 17:43:52 GMT</pubDate>
            <description><![CDATA[<h1 id=""></h1>
<p>webpack에 대해 정리를 해보려고한다.
웹팩이 빌드 툴로서 파일들을 합쳐주고 최적화 해준다는것 정도만 알고 있었고 webpack의 원리에 대해 알아볼 기회가 없었다.</p>
<p>이번에 vanilajs로 만든 프로젝트를 번들링해볼 겸 webpack을 정리하고 공부해보려고 한다.
정리는 <a href="https://serzhul.io/JavaScript/learn-webpack-in-under-10minutes/">여기</a>를 참고하여서 진행하였다. </p>
<h1 id="웹팩을-왜-배워야할까">웹팩을 왜 배워야할까?</h1>
<p>웹팩에 대해 잘 알지 못해도 개발은 가능하다. 그러나 성능에 대해 고민을 시작하게 된다면 웹팩을 피해갈 수 없다.
사실 작은 프로젝트에서는 웹팩으로 파일을 합쳐주는 과정(번들링)도 최적화의 필요성도 잘 못느낄 수 있다. 그러나 애플리케이션의 규모가 커질 수록 빌드툴을 이용한 번들링은 필수사항이 된다.</p>
<h2 id="배워보자">배워보자</h2>
<p>웹팩의 필요성을 알았다면 이제 실전 예제를 통해 웹팩에 대해 정리해보자.
만약 기본용어가 헷갈릴때는 <a href="https://velog.io/@hih0327/Webpack-%EA%B8%B0%EC%B4%88">여기</a>를 참조하자. </p>
<h2 id="1-프로젝트-초기화-및-패키지-설치">1. 프로젝트 초기화 및 패키지 설치</h2>
<p>웹팩을 시작하기 위해서는 npm 프로젝트를 초기화해주어야한다</p>
<pre><code>npm init -y</code></pre><p>여기서 npm이란 무엇인지 잠깐 정리하자면</p>
<blockquote>
<p>npm이란
node package manager의 약자로 node 모듈들을 패키지로 관리하기 위한 패키지 매니저이자 node.js를 위한 오픈소스 생태계이다 </p>
</blockquote>
<p>좀 더 정리가 필요하다면 <a href="https://hoya-kim.github.io/2021/09/14/package-json/">여기</a>를 참고.</p>
<p>프로젝트가 초기화 되었다면 webpack 패키지를 설치한다.</p>
<pre><code>npm install --save-dev webpack webpack-cli webpack-dev-server</code></pre><p>이제 package.json도 생성이고 되고 방금 설치한 webpack package의 의존성이  package.json에 추가되었을 것이다.</p>
<p>dev라는 명령어로 개발모드에서 웹팩을 실행하기 위해 script 필드에 &quot;dev&quot; 를 추가해주자. </p>
<pre><code>&quot;scripts&quot;: {
    &quot;dev&quot;: &quot;webpack --mode development&quot;
            ...
  },</code></pre><p>기본적으로 package.json이 생성되면 main이 index.js로 되어있는것을 볼 수 있다. 이는 패키지의 기본 export가  index.js임을 의미한다. 우리는 아직 index.js이 없으므로 src 폴더와 함께 index.js를 생성하자.</p>
<h2 id="웹팩을-설정하기-전에">웹팩을 설정하기 전에!</h2>
<p>이제 설정을 작성해야하는데 그 전에 웹팩의 중요한 요소들에 대해 알아야한다. 정리는 <a href="https://tecoble.techcourse.co.kr/post/2021-07-10-webpack-exercise/">여기</a>를 참조하였다.</p>
<ol>
<li><p>엔트리(Entry)</p>
<ul>
<li>번들링을 시작하기 위한 진입점이다. 웹팩은 특정 범위에 있는 파일들 중 의존적인 모듈들을 모두 찾아내 번들링하는데 이때 의존 관계로 생기는 구조를 디펜던시 그래프라고한다  즉 재귀적으로 연결된 모든 모듈들이 번들링의 대상이 된다. entry에 지정된 js파일은 index.html에 삽입되는 대상이 된다(main js파일이 된다).  entry는 여러개일 수도 있다.(번들된 파일이 꼭 하나인것은 아니다!)</li>
</ul>
</li>
<li><p>아웃풋(Output)</p>
<ul>
<li>하나로 묶은 결과물을 저장할 위치이다.
파일명은 별도로 지정해주거나 미지정시 entry에서 결정된 이름이 유지된다.</li>
</ul>
<ol start="3">
<li>로더(Loader)</li>
</ol>
<ul>
<li>웹팩은 모듈, 즉 자바스크립트만 읽을 수 있다. 그러므로 js가 아닌 html, css ...등의 파일들을 모듈로 변환이 필요한데 이 때 사용되는것이 로더이다. 로더는 다른 확장자를 가진 파일들을 모듈화하기 위한 도구라고 볼 수 있다.</li>
</ul>
<ol start="4">
<li>플러그인</li>
</ol>
<ul>
<li>플러그인은 번들된 결과물을 처리하는 역할을 한다. 
로더가 파일을 처리했다면 플러그인은 그 결과물에 추가적인 작업을 진행한다. 예를들어 모듈화된 HTML파일에 번들된 스크립트를 추가하는 일을 할 수 있다. </li>
</ul>
</li>
</ol>
<p>이제 웹팩을 설정해보자.</p>
<h2 id="2-웹팩-설정하고-실행하기">2. 웹팩 설정하고 실행하기</h2>
<h3 id="1-설정파일-생성">1) 설정파일 생성</h3>
<p>웹팩을 설정하기 위한 내용들을 입력할 파일이 필요하다. webpack.config.js를 생성하자.</p>
<h3 id="2-엔트리-포인트-아웃풋-설정하기">2) 엔트리 포인트, 아웃풋 설정하기</h3>
<p>default 옵션과 다른 엔트리포인트 아웃풋을 설정할 수 있다. 
엔트리 포인트의 default는 src/index.js
아웃풋의 default 위치는 dist폴더이다.</p>
<h3 id="3--플러그인-설정하기">3)  플러그인 설정하기</h3>
<p>필요한 플러그인이 있다면 설정파일에 추가해주어야한다. 
해당 문서내에서는 HTML파일을 읽고 해당파일에 번들을 삽입해주는 플러그인 <code>html-webpack-plugin</code>의 예시를 소개하였다.</p>
<h3 id="4-loader-적용하기">4) loader 적용하기</h3>
<p>위에서 로더란 webpack이 js외 다른 파일들을 모듈로 만들기 위한 도구라고 하였다.
css파일을 모듈로 만들기 위해서는 css로더들을 설치하고 로더 설정 방법에 따라 작성하면 된다. 아래는 표준 예시이다.</p>
<h3 id="4-실행하기">4) 실행하기</h3>
<p> 서버를 실행하면 우리가 생성한 html파일이 열리면서 적용한 플러그인, loader들을 확인할 수 있다. 
 또한 html에 번들링된 스크립트 태그가 추가된것을 볼 수 있다. 해당  스크립트 태그를 살피면 속성이 defer로 지정되었음을 볼 수 있는데 모듈의 default 속성이 defer이기 때문이다. 즉 가장 마지막에 실행된다.
한가지 더 알아야할 것은, 우리는 모듈을 모아 스크립트를 추가한것인데, type이 module로 지정되지 않았는데 이는 웹팩이 번들링을 한 후 엔트리, 즉 메인 js파일에 의존 파일들이 모두 번들링되었다면 해당 파일만을 일반 스크립트로 호출하기 때문이다.</p>
<pre><code>module.exports = {
...
  module: {
      rules: [
        {
          test: /\.파일확장자$/,
          use: [&quot;로더2&quot;, &quot;로더1&quot;],
        },
      ],
    },
};</code></pre><h2 id="3-babel-적용하기">3. babel 적용하기</h2>
<p>webpack의 중요 기능중 하는 바로 babel을 이용해서 최신 자바스크립트 문법을 호환해준다는 것이다. webpack만으로는 번들링을 위한 도구로서 컴파일은 불가능하며 babel 설정, 패키지등이 별도로 필요하다. </p>
<p>babel을 설정하기 전에 </p>
<h3 id="babel은-어떻게-작동할까">babel은 어떻게 작동할까?</h3>
<p>관련 내용은 <a href="https://velog.io/@pop8682/%EB%B2%88%EC%97%AD-%EC%99%9C-babel-preset%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%98%EA%B3%A0-%EC%99%9C-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80-yhk03drm7q">여기</a>를 참고하자.
해당 내용을 정리하자면 바벨의 실제 동작은 플러그인에 의해 실행되며, 사용할 플러그인을 설치하고 바벨 설정파일인 <code>.babelrc</code>에게 &quot;컴파일 시 이 플러그인을 사용해줘&quot; 라고 알려주어야 한다는 것이다. 그럼 <code>.babelrc</code>은 컴파일시 해당 플러그인을 사용하여 코드를 컴파일 할 것이다.
그리고 필요한 문법마다 플러그인을 설치하기에는 번거로우므로 preset을 사용한다. 즉 <code>babel-preset = "plugin을 모아둔 번들"</code>이다.
간단하게 <code>babel/preset</code> 만 설치하고 <code>.babelrc</code>에 추가함으로서 모든 es6 기능 컴파일이 가능하다.</p>
<h3 id="바벨-적용하기">바벨 적용하기</h3>
<p>이제 바벨을 적용해보자.
필요한 패키지들을 설치해주어야한다.  바벨 컴파일러인 <code>@babel/core</code> 와 웹팩에서 babel을 사용하기 위한 로더 <code>babel-loader</code>, 그리고 플러그인인 <code>@babel/preset-env</code>를 설치한다.</p>
<p>위에서 babel에 plugin을 설정해줄 때 babel에 환경 설정 파일에 plugin을 추가해주어야한다고 했다. webpack에서 또한 똑같이 적용이 필요하다. babel 로더를 지정할 때 options에 presets에 설치한 <code>@babel/preset-env</code> 를 추가해준다.</p>
<p>마지막으로 webpack이 babel을 사용할 수 있도록 webpack환경설정에  loader를 추가한다. </p>
<p>이제 index.js에 es6문법의 코드를 작성하고 npm start 시 es5문법으로 컴파일된것을 확인할 수 있다</p>
<pre><code>const test = ()=&gt;{
    console.log(&quot;TEST!&quot;)
}</code></pre><pre><code>function test() {\n  console.log(\&quot;TEST!\&quot;);</code></pre><h2 id="4-최적화하기">4. 최적화하기</h2>
<p>다음으로 webpack으로 코드를 최적화하는 방법이다.
웹팩의 모드에는 개발, 프로덕션 두가지가 있는데 이는 프로덕션모드에서만 가능하다.</p>
<p>우선 프로덕션 모드로 빌드하기 위해 scripts에 
production 빌드 명령어를 추가하고 실행한다. </p>
<pre><code>&quot;scripts&quot;: {
     ...
    &quot;build&quot;: &quot;webpack --mode production&quot;
  },</code></pre><p>빌드된 프로덕션 파일은 우리가 작성했던 코드 그리고 개발모드와 다르며  공백이 없음을 확인할 수 있다.</p>
<h2 id="5-code-split">5. code split</h2>
<p>js파일을 번들링했을 때, 코드의 크기가 너무 클때는 한번에 로드하는것보다 필요에 따라 분산시켜 가져오는 것이 좋다. 처음에 필요한 코드만 로드한 뒤 필요에 따라 추가적으로 나머지 코드를 불러오는 방식이다. 각각의 추가로 로드되는 코드를 chunk라고 한다.</p>
<p>방법은 </p>
<ol>
<li>Entry Points</li>
<li>Prevent Duplication</li>
<li>동적 import 
가 있다.</li>
</ol>
<h3 id="1-entry-points">1. Entry Points</h3>
<p>만약 번들링하는 모듈을 기능에 따라 분리가 가능하다면 여러개의 엔트리포인트를 둘 수 있을 것이다. 
entry설정을 사용하여 코드를 여러개의 엔트리로 분리할 수 있다.
그러나 엔트리포인트가 다를때, 각각의 엔트리의 의존 모듈들도  별도로 관리되기때문에 만약 다른 엔트리에서 중복되는 모듈이 많다면 비효율적으로 코드가 증가될 수 있다.</p>
<h3 id="2-prevent-duplication">2. Prevent Duplication</h3>
<p> SplitChunksPlugin 등을 사용해서 중복 청크를 제거하고 청크를 분할 할 수 있다. 
dependOn 옵션을 사용해서 모듈을 공유하게 할 수 있다.</p>
<h3 id="3-동적-import">3. 동적 import</h3>
<p>일반적으로 react에서 router로 이동하는 page에 적용할 수 있는 방법이다. 페이지를 이동하기 전까지는 해당 파일들이 불필요하므로 router로 이동하고자 할때 로드 후 실행한다는 개념이다.
혹은 유저의 입력, 이벤트에 따라 나타나는 컴포넌트의 경우 import를 동적으로 할 수 있다.</p>
<p>너무 무분별한 code split은 오히려 코드의 번들링의 이유를 해치므로 주의하자</p>
<p>참고
<a href="https://tecoble.techcourse.co.kr/post/2021-07-10-webpack-exercise/">웹팩 이해하기</a>
<a href="https://velog.io/@hih0327/Webpack-%EA%B8%B0%EC%B4%88">webpack기초</a>
<a href="https://velog.io/@pop8682/%EB%B2%88%EC%97%AD-%EC%99%9C-babel-preset%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%98%EA%B3%A0-%EC%99%9C-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80-yhk03drm7q">[번역] babel-preset-env는 무엇이고 왜 필요한가?</a>
<a href="https://serzhul.io/JavaScript/learn-webpack-in-under-10minutes/">10분 만에 웹팩 배우기</a>
<a href="https://webpack.kr/guides/code-splitting/">webpack-guide</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Atomic design]]></title>
            <link>https://velog.io/@pro-yeong/Atomic-design</link>
            <guid>https://velog.io/@pro-yeong/Atomic-design</guid>
            <pubDate>Thu, 30 Jun 2022 14:17:52 GMT</pubDate>
            <description><![CDATA[<p>react를 공부하면서 자주 보이는 용어중 하나는 바로 Atomic design Parttern이다.</p>
<h2 id="atomic-design이란">Atomic design이란?</h2>
<blockquote>
<p>Atomic design
일종의디자인 시스템을 만드는 하나의 방법론으로 가장 작은 컴포넌트를 원자 단위로 설정하고이를 바탕으로 상위 컴포넌트를 만들어 재사용을 최대화하는 방법론이다. 컴포넌트는 순서대로 원자, 분자, 유기체, 템플릿, 페이지의 단계로 구분된다.</p>
</blockquote>
<p>즉 컴포넌트들을 효율적으로 사용하기 위한 일종의 체계라고 할 수 있다.
각 단계에 대해 좀 더 자세히 살펴보면</p>
<h3 id="atom원자">Atom(원자)</h3>
<p>디자인과 기능의 최소 단위이다. 더 이상 분해할 수 없어야 하며 일반적으로 버튼, 아이콘등이 여기에 해당한다.
원자 단위의 컴포넌트는 그자체로 사용하는 경우가 많이 없으며 atom단위를 서로 결합해서 분자 혹은 유기체 단위로 사용한다</p>
<h3 id="molecule분자">Molecule(분자)</h3>
<p>원자보다 큰 단위로 여러개의 atom이 결합되어 형성된다. 
예를들어 입력폼 atom단위인 버튼과 input을 결합해서 만들어진다. 이러한 form은 Molecule라고 할 수 있다.</p>
<h3 id="organism유기체">Organism(유기체)</h3>
<p>Atom, Molecule 보다는 좀 더 복잡한 구조로 여러개의 atom, molecule이 결합하여 형성된다. 명확하게 그 범위를 정의할 수는 없으나 그 자체로 이미 충분한 기능을 형성하며 상대적으로 재사용성이 낮다.</p>
<h3 id="template템플릿">Template(템플릿)</h3>
<p>여러개의 atom, molecule,Organism 이 결합하여 형성된다. 페이지에 가까운 형태이며 일종의 와이어프레임이라고 할 수 있다.</p>
<h3 id="page페이지">Page(페이지)</h3>
<p>실제 유저가 보게되는 화면 , 페이지이다.</p>
<h2 id="아토믹-디자인-패턴의-단점">아토믹 디자인 패턴의 단점</h2>
<p>애플리케이션의 규모가 점점 커질수록 아토믹 디자인패턴의 불편함이 발생한다. 이유는 크게 2가지로 정리할 수 있다.</p>
<h3 id="1-비용이-높다">1. 비용이 높다.</h3>
<p>학습비용, 시간적 비용 모두 해당한다. 아토믹 디자인 패턴을 적용한 환경에서 새롭게 page를 구성하기 위해서는 대부분의 작은 단위의 컴포넌트들을 학습하고 알아야한다. 그래야 불필요한 중복을 막고 올바른 아토믹 디자인 패턴을 적용했다고 할 수 있다.</p>
<h3 id="2-유연성이-부족하다">2. 유연성이 부족하다.</h3>
<p>작은 컴포넌트 단위이기때문에 자유롭지만 사실 그렇기 때문에 고민이 발생한다. 
예를들어 글씨만 있는 버튼 컴포넌트가 존재하는데 버튼에 아이콘을 추가해달라는 새로운 요구사항이 생겼다. 이미 작은 단위이기때문에 이것을 더 작은 단위로 쪼개는 것은 불가능하다. 
대신 선택할 수 있는 방법은 여러가지가 있다. </p>
<ol>
<li>아이콘이 들어있는 버튼컴포넌트를 새롭게 만든다</li>
<li>버튼의 props를 추가해 아이콘 지정여부를 결정한다. </li>
</ol>
<p>모두 간단한 방법이다. 그러나 이렇게 추가적인 요구사항이 증가할 수록 점점 컴포넌트의 갯수 혹은 그 복잡도는 증가하게 된다. 
이러한 경우 사용할 수 있는 방법이 복합 컴포넌트이다.</p>
<h2 id="복합컴포넌트란">복합컴포넌트란?</h2>
<blockquote>
<p>복합 컴포넌트란, 구성요소들이 백그라운드에서 서로 통신할 수 있도록 암시적인 상태를 공유하도록 하는 패턴이다.
즉 여러 구성요소가 함께 작동하며 상태를 공유하는 경우, 복합 구성 요소라고한다.</p>
</blockquote>
<p>가장 대표적이며 익숙한 복합 구성 요소는 select 와 option이다. 두 구성 요소는 따로 사용하지만 서로 상태를 공유하고 있다. </p>
<p>복합 컵포넌트는 컴포넌트 사이 관계를 표현할 수 있는 매우 좋은 방법이다.
복합 컴포넌트의 중요한 점 중 하나는 암시적인 상태라는 것이다. select는  option의 상태를 저장하고 해당 상태를 하위요소와 공유한다. 그러나 직접적으로 해당 코드에 접근할 수는 없기 때문에 암묵적이라고 할 수 있다.</p>
<p>Ref : 
<a href="https://blog.logrocket.com/understanding-react-compound-components/">Understanding React compound components</a>
<a href="https://fe-developers.kakaoent.com/2022/220505-how-page-part-use-atomic-design-system/">아토믹 디자인을 활용한 디자인 시스템</a>
<a href="https://brunch.co.kr/@skykamja24/580">아토믹 컴포넌트 디자인 개발 패턴</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 성능 최적화하기]]></title>
            <link>https://velog.io/@pro-yeong/React-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@pro-yeong/React-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 30 Jun 2022 11:23:53 GMT</pubDate>
            <description><![CDATA[<h2 id="성능-측정하기">성능 측정하기</h2>
<p>React에서 성능 최적화는 가장 중요한 요소 중 하나이다.
토이프로젝트를 위해 최적화를 하는 방법을 찾아보다 React Developer Tools에 있는 Profiler라는 기능을 알게되었다, </p>
<h2 id="react-developer-tools-with-profiler">React Developer Tools with Profiler</h2>
<p>React Developer Tools은 오픈소스 React JavaScript 라이브러리용 Chrome DevTools 확장 프로그램으로 React의 컴포넌트 계층구조등을 검사할 수 있다.
React Developer Tools은 구성요소, 프로파일러라는 두개의 탭을 갖는데 구성요소는 돔트리 처럼 실제 컴포넌트의 트리를 볼 수 있다. 
프로파일러탭에서는 성능정보를 기록하고 조회할 수 있다.</p>
<p>이중 프로파일러 기능에 대해 기록하고자 한다.</p>
<h2 id="성능을-개선하자">성능을 개선하자</h2>
<p>우선 성능을 개선하기 위해서는 성능을 측정, 비교 후 더 나은 방식을 선택해야한다.
진행중인 프로젝트에서 검색을 하고 무한 스크롤로 데이터를 가져오는 컴포넌트를 대상으로 개선을 진행하고자한다.
사용방법은 <a href="https://moood.dev/reactjs/performance-profiling-your-react-app/">여기</a>를 참고한다.</p>
<h3 id="case1">Case1</h3>
<p>검색form에서 검색을 하면 redux store에 데이터가 저장되고 List 컴포넌트에서 해당 데이터를 가져와 출력하는 컴포넌트이다.
코드는 다음과 같다.</p>
<p>in SearchList</p>
<pre><code>const { plants, loading, totalCount, error } =seSelector((state) =&gt; ({
    ...state.plants,
  }));
 ...
 let content = &lt;PlantList plants={plants} /&gt;;
if (loading) content = &lt;LoadingSpinner /&gt;;
if (error) return &lt;PlantList error={error} /&gt;;

return (
    &lt;Fragment&gt;
        &lt;SearchForm/&gt;
          ...
        {content}
    &lt;/Fragment&gt;
  );
</code></pre><p>Profiler를 실행시켜 검색을 진행했을때의 측정 결과이다. 
18번의 commit이 발생했으며 그 중 가장 오래걸린 commit은 아래 사진과 같다.
<img src="https://velog.velcdn.com/images/pro-yeong/post/caa82fd5-58b2-415e-89b1-584ae5089316/image.png" alt=""></p>
<p>plantList가 렌더링되는데 0.4ms가 걸렸으며 그 이유는 부모의 렌더링 때문이라고 한다. 즉 props변경이나 state값의 변경이 아닌 부모 컴포넌트의 변경때문이다.  </p>
<p>부모가 리렌더링 되더라도 자식의 상태의 변화가 없다면 리렌더링 하지않도록 (정확히는 저장해둔 값을 사용하는) 하기 위해 PlantList에 React.memo를 적용하였다.</p>
<p><img src="https://velog.velcdn.com/images/pro-yeong/post/cf56ad5e-e11f-42ef-aec6-2f1c0d3c593e/image.png" alt=""></p>
<p>그 결과, 같은 commit에서 가장오래걸렸던 PlantList는 렌더링 되지않았으며 그 하위 컴포넌트도 모두 렌더링되지않아 렌더링 시간이 약 5ms 감소하였다. 
전체적인 흐름에서 PlantList의 렌더링 횟수도 9번에서 3번으로 감소하였다. </p>
<h3 id="case2">Case2</h3>
<p>DevTools은 추가적으로 Highlight updates when components render 기능을 제공한다. 화면상에 파란색 ~ 주황색의 박스로 렌더링 여부를 표기해주는 기능이다. 렌더링 1번은 파랑색 연속적으로 발생하면 주황색으로 표기된다.</p>
<p>측정 대상으로는 검색 form을 선택하였다.
1개의 input, 2개의 selectBox가 있는 검색 form 이다. </p>
<p>검색 form의 input에 단어를 입력하다보면 사용하지도 않는 selectBox가 계속 주황색으로 깜박거리는것을 볼 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/pro-yeong/post/0589b5c9-d630-4d29-b006-dbe9c4960c16/image.png" alt=""></p>
<p>Input에의해 form컴포넌트의 상태가 계속변하면서 하위 요소인 selectBox도 계속 렌더링이 발생하게 되는것이다.</p>
<p>실제로 측정해보면 SelectBox가 여러번 리렌더링 되는것을 볼 수 있다.
<img src="https://velog.velcdn.com/images/pro-yeong/post/58119a35-f81d-45a5-8783-b3728be466ec/image.png" alt=""></p>
<p>이를 위해 SelectBox를 React.memo로 묶고 속성으로 지정된 함수를 useCallback으로 감싸준다.</p>
<p><img src="https://velog.velcdn.com/images/pro-yeong/post/b478404c-07f3-4f2d-a8fa-3e07ae81b098/image.png" alt="">
그 결과 SelectBox는 아예 렌더링이 발생하지 않을 수 있다.</p>
<h2 id="정리하기">정리하기</h2>
<p>여러가지 케이스 적용을 통해 생각보다 최적화가 중요함을 느꼈다. 
단, useCallback, React.memo와 같은 최적화가 항상 최적의 결과를 낳는것은 아님을 항상 기억하자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Infinite scroll 구현하기 wtih IntersectionObserve]]></title>
            <link>https://velog.io/@pro-yeong/React-Infinite-scroll-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-wtih-IntersectionObserve</link>
            <guid>https://velog.io/@pro-yeong/React-Infinite-scroll-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-wtih-IntersectionObserve</guid>
            <pubDate>Thu, 30 Jun 2022 06:13:45 GMT</pubDate>
            <description><![CDATA[<p>현재 토이프로젝트로 가드너를 위한 사이트를 만들고 있는데, 식물 검색결과를 가져오는 부분에서 무한 스크롤 구현 파트가 필요했다.</p>
<h2 id="현재상황">현재상황...</h2>
<p>사실, 처음에는 일반스크롤도 구현된 상황이었다. 식물 검색결과, 여러 기관에서 데이터를 가져오는데, 사진-설명만 다르고 품종이 같은 식물정보가 많이 조회되었다.
예를들면,,
<img src="https://velog.velcdn.com/images/pro-yeong/post/2d4b8ab6-db21-4c2c-95f7-6035e204dd68/image.png" alt=""> 같다고도 다르다고도 볼 수 없는 데이터ㅠㅠ...
처음 구현당시에는 불필요하게 중복되는 것을 막고자 filter처리를 하였다.</p>
<h4 id="초기-중복처리-코드">초기 중복처리 코드</h4>
<pre><code>    let preVarieties = {};
    let varieties = [];
    if (result.body.items.totalCount &lt; 1) return [];
    result.body.items.item.forEach((variety) =&gt; {
      if (!preVarieties[variety.prdlstCtgCode]) {
        preVarieties[variety.prdlstCtgCode] = {
          description: variety.mainChartrInfo,
          name: variety.svcCodeNm,
          plantId: variety.prdlstCtgCode,
          instt: variety.unbrngInsttInfo,
          imgLink: variety.imgFileLink,
        };
      }
    });
    for (let variety of Object.keys(preVarieties)) {
      varieties.push(preVarieties[variety]);
    }
    return varieties;</code></pre><p>filter를 이중 루프를 도는것보다는 객체로 필터링하는게 더빠를 것 같아 위와 같이 처리했다.</p>
<h2 id="이게-맞을까">이게 맞을까?..</h2>
<p>그러나 프로젝트를 진행하면서 해당 부분에 대한 고민이 계속 생겼다. api의 호출결과는 228개인데 중복을 필터하여 10여개가 나온다. 품종코드로만 필터를 걸었기때문에 설명이 다른 작물도 존재한다.</p>
<p>결국 고민끝에 필터부분을 제외하고 모든 데이터를 가져오기로 하였다. 필터가 필요한 부분은 카테고리, 기관명 설정으로 사용자가 선택할 몫이라고 보았다.</p>
<h2 id="😵💫-새로운-문제">😵‍💫 새로운 문제</h2>
<p>많아야 10여개가 나오던 데이터가 100여개로 증가하였고, 모든데이터를 한번에 가져오기에는 너무 오랜시간이 걸렸다 (5초ㅠ..) 
페이징 처리가 필요하였고 적절한 방법을 찾다가 스크롤이 내리면 데이터를 호출하는 방법으로 구현하기로 하였다.</p>
<h2 id="scroll-vs-intersectionobserve">Scroll vs IntersectionObserve</h2>
<p>일반적으로 scroll을 이동하게 이벤트를 발생시킬때 두가지 방법을 사용한다.</p>
<ol>
<li>Scroll eventListener 스크롤 이동시마다 event가 발생하며 조건에 만족할 때 핸들러 실행</li>
<li>IntersectionObserve로 지정 view와 타켓 view가 교차할 때 핸들러 실행</li>
</ol>
<p>둘 중에 어떤것이 좋을 지 여러 리소스를 찾아보았는데 scroll시 위치에 대한 계산( getBoundingClientRect등)이 발생할 경우  reflow(화면을 다시 그림)가 발생한다고 한다.  본인은 스크롤 위치에 따라 api를 호출해야하므로 매번 현재위치를 가져와야한다. Intersection Observer는 교차할때 발생하는 콜백에서 getBoundingClientRect에 대한 정보를 제공해준다. 
따라서 Scroll 이벤트가 아닌 IntersectionObserve 를 사용하기로 하였다.</p>
<h2 id="infinite-scroll-구현하기">Infinite scroll 구현하기</h2>
<p>사실 IntersectionObserve는 과거 포트폴리오를 작성할때, section마다 감지시 사용했던 경험이 있어 어렵지 않게 구현할 수 있을 줄 알았다.
그러나 늘 기대는 배반하는 법. 역시나 많은 삽질의 과정이 필요했다.. 과정은 다음과 같았다.</p>
<h3 id="1-root-target-intersectionobserver-생성하기">1. root, target IntersectionObserver 생성하기</h3>
<p>IntersectionObserver  기본 구성은 아래와 같다. </p>
<pre><code>const observer = new IntersectionObserver(isIntersect, {
      threshold: 1,
    });
    observer.observe(target);</code></pre><p>IntersectionObserver을 생성하기 위해서는 두개의 인수가 필요하다.</p>
<ol>
<li><p>observer가 target을 감지했을때 호출되는 callback(isIntersect)</p>
</li>
<li><p>관찰자? 역활을 하는 root , rootMargin, 교차 비율등을 설정하는 threshold을 속성으로 하는 option 객체.</p>
<p>root의 기본값은 viewPort로 threshold를 제외한것은 기본값으로 사용하였다.</p>
</li>
</ol>
<h3 id="2-custom-hook으로-만들기">2. custom hook으로 만들기</h3>
<p>해당 코드를 여러군데에서 사용할 가능성이 있을 것 같아 별도로 훅으로 작성했다.</p>
<pre><code>const useIntersectionObserver = ({ intersectionHandler }) =&gt; {
  // ref가 담길 state
  const [target, setTarget] = useState();

  // target element의 ref가 변경되면 호출.

  const isIntersect = useCallback(
    ([entry], observer) =&gt; {
      if (entry.isIntersecting) intersectionHandler(entry);
    },
    [intersectionHandler]
  );
  const serRef = useCallback((element) =&gt; {
    if (!element) return;
    setTarget(element);
  }, []);
  useEffect(() =&gt; {
    if (!target) return;
    const observer = new IntersectionObserver(isIntersect, {
      threshold: 1,
    });
    observer.observe(target);

    return () =&gt; observer.unobserve(target);
  }, [target, isIntersect]);

  return { serRef };
};</code></pre><p>setTarget은 감지 대상이 될 target이 담긴다. 
사실, observer 로 감시하기 위해서는 DOM요소가 필요하므로 target요소를 ref로 참조하여 가져와야한다.
그러나 ref의 변화는 react가 감지하지 못한다. 우리는 target이 바뀔때마다 observer를 해제하고 연결하고를 반복해야하므로 ref를 useState로 감시하여 대신 ref값을 받아와 state에 저장하였다.
해당 부분을 위한 함수가 serRef이며 대상 요소의 ref 속성에 지정하면,자동으로 요소가 생성, 해제될때마다 setRef가 호출되고 매개변수로 해당 요소를 참조해온다.
자세한것은 <a href="https://medium.com/@teh_builder/ref-objects-inside-useeffect-hooks-eb7c15198780">여기</a>를 참조한다.</p>
<h3 id="3-observer-연결하기">3. observer 연결하기</h3>
<pre><code>    const intersectionHandler = useCallback(
    async (entry) =&gt; {
      if (!loading) await loadMoreData();
    },
    [loading, loadMoreData]
  );

  const { serRef } = useIntersectionObserver({ intersectionHandler });
  let content = &lt;PlantList plants={plants} /&gt;;

  if (currentPage.current === 1 &amp;&amp; loading) content = &lt;LoadingSpinner /&gt;;
  return (
    &lt;Fragment&gt;
      &lt;SearchForm onSubmit={submitFormHandler} /&gt;
      {content}
      {!loading &amp;&amp; plants &amp;&amp; plants.length &gt; 0 &amp;&amp; &lt;div ref={serRef} /&gt;}
    &lt;/Fragment&gt;
  );
};</code></pre><p>이제 바닥에 닿을때마다 호출할 intersectionHandler 생성하고  useIntersectionObserver에 전달한다.
그리고 ref를 참조하기 위해 target에 setRef를 연결한다.
현재 컴포넌트내에 Form 컴포넌트가 함께 있어서 분기처리가 복잡하다..ㅠ  observer를 추가하며 컴포넌트가 단순 리스트의 성격을 벗어났으므로 ,  이부분은 개선이 필요해보인다.</p>
<p> target에 해당하는 [div]에 setRef를 연결하여 div가 마운트, 언마운트 될때마다 ref가 setRef로 전달되도록한다.
 주의할 것은 loading, plants가 없을경우는 해당 target이 언마운트 되어서 observer에 아무것도 연결되지 않도록 해야한다. 
 만약 계속 div가 떠 있다면 observe는 계속 연결된 상태이며, 리스트가 0일때 target이 가장 상단에 위치하여 계속해서 intersectionHandler이 호출된다.</p>
<p>목록에 위치에는 경우에 따라 초기값이 없고 로딩중인 경우는 [LoadingSpinner] 그외에는 [PlantList] 를 렌더한다.</p>
<h3 id="4-마무리">4. 마무리</h3>
<p>데이터를 추가 로드할 loadMoreData 함수를 호출한다. 초기호출과 추가 호출을 구분하기 위해 함수를 별도로 작성하였다. 
추가 로드의 경우 현재 페이지와 totalCount와 비교해 유효성을 검증한다.
초기 로드의 경우 현재페이지의 값을 1로 초기화한다.</p>
<p>현재 parameter와 page는 ref로 관리한다. ref는 DOM요소 참조외에도 컴포넌트의 고유한 값을 저장하기 위해서도 사용된다. 단순히 값만 저장하고 렌더링과는 무관하므로 state보다는 ref를 사용하였다.</p>
<pre><code>  const currentPage = useRef(1);
  const currentParams = useRef();

    // first Load
  const submitFormHandler = useCallback(
    async (config) =&gt; {
      currentParams.current = config;
      currentPage.current = 1;
      dispatch(searchThunk({ ...currentParams.current, pageNo: 1 }));
    },
    [dispatch]
  );


  // more Load
  const loadMoreData = useCallback(async () =&gt; {
    if (currentPage.current * 10 &gt; totalCount) return;

    currentPage.current++;
    dispatch(
      getMoreSearchThunk({
        ...currentParams.current,
        pageNo: currentPage.current,
      })
    );
  }, [dispatch, totalCount]);</code></pre><h2 id="정리하기">정리하기</h2>
<p>사실 구현하면서 이것저것 리소스도 많이 참고하고 시간도 많이 들였다.
그럼에도 고칠점이 아직 많아보인다. </p>
<p>Ref : 
<a href="https://itnext.io/1v1-scroll-listener-vs-intersection-observers-469a26ab9eb6">scroll-listener-vs-intersection-observers</a> 
<a href="https://velog.io/write?id=38dfb01d-b5dd-412d-baa4-187a62111af1">useRef vs useState
</a><a href="https://y0c.github.io/2019/06/30/react-infinite-scroll/">Infinite-scroll</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[shouldComponentUpdate 와 React.memo]]></title>
            <link>https://velog.io/@pro-yeong/shouldComponentUpdate-%EC%99%80-React.memo</link>
            <guid>https://velog.io/@pro-yeong/shouldComponentUpdate-%EC%99%80-React.memo</guid>
            <pubDate>Mon, 27 Jun 2022 16:24:47 GMT</pubDate>
            <description><![CDATA[<h2 id="shouldcomponentupdate-와-reactmemo">shouldComponentUpdate 와 React.memo</h2>
<p>프로젝트를 최적화하기 위해 여러가지 방법을 찾아보다가 shouldComponentUpdate 라는 메서드를 처음 알게되었다.</p>
<h3 id="shouldcomponentupdate">shouldComponentUpdate</h3>
<blockquote>
<p>shouldComponentUpdate란?
컴포넌트의 prop이나 state가 변경될때, 변화가 있는지를 확인하고 렌더링 여부를 결정할 수 있다. (true =&gt; rendering, false=&gt; no rendering)
성능 최적화만을 위한 메서드로 렌더링을 방지하는 용도로 사용할 경우 버그가 발생할 수 있다. 
props와 state가 변경되어 렌더링이 발생하기 직전에 호출된다.</p>
</blockquote>
<p>그런데,  일반적으로 shouldComponentUpdate는 직접 작성하기 보다 PureComponent를 사용하는방식으로 대신된다고한다.</p>
<p>그렇다면 다시 PureComponent는 무엇인가..</p>
<h3 id="reactpurecomponent">React.PureComponent</h3>
<blockquote>
<p>PureComponent 란?
React.Component와 거의 유사하나 내부적으로 shouldComponentUpdate를 구현하며 props와 state를 이용한 얇은 비교를 구현한다는 차이가 있다.</p>
</blockquote>
<p>즉 PureComponent가 이미 shouldComponentUpdate를 내포하고 있다고 보면 될 것 같다.
단, PureComponent는 얇은비교를 하므로 객체등의 타입을 제대로 비교하지 못한다는 것을 기억해야한다!</p>
<p>PureComponent가 props를 비교하여 렌더링 여부를 결정한다는 점에서 비슷한 함수가 하나 떠오른다. 바로 React.memo이다.
해당 글도 React.memo와 shouldComponentUpdate의 차이가 무엇인가 싶어서 작성하게 되었다.</p>
<h3 id="reactmemo">React.memo</h3>
<blockquote>
<p>React.memo 란?
동일한 props에 따른 호출 결과를 메모이징 해두었다가 props가 변경도되지않을 경우 마지막 렌더링된 결과를 재사용한다.
만약 이전props와 최신 props를 비교하여 렌더링 여부를 결정하고 싶다면 React.memo의 두번째 인자로 비교함수를 전달하면된다.</p>
</blockquote>
<pre><code>function MyComponent(props) {
  /* props를 사용하여 렌더링 */
}
function areEqual(prevProps, nextProps) {
  /*
  nextProps가 prevProps와 동일한 값을 가지면 true를 반환하고, 그렇지 않다면 false를 반환
  */
}
export default React.memo(MyComponent, areEqual);</code></pre><h3 id="shouldcomponentupdate-vs-reactmemo">shouldComponentUpdate vs React.memo</h3>
<p>React.memo는 두번째 인자의 함수가 true를 return할 경우 렌더링이 유지되고 그 반대의 경우에 재평가된다.
반면 shouldComponentUpdate는 true를 return 할 경우 재평가가 발생한다.</p>
<p>즉 작동 방식이 반대이다.</p>
<h3 id="reactmemo를-언제-사용해야할까">React.memo를 언제 사용해야할까?</h3>
<p>일반적으로 함수형 컴포넌트를 구현하므로 React.memo를 기준으로 할때, React.memo는 최적화를 하기 매우 좋은 도구이다. 그렇다면 모든 컴포넌트를 React.memo로 감싸는것이 좋을까?</p>
<p>당연히 아니다.
React.memo를 사용하면 props의 결과를 기억하고 props를 비교하는 과정이 추가로 들어간다. 이 또한 비용이다.
React.memo는 단지 위에 설명한 비용과 재평가의 비용을 바꾼것이다.</p>
<p>만약 빈번하게 props가 변경되는 컴포넌트에 React.memo를 사용한다면 그저 비용을 두배로 지불할 뿐이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React와 Redux (2)]]></title>
            <link>https://velog.io/@pro-yeong/React%EC%99%80-Redux-2</link>
            <guid>https://velog.io/@pro-yeong/React%EC%99%80-Redux-2</guid>
            <pubDate>Fri, 17 Jun 2022 16:39:38 GMT</pubDate>
            <description><![CDATA[<h3 id="상태를-읽어오기">상태를 읽어오기</h3>
<p>이제 컴포넌트에서 저장소를 구독하고 데이터를 가져올 차례이다.
사실 redux만 사용한다면 구독을 위해서는 subscribe라는 함수를 사용한다.</p>
<p>예시로 구독자 함수를 만들고 해당 구독자를 연결해보자.</p>
<pre><code>const subscriber = () =&gt; {
  let latestState = store.getState();
    console.log(&quot;receive new State !&quot;, latestState);
};

store.subscribe(subscriber);</code></pre><p>위와 같이 코드를 작성하면 redux는 subsciber라는 구독자 함수를 인식하게되고 저장소가 변경되었을때 해당 함수를 트리거한다.
그리고 구독자함수 내에서 getState() 메서드로 최신 상태를 전달 받을 수 있다.</p>
<p>그러나 우리는 react-redux를 사용할 것이기때문에 위와같은 로직을 사용할일이 드물다.
subscribe()와 getState() 대신 react-redux가 제공하는 useSelect()훅을 사용할 수 있다.</p>
<p><em><strong>useSelector 사용하기</strong></em></p>
<pre><code>import {useSelctor} from &#39;react-redux&#39;

const status = useSelector((state) =&gt; state.status.status);</code></pre><p>useSelector를 사용하면 자동으로 해당 컴포넌트가 redux store에 구독등록?이 된다. 따라서 store가 업데이트 되면 해당 컴포넌트가 자동으로 재실행된다. 또한 구독중인 store에서 최신상태값을 조회해올 수 있다. store.getState()와 동일한 기능을 하며 useSelector의 인수로 넘기는 콜백함수에 현재 store의 상태값이 매핑되고 그 상태값에서 원하는 속성을 꺼내기만 하면된다. 또한 컴포넌트가 unmount될때 구독은 자동으로 해지된다는것도 기억하자.</p>
<p>주의할것은 현재 reducer를 combineReducer로 결합했기때문에 특정 reducer에 속하는 상태값을 꺼내기 위해서는 combineReducer에 지정된 속성명을 거쳐야한다는 것이다. 위 코드에서 첫번째 status 속성이 그 역할을 한다.</p>
<p>useSelector를 사용할때 명심할 것은 가져오는 state값에 따라 렌더링여부가 결정된다는 것이다.
우리는 현재 state.status.status만을 가져오고 있으므로 state.status.status가 변경되었을때만 해당 컴포넌트가 재평가된다.
만약 state.status.error 가 변경되었다면 해당 컴포넌트는 재평가되지 않는다.
단</p>
<pre><code>(state)=&gt;({state : state.status.status });
</code></pre><p> 와 같이 가져오려는 state를 객체로 감싼다면 react-redux는 객체안을 읽지못하고, 결국 가져오려는 값이 무엇인지 몰라 무조건 컴포넌트를 재렌더링 해버린다. 만약 state에서 두개이상의 상태값을 조회할때 하나의 상태값만 변경되는 케이스가 빈번하다면 객체타입을 피하는것이 좋을 것이다.</p>
<p> 대신 useSelector을 여러번 사용하거나  react-redux의 shallowEqual 함수를 useSelector의 두번째 매개변수로 전달해주면 된다. 보다 자세한 내용은 <a href="https://react.vlpt.us/redux/08-optimize-useSelector.html"> useSelector최적화</a>를 참고하는것을 추천한다.</p>
<h3 id="상태-업데이트하기">상태 업데이트하기</h3>
<p> 마지막으로 상태 업데이트하기만 남았다.
 상태를 업데이트하기 위해서는 컴포넌트내에서 action을 dispatch하면 된다.
 진행순서는 다음과 같다.</p>
<ol>
<li><p>액션생성자 함수를 import 한다.</p>
</li>
<li><p>useDispatch() 훅으로 dispatch함수를 가져온다.</p>
</li>
<li><p>액션생성자함수를 실행시켜 dispatch로 전달한다.</p>
<p>실제 코드로 예시를 본다면, </p>
<pre><code>const dispatch = useDispatch();

const submitSearchFormHandler = async (e) =&gt; {
e.preventDefault();
dispatch(changeStatus(&quot;PENDING&quot;));
...
dispatch(changeStatus(error?&quot;ERROR&quot; : &quot;SUCCESS&quot;);
};
</code></pre></li>
</ol>
<p>```
api를  호출하면
useDispatch()함수로 가져온 dispatch 에 changeStatus라는 액션생성자함수를 호출해 생송헌 액션을 전달한다. 
해당 액션생성자 함수는 상태의 status속성을 업데이트하는 액션을 생성한다.
이제 reducer로 해당 action이 전달될 것이며  전달한 action에 맞추어 state가 업데이트된다.
&quot;PENDING&quot;이라는 값을 전달했으므로 state.status는 PENDING 업데이트되며 해당 상태를 구독중인 모든 컴포넌트에 전달된다.
api호출을 종료하면 결과값에 따라 &quot;ERROR&quot;, &quot;SUCCESS&quot;를 전달한다.
다시 state.status는 SUCCESS 혹은 ERROR로 업데이트되며 해당 상태를 구독중인 모든 컴포넌트에 전달된다.</p>
<h3 id="정리하기">정리하기</h3>
<p>상태 업데이트까지 모두 완료되었다. 사실 redux에는 더 많은 기능이 있다. 또한 redux를 제대로 사용하기 위해서는 리덕스 미들웨어의 사용은 필수불가결하다고 할 수 있다.
앞으로 시간이 된다면 관련 내용도 블로그에 정리를 해볼 예정이다.
또한 redux를 편하게 사용하기 위한 toolkit도 존재한다! 사실 redux만 사용하기에는 reducer 코드가 너무 길어지거나, 기존 상태값을 수정하면 안된다는 규칙이 redux의 불편요소중 하나이다.. 
다만 toolkit을 사용한다면 기존 createRedux, reducer 정의 방식이 모두 달라지므로 다시 redux를 공부하는 기분을 낼 수 있다ㅎㅎ.. 
해당 내용도 나중에 기회가 되면 한번 정리해보고 싶다.</p>
<p>ref
<a href="https://www.udemy.com/course/best-react/">React 완벽 가이드 with Redux, Next.js, TypeScript</a>
<a href="https://react.vlpt.us/redux/">벨로퍼트와 함께하는 모던 리액트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React와 Redux (1)]]></title>
            <link>https://velog.io/@pro-yeong/React%EC%99%80-Redux-1</link>
            <guid>https://velog.io/@pro-yeong/React%EC%99%80-Redux-1</guid>
            <pubDate>Fri, 17 Jun 2022 15:01:31 GMT</pubDate>
            <description><![CDATA[<h1 id="react와-redux">react와 redux</h1>
<h2 id="redux를-도입하자">redux를 도입하자..</h2>
<p>여태까지 개발을 하며 사실 redux를 반드시 써야한다! 라는 경험은 사실 드물었다. 전역으로 상태 관리를 해야하는 경우 대부분 contextAPI로 해결되었기때문이다. 
사실 사용하면서도 빈번한 렌더링때문에 걱정이 된 적도 있었으나ㅎㅎ.. 전역 상태 관리 로직을 모두 바꿀만큼의 크리티컬한 케이스를 만난적이 없기때문에 잘 버텨왔다...
그런데, 이번 프로젝트를 진행하며 각각 다른 위치에서 호출되는 A,B라는 컴포넌트가 있고 A컴포넌트에서 api를 호출하면 B컴포넌트에 로딩바를 띄워야 하는 상황이 되었다.
사실 context로 처리하면 매우 간단하나, 로딩상태는 어디에서나 사용될 수 있고 전역에서, 많은 컴포넌트에서 사용될 것이다.  이러한 경우 context보다는 redux로 상태를 관리하는것이 더 좋겠다 싶어 redux를 적용하려고 한다!  그리고 필요할때마다 다시 확인하기 위해 블로그에 기록을 남긴다</p>
<h2 id="redux란">redux란?</h2>
<p>우선 redux가 무엇인지 간단하게 정리하자.
redux는 크로스 컴포넌트 또는 app wide 상태를 위한 상태 관리 시스템이다. 쉽게 전역에서 상태를 관리할수 있도록 도와주는 아이이다.
상태는 크게 3가지로 분리된다. 로컬, 크로스 컴포넌트 , 그리고 앱 와이드
로컬은 말 그대로 해당 컴포넌트 안에서만 관리되는 상태이다.
크로스 컴포넌트와 앱와이드는 그 범위는 다르지만 모두 다수의 컴포넌트에 영향을 미치는 상태를 가리킨다. 일반적으로 props chaining , drilling을 통해 구축이 가능하나 contextAPI, redux와 같은 라이브러리를 사용해서 관리할 수도 있다.</p>
<p>사실 context는 이미 react에 내장되어있다. 그렇다면 왜 굳이 redux를 설치해서 사용하는걸끼?</p>
<h2 id="왜--redux">왜  redux?</h2>
<p>context도 매우 유용한 기능이다. 그러나 context는 잠재적인 단점이 있다.</p>
<ol>
<li>설정과 관리가 매우 복잡해질 수 있다. 작은 앱이라면 괜찮으나 규모가 큰 앱에서는 여러개의 컨텍스트가 사용될때, 과도한 중첩등 복잡한 구조가 될 수 있다.</li>
<li>성능이 떨어진다.
실제로 react팀원이 contextAPI에 대해 데이터가 너무 자주 바뀌는 경우 context가 적합하지 않다고 언급한적이 있다. context는 해당 하나의 저장소에서 단 하나의 상태라도 구독하고 있는 모든 컴포넌트가 재평가되도록 한다. 즉 다른 상태가 업데이트 되더라도 리렌더링이 발생한다.
반면 redux는 특정 상태를 구독하고 있는 컴포넌트만 리렌더링한다. (단 객체타입이 아닌경우)</li>
</ol>
<p>사실 요즘 redux외에도 수많은 상태관리 라이브러리들이 등장하고 있다. 다른 라이브러리에 대해서도 공부가 많이 필요하다ㅠㅠ..</p>
<h2 id="redux의-작동방식">redux의 작동방식</h2>
<h3 id="저장소">저장소</h3>
<p>사실 redux에는 많은 요소가 존재하기때문에 처음 redux를 배울때 가장 어려웠던점이 이 동작원리이다. 
redux는 하나의 중앙 데이터 저장소이다. 여기서 데이터는 상태를 가리킨다. 즉 redux는 하나의 상태 저장소이다.
모든 상태가 하나의 저장소에 저장된다.</p>
<h3 id="데이터-읽기">데이터 읽기</h3>
<p>우리는 이 저장소에서 상태를 가져다가 컴포넌트에서 사용할 수 있다.
정확히는 저장된 상태가 변경되면 컴포넌트에서 그것을 인지하고 컴포넌트를 재평가할 수 있다. 단, 컴포넌트가 저장소가 변경되었다는 것을 알기 위해서는 저장소를 구독해야하며 구독 후에 저장소는 데이터가 변경될때 컴포넌트에게 알려주고 컴포넌트는 변경된 상태를 전달받는다.</p>
<h3 id="데이터-수정">데이터 수정</h3>
<p>단순히 상태를 전달받는것 외에도 상태를 업데이트하는 기능도 필요하다. 여기서 중요한것은 컴포넌트는 저장소를 직접적으로 수정할 수 없다. 즉 데이터는 [저장소 =&gt; 컴포넌트] 의 방향으로만 흐르며 [컴포넌트=&gt;저장소]는 불가능하다.
대신 컴포넌트는 reducer라는 것을 사용해 상태를 수정을 요청할 수 있다.
reducer함수는 상태를 변환하는 역할을 한다.</p>
<p>그렇다면 컴포넌트는 어떻게 reducer에서 수정을 요청할 수 있을까? 
컴포넌트는 reducer에서 수정을 요청하기 위해 action을 사용한다. action을 reducer로 보내서  &quot;이러이러한 action을 수행해줘!&quot; 라고 전달하는 것이다. 여기서 전달이라는 개념은 redux에서 dispatch라는 용어로 사용된다. 즉 component가 action을 reducer로 dispatch하는 것이다.</p>
<p>이제 reducer가 action을 받게 되면 action에 담긴 type과 data에 따라 새로운 상태를 내뱉는다. 그리고 reducer가 내뱉은 이 상태는 그대로 store의 기존 상태를 대체한다.  이제 저장소의 상태가 업데이트 되었으니 이 저장소를 구독중인 컴포넌트는 자신이 요청한대로 변경된 상태를 전달받을 것이다.</p>
<h2 id="기초-설정">기초 설정</h2>
<p>우선 redux 라이브러리를 설치해야한다.
react에서 redux를 조금 더 편하기 사용할 수 있도록 도와주는 라이브러리인 react-redux도 같이 설치한다.</p>
<pre><code>npm install redux react-redux
</code></pre><p>이제 저장소를 만들 폴더를 지정한다</p>
<pre><code>src 
└─store
    ├─ index.js
    └─ [reducer].js</code></pre><p>우선 간단하게 위와 같은 구조로 작성하였다.
action들을 모아두는 actions폴더를 따로 정의하기도 하지만 우선 reducer를 작성할때 참고하기 위해 같은 파일내에 작업할 예정이다.</p>
<h3 id="store-만들기">store 만들기</h3>
<p>가장 먼저 상태 저장소가 될 store를 생성한다. store은 redux의 createStore라는 메서드를 통해 생성이 가능하다.
store을 생성하면 이 저장소를 구독할 컴포넌트들이 store에 접근할 수 있도록 해주어야하는데 이때 방식은 context와 유사하다. react-redux의 요소 provider로 store에 접근할 모든 하위 컴포넌트를 wrap함으로서 하위 컴포넌트들이 store에 접근할 수 있도록 해주어야 한다.
그리고 react-redux가 제공하는 Provider는 redux가 생성한 store에 대한 정보가 없으므로  속성값으로 이를 전달한다.</p>
<pre><code>import { Provider } from &quot;react-redux&quot;;
import store from &quot;./store/index&quot;;
function App() {
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;Provider store={store}&gt;
        &lt;Layout&gt;
                ...
        &lt;/Layout&gt;
      &lt;/Provider&gt;
    &lt;/div&gt;
  );
}</code></pre><h3 id="초기상태-reducer--action--생성자-만들기">초기상태, reducer , action  생성자 만들기</h3>
<p>다음으로 reducer와 action 생성자를 만든다.
action 생성자는 단순하게 객체타입의 액션을 만들어주는 함수이다. 액션은 type이라는 속성을 갖는 일반 객체로서, 액션 생성자를 만들지 않고 바로 type속성을 갖는 객체를 dispatch하여도된다.</p>
<p>reducer는 store폴더 하위에 별도의 reducer.js파일을 만들어서 작성한다. store와 같은 파일에서 관리하여도 되지만 reducer가 여러개가 되는 경우 파일이 과도하게 길어질 수 있다.
reducer는 자동으로 state와 action을 매개변수로 전달받는다. 또한 새로운 상태 객체를 반환해야한다.</p>
<p>초기상태는 api호출 상태를 관리할 것이므로 상태 객체에 status 속성과 error 메시지를 담을 속성을 지정한다.</p>
<p><strong>초기상태</strong></p>
<pre><code>const initialStatusState = {
  status: &quot;&quot;,
  error: null,
};</code></pre><p> api호출 상태를 변경하는 액션을 생성하는 changeStatus 생성자를 생성한다
<strong><em>액션생성자</em></strong></p>
<pre><code>export function changeStatus(data) {
  return {
    type: &quot;CHANGE_STATUS&quot;,
    data: data,
  };
}
</code></pre><p> 리듀서 함수는 action을 받아 새로운 상태와 error를 반환하도록 한다.</p>
<p><em><strong>리듀서</strong></em></p>
<pre><code>const statusReducer = (state = initialStatusState, action) =&gt; {
  switch (action?.type) {
    case SUCCESS:
      return {
        ...state,
        status: SUCCESS,
        error: null,
      };
    case ERROR:
      return {
        ...state,
        status: ERROR,
        error: action.data.error,
      };

    default:
      return state;
  }
};
</code></pre><p>reducer와 store를 모두 작성했다면 둘을 연결시켜야한다. store에 이 reducer에서 상태값을 가져와! 라고 연결을 해주는 과정이다.</p>
<p>이제 초기 설정은 완료되었다!
추가로 상태를 구독할 컴포넌트에서 store를 구독하고 action을 dispatch하도록 설정해야한다.
해당내용은 2편에서 이어서 작성하겠다. </p>
<p>ref :
<a href="https://www.udemy.com/course/best-react/">React 완벽 가이드 with Redux, Next.js, TypeScript</a>
<a href="https://react.vlpt.us/redux/">벨로퍼트와 함께하는 모던 리액트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹과 인증]]></title>
            <link>https://velog.io/@pro-yeong/%EC%9B%B9%EA%B3%BC-%EC%9D%B8%EC%A6%9D</link>
            <guid>https://velog.io/@pro-yeong/%EC%9B%B9%EA%B3%BC-%EC%9D%B8%EC%A6%9D</guid>
            <pubDate>Wed, 15 Jun 2022 01:38:17 GMT</pubDate>
            <description><![CDATA[<p>웹 개발을 하다보면 인증에 관한 이야기를 많이 들을 수 있다. 세션, 토큰 등등...
그 종류도 매우 다양하다. 그러나 사실 인증이 없어도 개발은 가능하고 모두 동작한다. 그렇다면 왜 그렇게 인증에 신경을 쓰고 보안을 위한 수 많은 기술들이 등장하는 것일까?</p>
<h2 id="인증이-필요한-이유">인증이 필요한 이유?</h2>
<p>인증이 필요한 이유는 바로 보호해야할 정보가 있기 때문이다. 예를들어 사이트의 프로필페이지 같은 특정페이지에 인증된 사용자가 아니라면 접근이 불가능해야한다. 또한 회원만이 이용할 수 있는 기능등에도 인증이 필요하다.
그렇다면 인증은 어떻게 진행할 수 있을까, 어떠한 단계를 거치는가?</p>
<h2 id="인증의-단계">인증의 단계</h2>
<p>일반적으로 인증은 두단계로 진행된다. </p>
<ol>
<li>사용자 접근허가(로그인등이 이에 해당)</li>
<li>서버사이드 세션 , 인증토큰</li>
</ol>
<p>간단하게 로그인 통해 받은 허가, 인가를 세션-토큰을 이용해서 유지하는 것이다. 
로그인을 성공하면 해당 사용자는 허가된 사용자가 되는데 서버에 정보를 요청할때마다 로그인정보를 입력할 수 없으며, 허가되었다는것을 단순히 예-아니오로 기록할 수도 없다.
안전하게 해당 사용자가 인증된 사용자라는것을 식별하기 위해 세션-토큰을 사용하는 것이다.
그렇다면 서버사이드세션과 토큰의 차이는 무엇인가?</p>
<h3 id="세션-방식">세션 방식</h3>
<p>서버 사이드 세션은 전통적인 인증방식으로, 사용자 접근을 허가한 서버가 허가를 받은 클라이언트의 고유 ID를 생성하고 저장한뒤 이 정보가 클라이언트에게도 보내는 방법으로 진행된다.
서버와 클라이언트는 이 고유ID를 각각 세션과 쿠키에 모두 저장한 뒤 이 고유ID를 통해 통신을 하게 된다. 이제 클라이언트가 서버에게 보내는 모든 요청에 해당 세션이 같이 보내져서 유효하지않은 ID라면 거부처리가되고  외부에서 임의로 API를 호출하는것을 막을 수 있다.  서버에서 해당 ID를 저장하고 있기때문에 가능하다.</p>
<h4 id="장점">장점</h4>
<p>세션방식을 사용하면 회원별로 고유ID가 부여되고 세션저장소에 회원의 정보가 저장되기때문에 빠르게 회원을 식별하고 응답할 수 있다.</p>
<h4 id="단점">단점</h4>
<p>그러나 세션방식은 서버하이재킹 위험이 있으며(https보안 강화가능) 서버가 모든것을 관리하므로 서버에 부하가 발생할 수도 있다.
또한 때로 백엔드-프론트엔드 서버가 분리된 상태라면 사용이 불가능하다. 예를 들어 여러 사이트에서 사용하는 API라면 접속한 클라이언트의 데이터를 저장해서는 안되며 서버는 이른바 무상태여야한다.</p>
<p>이럴때는 인증토큰을 사용할 수 있다. </p>
<h3 id="인증토큰">인증토큰</h3>
<p>사용자가 로그인을 시도하면 해당정보에 대해 서버가 DB에서 유효성을 확인 후  유효하면 이메일 등 정보로 인코딩 후 인증토큰을 생성하는 방식이다.
이 토큰은 요청한 클라이언트에 보내져 저장되고 서버에는 저장되지않는다. 대신 클라이언트는 요청을 할때마다 헤더에 해당 토큰을 보내고 서버는 자신이갖고있는 코드로 해싱해서 유효한지 판단을 할 수 있다.
토큰은 서버만 아는 비밀키를 사용해 해싱되므로 클라이언트는 토큰을 디코딩할 수 없고 당연히 외부에서도 시크릿키를 모르는한 정보 탈취가 불가능하다
만약 위조되었거나 키가 다르다면 접근을 거부. 
이는 서버가 클라이언트를 식별하는 보안방식이자, 프론트엔드와 백엔드를 분리하도록 허용하는 기법이기도하다
이러한 토큰은 일반적을 JSON웹토큰 = JWT  형식으로 생성된다.</p>
<h4 id="장점-1">장점</h4>
<p>토큰방식은 별도의 저장소 관리가 필요없으며 stateless한 서버를 만드므로 서버 화장에도 용이하다.</p>
<h4 id="단점-1">단점</h4>
<p>반면 토큰방식도 단점이 존재한다. 이미 발급된 토큰에 대해서는 돌이킬 수 없습니다. 세션-쿠키의 경우 만일 쿠키가 악의적으로 이용된다면, 해당하는 세션만 지워버리면 된다. 반면 토큰의 경우 한번 발급이 된다면 만료기간까지 사용이 가능하기 때문에 탈취의 빈도가 더 높을 수 있다. 
또한  인코딩된 토큰의 길이는 매우 길기때문에 자원의 낭비가 발생할 수 있다.</p>
<p>ref
<a href="https://tansfil.tistory.com/58">쉽게 알아보는 서버 인증 1편(세션/쿠키 , JWT)
</a>
<a href="https://www.udemy.com/course/best-react/learn/lecture/28518349">Udemy React완벽가이드 with Redux...</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 런너기법]]></title>
            <link>https://velog.io/@pro-yeong/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%9F%B0%EB%84%88%EA%B8%B0%EB%B2%95</link>
            <guid>https://velog.io/@pro-yeong/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%9F%B0%EB%84%88%EA%B8%B0%EB%B2%95</guid>
            <pubDate>Sat, 28 May 2022 06:05:06 GMT</pubDate>
            <description><![CDATA[<h1 id="런너기법이란">런너기법이란?</h1>
<p>런너기법이란 연결리스트를 순회하며 두개의 포인터를 사용하는 기법이다. &quot;부가 포인터&quot;라고도 한다. 
연결리스트에서 주로 사용되며 연결리스틑 순회할때 두개의 포인터를 사용하는 방법이다. 하나의 포인터는 빠르게 증가하고 하나의 포인터는 느리게 증가하여 병합지점, 중간지점 ,길이등을 판별할때 유용하다.</p>
<p>예를들어,
fast포인터는 2*i씩 증가하고 느린포인터는 i씩 증가한다면, fast포인터가 끝에 도달했을때 slow포인터는 중간 지점에 있게된다.
다시 fast포인터를 기본 리스트로 초기화하고 slow.next에 별도의 변수에 할당한뒤(참조값 유지) slow.next를 null로 설정하면 fast와의 연결점이 끊어짐으로서 한개의 연결리스트가 두개의 리스트로 분할된다.</p>
<pre><code>function patition(head) {
  let fast = head;
  let slow = head;
  while (fast.next !== null &amp;&amp; fast.next.next !== null) {
    slow = slow.next;
    fast = fast.next.next;
  }
  let left = head;
  let right = slow.next;

  slow.next = null;

 return [left ,right]
}</code></pre><h2 id="주의">주의</h2>
<p>짝수와 홀수일때를 구분해야한다.
짝수일때는 slow.next를 분리점으로 한다면 2등분이 가능하나, 홀수일 경우 slow가 가리키는 지점이 중앙지점이 된다.
만약 Palindrome 문제를 푼다면 가운데 요소는 필요가 없다. 이럴때, slow 해당 값을 버린다고 생각하면된다.</p>
<h2 id="해결할-문제">해결할 문제</h2>
<ol>
<li><del>루프를 돌릴때 , fast.next &amp; fast.next.next만 비교하는 경우가 많던데 fast는 비교를 안해도되는가? undefined오류가 떨어질 것이라고 생각하는데 이점에 대해 의문이 남는다.</del>
해결: 이미 while문의 조건으로 fast.next.next가 null이 아님을 확인했으므로 fast.next.next를 할당받은 fast는 null이 될 수 없다!</li>
<li></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[call과 apply]]></title>
            <link>https://velog.io/@pro-yeong/call%EA%B3%BC-apply</link>
            <guid>https://velog.io/@pro-yeong/call%EA%B3%BC-apply</guid>
            <pubDate>Mon, 09 May 2022 07:13:47 GMT</pubDate>
            <description><![CDATA[<p>메소드를 사용하다보면 가끔 ReferenceError가 뜨며 참조할 수 없다고 나올때가 있다.
경험상 90%가 인수를 제대로 넘기지 않았거나 this를 잃어버린 상황이다.
객체 내 메소드를 사용할때 this를 제대로 바인딩시키는게 매우 중요하다.
메소드 내 this가 제대로된 참조값을 갖도록하기 위해 call, apply, bind 를 사용할 수 있다.</p>
<h2 id="call">call</h2>
<blockquote>
<p>call
 설명  : this를 명시적으로 고정해 함수를 호출할 수 있게 해주는 내장메소드.
 ex: function.call(context,[arg1,arg2...])</p>
</blockquote>
<p>call에 첫번째인수로 객체를 명시해주면 호출되는  메서드의 this가 명시된 객체로 고정된다.
call에 나머지 인수들은 호출되는 메서드의 매개변수로 넘어간다. </p>
<p>예를들어</p>
<pre><code>const student={
    name:&quot;John&quot;,
    age:16,
    addr:&quot;seoul&quot;,
       introduce (greetings ){
     return greetings + &quot;my name is &quot; + this.name;
    }
}</code></pre><p>student 라는 객체가 있으며 위와같은 속성들을 가졌다고 하자.
만약 student.introduce(&quot;hello&quot;)를 호출한다면 의도대로 동작하지만, student.introduce를 임시변수 say 복사한뒤 say(&quot;hello&quot;)를 호출한다면 오류가 발생하거나 의도하지 않은 방향(undefined 참조)으로 작동할 수 있다.
introduce 메서드 내 this.name에서 this 가 undefined를 가리키기 때문이다. 
이러한 상황을 해결하기 위해서 call을 사용할 수 있다.</p>
<pre><code>let saySomething ;
const say = student.introduce;
saySomething = say(&quot;hello!!&quot;);
console.log(saySomething); //hello!!my name is undefined

saySomething = say.call(student, &quot;bye!&quot;);
console.log(saySomething); //bye!my name is John
</code></pre><p>call은 위와같이context를 지정하여 this가 바인딩되도록 할때 유용하다.</p>
<h2 id="apply">apply</h2>
<blockquote>
<p>apply
설명 : this를 명시적으로 고정해 함수를 호출할 수 있게 해주는 내장메소드.
ex: function.call(context,[args])</p>
</blockquote>
<p>apply는 this를 바인딩시켜주는 역할을 한다는점에서는 비슷하지만 유사배열객체를 인수로 넘길 수 있다는점에서 차이가 있다.</p>
<p>call을 사용해 1개이상의 인수를 넘길때는 각 인수를 나열해주어야하며, 만약 배열을 인수로 넘기기위해서는 spread문법을 이용해 인수로 넘겨야한다.
반면 apply을 사용하여 복수의 인수를 넘길때 인수가 담긴 배열을 통째로 넘기면 순서에 따라 매개변수가 매핑된다.</p>
<p>예시를 들어 비교하면 아래와 같다.</p>
<pre><code>const student = {
  name: &quot;John&quot;,
  age: 16,
  addr: &quot;seoul&quot;,
  introduce(a, b) {
    return `${a} ${b}  ${this.name}`;
  },
};
student.introduce(&quot;hello...&quot;);

const say = student.introduce;

const saySomething = say.call(student, &quot;bye!&quot;, &quot;hello&quot;);
const saySomething2 = say.apply(student, [&quot;bye!&quot;, &quot;hello&quot;]);
console.log(saySomething); //bye!my name is John
console.log(saySomething2); //bye!my name is John
</code></pre><p>
인수가 넘어가는 형태를 제외하고 두 메서드는 동일하지만 자바스크립트 엔진내부에서 apply를 최적화하기 때문에 apply를 사용하는 것이 조금 더 빠르다.</p>
<p>실제로 일부 내장함수에 대해서는 apply를 이용하면 배열과 루프없이 쉽게 처리할 수 있다고 한다. 예를들어 Math.max(...args)를 구하기 위해 Math.max.apply([args])를 사용하는것이 더 효율적일 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터저장-2. localStorage]]></title>
            <link>https://velog.io/@pro-yeong/%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%A0%80%EC%9E%A5-2.-localStorage</link>
            <guid>https://velog.io/@pro-yeong/%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%A0%80%EC%9E%A5-2.-localStorage</guid>
            <pubDate>Mon, 18 Apr 2022 12:02:35 GMT</pubDate>
            <description><![CDATA[<p>클라이언트에서 데이터를 저장하는 방법 중 하나로 localStorage와 sessionStorage가 있다.</p>
<p>두 객체는 브라우저 내에 데이터(키-값)을 저장할 수 있게 해준다.
쿠키와 가장 큰 차이점은 서버가 아닌 브라우저내에만 저장된다는 것이다.</p>
<h1 id="localstorage">localStorage</h1>
<p>localStorage는 브라우저에 값을 저장할수 있도록 도와주는 객체이다. localStorage에 저장한 데이터는 서버로 전송되지 않는다. 모든 일은 자바스크립트내에서 수행된다. </p>
<h2 id="특징">특징</h2>
<p>localStorage의 특징은 다음과 같다.</p>
<ol>
<li>쿠키와 다르게 서버로 전송되지 않는다.</li>
<li>getItem, setItem,removeItem등의 메서드로 접근이 가능하다.</li>
<li>오리진 , 도메인이 같을 경우 데이터는 모든탭과 창에서 공유된다.</li>
<li>iterable객체가 아니므로 순회가 불가능하다. </li>
<li>값과 데이터로 문자열만 사용이 가능하다. 형변환이 자동으로 일어난다.</li>
</ol>
<h1 id="sessionstorage">sessionStorage</h1>
<p>sessionStorage 또한 localStorage처럼 자바스크립트 내에서 데이터를 저장하기위한 객체이다. localStorage와 제공하는 메서드와 속성들도 동일하다. 
다만, sessionStorage는 몇가지 제약사항이 존재한다.</p>
<h4 id="sessionstorage의-제약사항">sessionStorage의 제약사항</h4>
<ol>
<li>storage는 현재 떠있는 탭에서만 유효하다. 즉, 같은 도메인, 같은 페이지여도 다른 탭에 떠있다면 정보공유가 불가능하다.</li>
<li>페이지가 종료되면 데이터는 사라진다. (새로고침시에는 유지된다.)</li>
</ol>
<p>이러한 제약사항들때문에 sessionStorage는 잘 사용되지 않는다고 한다.</p>
<h2 id="storage-이벤트">storage 이벤트</h2>
<p>sessionStorage나 localStorage에 데이터 변화가 발생할때 해당 스토리지를 공유하는 모든 페이지에서 storage이벤트가 실행된다.
즉 탭 두개에 A라는 사이트를 띄어두었을때, 하나의 탭에서 Storage가 갱신되면 다른 탭에 Storage이벤트가 발생하면서 변경사항이 공유된다.
이러한 기능을 이용해 오리진이 같은 창끼리 메시지를 교환할 수 있다. </p>
<p>ref: javascript info <a href="https://ko.javascript.info/localstorage">localStorage와 sessionStorage</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터 저장 -1. 쿠키,세션]]></title>
            <link>https://velog.io/@pro-yeong/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%80%EC%9E%A5-1.-%EC%BF%A0%ED%82%A4%EC%84%B8%EC%85%98</link>
            <guid>https://velog.io/@pro-yeong/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%80%EC%9E%A5-1.-%EC%BF%A0%ED%82%A4%EC%84%B8%EC%85%98</guid>
            <pubDate>Mon, 18 Apr 2022 11:44:07 GMT</pubDate>
            <description><![CDATA[<p>브라우저에 데이터를 저장하는 방법은 여러가지가 있다. </p>
<p>쿠키, 세션, 캐쉬들이 웹에 데이터를 저장하는 방법 중 하나라는 것은 알고 있으나 정확한 차이점, 언제 어떤 때에 무엇을 써야하는지 명확하지가 않았다.</p>
<p>이번기회에 각 기술들의 차이를 명확하게 정리해보려고 한다!</p>
<p>우선 가장 먼저 쿠키와 세션을 알아보자.</p>
<h1 id="쿠키">쿠키</h1>
<p>쿠키는 서버에 의해 응답받은 정보가 브라우저에 저장되는 데이터 저장 방식으로 주로 인증정보에 사용된다.
클라이언트측에서 저장를 하기보다 서버쪽에서 HTTP 응답헤더에 set-cookie에 내용을 넣어 응답하면 브라우저가 해당 내용을 브라우저에 저장한다.
이제 해당 쿠키를 생성하도록한 서버 (사이트)에 접속할때마다 쿠키의 내용이 요청헤더에 담겨 함께 전달된다. </p>
<h3 id="쿠키가-저장되는-순서는-다음과-같다">쿠키가 저장되는 순서는 다음과 같다.</h3>
<ol>
<li>사용자가 로그인을 요청하면 서버가 응답헤더 set-Cookies에 정보를 저장해 응답한다.</li>
<li>브라우저가 해당 정보를 쿠키에 자동 저장</li>
<li>같은 도메인(명시에 따라 서브도메인포함)에 정보를 요청하면 요청 HTTP Cookie헤더에 인증정보가 함께 담겨 서버로 요청</li>
<li>서버가 요청헤더를 읽어 사용자를 식별</li>
</ol>
<h3 id="쿠키에-접근하기">쿠키에 접근하기</h3>
<p>자바스크립트를 통해 쿠키에 접근하거나 쿠키를 작성하는것 또한 가능하다.
document.cookie 속성을 사용하면 되는데 주의할 점은 cookie 프로퍼티는 데이터 프로퍼티가 아닌 접근자 프로퍼티이다! (getter,setter)</p>
<h3 id="쿠키의-한계">쿠키의 한계</h3>
<p>쿠키는 한계가 존재한다. 먼저 하나의 쿠키는 4KB를 넘을 수 없다.
또한, 도메인 하나당 저장할 수 있는 쿠키의 개수는 20여개이다. </p>
<h3 id="그외">그외</h3>
<p>그외에도 쿠키에 설정할 수 있는 다양한 옵션이 있다.
Secure, HttpOnly, SameStie, path, domain..
대부분 쿠키의 보안을 강화하기 위한 옵션들이다.  쿠키는 브라우저 자체가 저장되기 때문에 보안적으로 안전하다고 할 수 없다. 중요한 정보는 쿠키에 저장해서는 안된다.</p>
<h1 id="세션">세션</h1>
<p>세션은 쿠키와 비슷한 역할을 한다. 둘의 큰 차이점은 데이터가 저장되는 위치이다. 
쿠키는 브라우저, 즉 클라이언트측에 저장되나  세션은 서버측에 저장된다는 것이 가장 큰 차이이다. 세션은 단순히 세션아이디만은 클라이언트측에 보내 저장하도록한다. 그리고 그 세션아이디에 해당하는 실제 값은 세션아이디를 키값으로 서버측에 저장된다.</p>
<h3 id="세션이-동작하는-순서는-다음과-같다">세션이 동작하는 순서는 다음과 같다.</h3>
<ol>
<li>사용자가 로그인을 요청하면 서버가 응답헤더 set-Cookies의 session id에 식별정보를 넣어서 응답한다. 그리고 서버측에 session-id를 키값으로 정보를 저장해둔다. </li>
<li>브라우저가 해당 정보를 쿠키에 저장한다. </li>
<li>창이 꺼지기 전까지 같은 도메인(명시에 따라 서브도메인포함)에 정보를 요청하면 요청 HTTP Cookie헤더에 session-id가 담겨 함께 요청된다.</li>
<li>서버가 요청헤더를 읽어 session-id가 존재한다면 해당하는 값을 응답하고 없으면 다시 session-id를 생성해 응답에 함께 전달한다.</li>
</ol>
<h3 id="세션에-접근하기">세션에 접근하기</h3>
<p>클라이언트측에는 단순히  세션ID만 저장되기때문에 정보에 접근할 수 없다. 서버를 통해서만 정보에 접근이 가능하다.</p>
<h3 id="세션의-한계">세션의 한계</h3>
<p>클라이언트측에는 단순히  세션ID만 저장되고 서버에 요청하는 값이므로 서버의 접속이 가능하다면 제한되는 용량이나 갯수제한은 없다.</p>
<h3 id="그외-1">그외</h3>
<p>세션은 쿠키와 달리 브라우저가 종료되면 저장된 세션정보가 모두 사라진다. </p>
<h1 id="쿠키-vs-세션">쿠키 vs 세션</h1>
<p>그렇다면 쿠키와 세션 중 어느것을 사용하는것이 더 좋을까.
쿠키는 세션보다 속도가 빠르나 보안적으로는 좋지않다. 세션은 보안적으로는 쿠키보다 안전하나 속도가 느리고 서버에 부하를 줄 수 있다.
간단한 정보라면 쿠키를 사용하고 보안적으로 중요한 정보라면 토큰 기반의 인증방식을 채택하는것이 좋다고 한다.</p>
<p>ref: <a href="https://ko.javascript.info/cookie">자바스크립트 인포 cookie</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[async와 defer 그리고 use strict]]></title>
            <link>https://velog.io/@pro-yeong/async%EC%99%80-defer-%EA%B7%B8%EB%A6%AC%EA%B3%A0-use-strict</link>
            <guid>https://velog.io/@pro-yeong/async%EC%99%80-defer-%EA%B7%B8%EB%A6%AC%EA%B3%A0-use-strict</guid>
            <pubDate>Mon, 18 Apr 2022 09:26:40 GMT</pubDate>
            <description><![CDATA[<h1 id="async-와-defer의-비교">async 와 defer의 비교</h1>
<p>html에 javscript를 포함하는 방법은 여러가지가 있다. </p>
<h2 id="1--head-태그에-안에-속성없이-script태그를-포함하여서-사용-하는-경우">1.  head 태그에 안에 속성없이 script태그를 포함하여서 사용 하는 경우</h2>
<pre><code>&lt;head&gt;
    &lt;script src=&quot;main.js&gt;&lt;/script&gt;
&lt;/head&gt;</code></pre><p>사용자가 html 파일 즉, 웹페이지를 로딩하면 브라우저가 코드의 가장 상단부터 한줄씩 코드를 읽고 실행한다.  위와같이 코드를 작성할 경우 html 코드를 파싱하다가 script태그를 만나면 html을 파싱하는 과정은 잠깐 멈추고 해당 스크립트 파일을 다운로드하고 곧 바로 실행하고 나서야 html을 파싱한다. 이 경우, html의 로딩이 javascript 코드가 모두 실행되고 난 후 진행되므로 많은 시간이 소요되고 사용자의 입장에서는 웹페이지의 로딩이 느리다고 느낄 수 있다.</p>
<h2 id="2-body의-끝에-script를-추가">2. body의 끝에 script를 추가</h2>
<p>body끝에 script요소가 있다면 html을 모두 파싱하고 나서 javascript를 다운로드받고 실행하게된다. 페이지가 가장먼저 로드되므로 사용자입장에서는 빠르게 로딩될 수 있으나 만약 웹사이트가 자바스크립에 의존적이라면 정상적으로 화면이 로딩될 수 없어 다시 자바스크립트의 다운로드, 실행시간을 기다려야 한다.</p>
<h2 id="3-head안에-script를-이용하되-async라는-속성값을-사용">3. head안에 script를 이용하되 async라는 속성값을 사용</h2>
<p>async를 사용하면 html을 파싱하다가 script요소를 만난다면 html파싱과 동시에 js파일을 다운받는 병렬구조로 작업이 진행된다. 이후 js파일 다운로드가 완료되면 html 파싱을 멈추고 js를 실행하고 남은 html을 파싱한다. 시간은 감소하나 자바스크립트내에서 돔요소를 조작한다면 오류가 발생할 수 있다. 그리고 여전히 js를 실행할 때 html의파싱이 멈추므로 사용자 경험에 부정적인 요소가 존재한다.</p>
<h2 id="4-ead안에-script를-이용하되-defer-속성값을-사용">4. ead안에 script를 이용하되 defer 속성값을 사용</h2>
<p>defer속성을 사용하면 html을 파싱하다가 script요소를 만났을때 js파일의 다운로드와 html의 파싱이 병렬구조로 진행된다. 여기까지는 async와 유사하나 defer의 경우 js파일의 실행을 다운로드 직후가 아닌 html파싱이 완료되고 나서 마지막에 진행한다. 이 경우 병렬구조로 진행되므로 다운로드 시간을 감소하며 html이 먼저 로딩되므로 사용자는 로딩된 화면을 먼저볼 수 있다. 또한 html ,js가 서로 의존적이여도 실행 시간을 최소화할 수 있는 가장 효율적인 방법이라고 할 수 있다.</p>
<h2 id="-여러개의-script를-실행할-경우">+ 여러개의 script를 실행할 경우</h2>
<p>async를 사용하면 작성순서, 의도와는 무관하게 다운로드가 완료되는 순서대로 실행이 되므로 js 파일이 순서에 의존적이라면 정상적으로 작동하지않을 수 있다. 
반면 defer를 사용하면 다운로드를 모두 완료 후 위에서부터 차례대로 실행되므로 원하는 순서대로 실행이 가능하다. </p>
<h1 id="use-script">use script</h1>
<p>javascript를 사용할 때, use strict를 선언하는것이 좋다.
자바스크립트는 매우 유연한 언어이므로 하위호환을 위해 새롭게 제정된 ES5에서 더이상 존재하지 않는 기능들도 사용할 수 있도록 지원한다.새롭게 정의된 변경사항이 제대로 실행되게 하기 위해서는  use strict를 선언하여 해당 스크립트는 ES5 문법을 따르겠다는 &#39;use strict&#39; 선언이 필요하다.
*<em>! use strict는 반드시 최상단에 위치시켜야한다. *</em></p>
<p>ref:
<a href="https://ko.javascript.info/strict-mode">javascript.ingo</a>
<a href="https://www.youtube.com/watch?v=tJieVCgGzhs&amp;t=1063s">elly 드림코딩</a></p>
]]></description>
        </item>
    </channel>
</rss>