<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>code_alpacat.log</title>
        <link>https://velog.io/</link>
        <description>In the future, I'm never gonna regret, cuz I've been trying my best for every single moment.</description>
        <lastBuildDate>Thu, 20 Oct 2022 18:03:35 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>code_alpacat.log</title>
            <url>https://images.velog.io/images/code_alpaca/profile/5d3cdbc4-2456-48af-9f43-e15dec77ee05/galina-bugaevskaya-koty-vezde-cats-everywhere (9)-815210db-03f2-4221-a402-b9337a6cc943.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. code_alpacat.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/code_alpaca" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[React Query - Mutation]]></title>
            <link>https://velog.io/@code_alpaca/React-Query-Mutation</link>
            <guid>https://velog.io/@code_alpaca/React-Query-Mutation</guid>
            <pubDate>Thu, 20 Oct 2022 18:03:35 GMT</pubDate>
            <description><![CDATA[<h2 id="mutation">Mutation</h2>
<blockquote>
<p>Mutation은 데이터를 읽는게 아닌 변경하는 로직에 대한 내용이다.
<code>CREATE</code> <code>UPDATE</code>, <code>DELETE</code>의 역할을 수행한다.</p>
</blockquote>
<h3 id="usemutation의-특징"><code>useMutation</code>의 특징</h3>
<ul>
<li><code>mutate</code> 함수를 반환한다.</li>
<li>캐싱할 필요가 없으므로 쿼리 키를 사용하지 않는다.</li>
<li>캐시가 존재하지 않으므로, <code>isFetching</code>이 없다.</li>
<li><code>retry</code>를 3회 시도하는 <code>useQuery</code>와는 다르게 <code>retry</code>가 일어나지 않는다. 만약 <code>retry</code>로 실패시 재시도하려면, 설정이 필요하다</li>
</ul>
<h3 id="사용법">사용법</h3>
<ul>
<li>기본적으로 <code>useQuery</code>와 같이 <code>isLoading</code>등이 존재하므로, 충돌을 피하기 위해 구조분해할당을 피해야할 경우가 있다.</li>
<li><code>mutate</code>메서드를 통해 인자를 받을 수 있다.</li>
</ul>
<pre><code class="language-jsx">import { useQuery, useMutation } from &quot;@tanstack/react-query&quot;;

async function deletePost(postId) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/postId/${postId}`,
    { method: &quot;DELETE&quot; }
  );
  return response.json();
}


//isLoading 등 이미 선언된 요소들과의 충돌을 피함.
const deleteMutation = useMutation((postId) =&gt; deletePost(postId));

//jsx
return (
    &lt;&gt;
      &lt;h3 style={{ color: &quot;blue&quot; }}&gt;{post.title}&lt;/h3&gt;
      &lt;button onClick={() =&gt; deleteMutation.mutate(post.id)}&gt;
        Delete
      &lt;/button&gt;
      {deleteMutation.isError &amp;&amp; &lt;p&gt;에러로 인해 지우지 못했습니다.&lt;/p&gt;}
      {deleteMutation.isLoading &amp;&amp; &lt;p&gt;지우는 중입니다.&lt;/p&gt;}
      {deleteMutation.isSuccess &amp;&amp; &lt;p&gt;데이터가 성공적으로 지워졌습니다.&lt;/p&gt;}
    &lt;/&gt;
  );</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Query - Prefetch]]></title>
            <link>https://velog.io/@code_alpaca/React-Query-Prefetch-gf3aylx8</link>
            <guid>https://velog.io/@code_alpaca/React-Query-Prefetch-gf3aylx8</guid>
            <pubDate>Thu, 20 Oct 2022 17:02:09 GMT</pubDate>
            <description><![CDATA[<h2 id="prefetch">Prefetch</h2>
<blockquote>
<p>비동기 요청은 받아오는 속도가 느리고, 데이터 양이 방대할수록 오래걸린다.
사용자 경험을 위해 데이터를 미리 받아 캐싱해놓으면, 새로운 데이터를 받기 전에 사용자가 캐싱된 데이터를 볼 수 있어 UX에 큰 영향을 끼친다.</p>
</blockquote>
<h3 id="특징">특징</h3>
<ul>
<li>데이터를 미리 캐싱해준다.</li>
<li>기본 값으로 즉시 stale 상태가 된다.</li>
<li>refetching되는 사이에 화면에 임시적으로 보여준다.<ul>
<li>cachetime이 만료되지 않는 가정하에!</li>
</ul>
</li>
</ul>
<h3 id="사용법">사용법</h3>
<ul>
<li>prefetch는 useQueryClient의 메소드로 사용한다.</li>
<li>불러오는 시점은 언제일까?<ul>
<li>페이지가 1에서 2로 넘어갈 때, 미리 3의 데이터를 받아와 쿼리 키에 캐싱한다.</li>
<li>그러면, 다음 페이지로 넘어갈 때, 사용자는 미리 받아온 stale 상태의 데이터를 기다림 없이 볼 수 있다.</li>
</ul>
</li>
<li><code>useEffect</code>를 사용해 현재 페이지의 상태가 바뀔 때마다 의존성에 의해 다음 페이지의 데이터를 요청하는 방법을 쓴다.</li>
</ul>
<pre><code class="language-js">import { useEffect, useState } from &quot;react&quot;;
import { useQuery, useQueryClient } from &quot;@tanstack/react-query&quot;;

async function fetchPosts(pageId) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts?_limit=10&amp;_page=${pageId}`
  );
  return response.json();
}

const queryClient = useQueryClient();
  useEffect(() =&gt; {
    if (currentPage &lt; maxPostPage) {
      const nextPage = currentPage + 1;
      queryClient.prefetchQuery([&quot;posts&quot;, nextPage], () =&gt;
        fetchPosts(nextPage)
      );
    }
  }, [currentPage, queryClient]);

  const { data, isLoading, isError } = useQuery(
    [&quot;posts&quot;, currentPage],
    () =&gt; fetchPosts(currentPage),
    { staleTime: 2000, keepPreviousData: true }
  );</code></pre>
<h2 id="isfetching-vs-isloading">*isFetching vs isLoading</h2>
<blockquote>
<h3 id="isfetching">isFetching</h3>
</blockquote>
<ul>
<li><code>isFetching</code>은 비동기 함수가 아직 데이터를 가져오지 못했을 때, true를 반환한다.</li>
</ul>
<blockquote>
<h3 id="isloading">isLoading</h3>
</blockquote>
<ul>
<li><code>isLoading</code>은 비동기 함수를 가져오지 못했으며, 캐싱된 데이터도 존재하지 않을 때, true를 반환한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/code_alpaca/post/6f0b98e2-3edd-49e2-b54f-b5825e12a2ee/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Query - Pagenation]]></title>
            <link>https://velog.io/@code_alpaca/React-Query-Prefetch</link>
            <guid>https://velog.io/@code_alpaca/React-Query-Prefetch</guid>
            <pubDate>Thu, 20 Oct 2022 16:35:19 GMT</pubDate>
            <description><![CDATA[<h2 id="1-pagination">1. Pagination</h2>
<blockquote>
<ul>
<li>데이터를 페이지마다 동적으로 가져와보자.</li>
</ul>
</blockquote>
<h3 id="어떻게-요청-한-번에-하나씩-캐싱하지">어떻게 요청 한 번에 하나씩 캐싱하지?</h3>
<ul>
<li>다음의 예시를 보자.</li>
</ul>
<pre><code class="language-js">async function fetchPosts(pageId) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts?_limit=10&amp;_page=${pageId}`
  );
  return response.json();
}

const { data, isLoading, isError } = useQuery([&quot;posts&quot;], () =&gt; fetchPosts(currentPage));</code></pre>
<ul>
<li>위와 같이 데이터를 불러와서 적용하면 페이지를 넘길 때, 잘 받아와질까?</li>
</ul>
<h3 id="정답은-no">정답은 No.</h3>
<ul>
<li>React Query는 기본적으로 쿼리키 <code>posts</code>에 캐싱하도록 선언되어있다.</li>
<li>즉, 페이지를 아무리 넘겨도 캐싱된 데이터는 같은 쿼리 키를 공유하므로 바뀌지 않는다.</li>
<li>그러므로, 아래와 같이 리스트에 페이지마다 다른 쿼리 키에 캐싱되도록 해줘야한다.</li>
</ul>
<pre><code class="language-js">async function fetchPosts(pageId) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts?_limit=10&amp;_page=${pageId}`
  );
  return response.json();
}

const { data, isLoading, isError } = useQuery([&quot;posts&quot;, PAGE_ID], () =&gt; fetchPosts(currentPage));</code></pre>
<ul>
<li>이제 제대로 작동하는 것을 볼 수 있다.</li>
</ul>
<h4 id="위의-usequery는-이제-page_id에-의존성을-갖게-되었고-page_id가-바뀌면-새로-요청을-보내-해당-페이지를-출력해준다">위의 useQuery는 이제 PAGE_ID에 의존성을 갖게 되었고, PAGE_ID가 바뀌면 새로 요청을 보내 해당 페이지를 출력해준다.</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[FrontEnd 웹 성능 최적화(1)]]></title>
            <link>https://velog.io/@code_alpaca/FrontEnd-%EC%9B%B9-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%941</link>
            <guid>https://velog.io/@code_alpaca/FrontEnd-%EC%9B%B9-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%941</guid>
            <pubDate>Thu, 20 Oct 2022 16:14:20 GMT</pubDate>
            <description><![CDATA[<h1 id="블로그-사이트-최적화">블로그 사이트 최적화</h1>
<h3 id="1-lighthouse-툴을-활용한-페이지-검사">1. LightHouse 툴을 활용한 페이지 검사</h3>
<ul>
<li><p><code>Category</code></p>
<ul>
<li>무엇을 위한 검사를 할지 항목을 선택 가능</li>
</ul>
</li>
<li><p><code>Device</code></p>
<ul>
<li>기기를 선택할 수 있음.<ul>
<li>Mobile</li>
<li>Desktop</li>
</ul>
</li>
</ul>
</li>
<li><p><code>Plugins</code></p>
<ul>
<li>커스텀 플러그인 세팅 가능</li>
</ul>
</li>
<li><p><code>Generate Report</code></p>
<ul>
<li>성능 검사를 완료하면 아래와 같이 보여준다.</li>
<li>1.<code>METRICS</code> - 검사의 지표를 통해 성능을 확인할 수 있다.</li>
<li>2.스크린 샷으로 랜더링된 페이지 목록을 볼 수 있다.</li>
<li>3.<code>Opportunities</code> - 리소스의 관점에서 <strong>로딩 성능 최적화</strong>에서 어느 부분을 개선할 수 있을지 문제점과 문제점의 해결 방안을 제시해 준다.</li>
<li>4.<code>Diagnostics</code> - 페이지의 실행 관점에서 <strong>렌더링 성능 최적화</strong>에서 문제점과 해결 방안을 제시해 준다.</li>
<li><img src="https://user-images.githubusercontent.com/90893428/190467126-e9bde866-40c7-4670-a3d7-fbdf22dce8d3.png" alt="image"></li>
</ul>
</li>
</ul>
<h3 id="2-opprtunities-항목을-통한-최적화">2. Opprtunities 항목을 통한 최적화</h3>
<ul>
<li>이미지 사이즈 최적화를 먼저 보겠다.</li>
<li>아래의 이미지들을 보면 상당히 크기가 크다.</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/90893428/190468896-1cd1268b-9e62-4451-9941-5e4298da7968.png" alt="image"></p>
<ul>
<li>이 아래의 이미지를 보면 랜더링된 이미지는 고작 120 * 120이지만 불러온 이미지의 크기는 1200 * 1200임을 알 수 있다.</li>
<li>넓이로 따지면 100배 정도는 더 크다.</li>
<li>그러므로 120 * 120 크기의 이미지를 사용하는 것이 옳은가?<ul>
<li>해상도에 따라서 더 많은 픽셀을 요구할 수 있으므로 2배 정도 크기를 사용해보자.</li>
</ul>
</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/90893428/190470905-ca9b14dd-9323-4fcd-92cb-2a0c6e8ff208.png" alt="image"></p>
<ul>
<li>아래와 같이 API를 통해 이미지의 주소를 가져온다.</li>
<li>이런 경우에는 이미지를 줄이기 쉽지 않다.<ul>
<li>이미지 <strong>CDN</strong>을 활용해 해결한다!</li>
</ul>
</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/90893428/190472068-99b949d5-94e7-433b-a695-90c5dea5f48f.png" alt="image"></p>
<h4 id="cdn이란">CDN이란?</h4>
<blockquote>
<p>Contents Delivery Network의 약자로 물리적 거리의 한계를 극복하기 위해 소비자(사용자)와 가까운 곳에 컨텐츠 서버를 두는 기술</p>
<p>ex) 미국 원본 서버에서 미리 한국 서버에 이미지를 복사해두면, 사용자가 요청할 때, 미국으로 요청을 보내지 않아도 된다.</p>
</blockquote>
<h4 id="image-cdn이란">image CDN이란?</h4>
<blockquote>
<p>image processing CDN</p>
<p>Image CDN은 기본적인 CDN 개념과 이미지 처리 과정을 거쳐 사용자에게 전달하는 과정이다. 사이즈, 포맷 등을 모두 처리할 수 있다.</p>
<h4 id="httpcdnimagecomsrcimg-srcwidth200height100">http:cdn.image.com?src=<strong>[img src]</strong>&amp;<strong>width=200</strong>&amp;<strong>height=100</strong></h4>
<p>위와 같이 사용할 수 있다. 원본 이미지 소스를 width: 200, height: 100으로 가공하는 소스이다.</p>
</blockquote>
<ul>
<li>Imagix와 같은 사이트에서 최적화 소스 솔루션을 제공한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Native 부수기(1)]]></title>
            <link>https://velog.io/@code_alpaca/React-Native-%EB%B6%80%EC%88%98%EA%B8%B01</link>
            <guid>https://velog.io/@code_alpaca/React-Native-%EB%B6%80%EC%88%98%EA%B8%B01</guid>
            <pubDate>Sun, 16 Oct 2022 15:37:06 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>React Native의 동작 원리</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/code_alpaca/post/a48193c8-17db-4d32-8fe8-4d9bba1abd28/image.png" alt=""></p>
<ul>
<li>React Native는 javascript기반의 마크업 언어를 iOS와 안드로이드 코드로 변환해 준다.</li>
<li>react native는 bridge를 통해 안드로이드, ios에 요청을 보낸다.
앱을 만들기 위해서는 JavaScript, Markup/Styling 뿐만 아니라 위 그림에 나온 모든 인프라를 설치해야만 한다. </li>
<li>물론 Expo는 모든 과정을 대신 수행해 Javascript와 Markup/Styling만 진행하면 되도록 해준다. 
하지만, 치명적인 단점이 있다.<ul>
<li>Expo 서버에서 동작하므로 가끔 불안정함.</li>
<li>상당히 앱 사이즈가 비대해짐. (Expo의 모든 기능을 내장한 채라서)</li>
<li>세부 설정을 건들이기 상당히 불편함.</li>
</ul>
</li>
</ul>
<h4 id="즉-기본적으로-javascript로-읽고-동작하는-코드를-react-native가-native-앱의-일부로-만들고-해석해주는-일종의-번역기라고-생각하면-된다">즉, 기본적으로 JavaScript로 읽고 동작하는 코드를 React Native가 Native 앱의 일부로 만들고 해석해주는 일종의 번역기라고 생각하면 된다.</h4>
<h2 id="1-expo-vs-react-native-cli-무엇을-사용할까">1. Expo vs React Native CLI 무엇을 사용할까?</h2>
<blockquote>
<p>Expo의 장단점</p>
</blockquote>
<h4 id="장점">장점</h4>
<ul>
<li><p>React Native를 처음 개발하는 사람에게 편리하다.</p>
</li>
<li><p>React Natvie를 위한 기본 설정이 미리 세팅되어있다.</p>
</li>
<li><p>Android / Xcode를 설치하지 않아도 QR코드를 통해 에뮬레이터를 실행시킬 수 있다.</p>
</li>
<li><p>배포가 매우 쉽다.</p>
<h4 id="단점">단점</h4>
</li>
<li><p>Java, kotlin, swift 등의 네이티브 모듈을 추가 할 수 없다.</p>
</li>
<li><p>기본 파일 크기가 크다</p>
</li>
<li><p>기능이 많은 앱 개발에는 부적합하다.</p>
</li>
<li><p>블루투스가 안된다.</p>
</li>
<li><p>Eject로 다시 세팅하는게 상당히 번거롭다.</p>
</li>
</ul>
<blockquote>
<p>React Native CLI의 장단점</p>
</blockquote>
<h4 id="장점-1">장점</h4>
<ul>
<li>네이티브로 앱을 개발할 수 있다.</li>
<li>기존 네이티브 언어로 개발을 이어나갈 수 있다.</li>
<li>네이티브 파일들을 직접 수정할 수 있다.</li>
<li>새로운 기능의 모듈을 직접 만들어 사용할 수 있다.</li>
<li>Expo 패키지 이용이 가능하다.</li>
</ul>
<h4 id="단점-1">단점</h4>
<ul>
<li>초기 환경 구성이 어렵고 오래걸린다. 옳은 방법으로 세팅하기도 어렵다.</li>
<li>프로젝트를 위해 Android / Xcode를 전부 설치해 빌드 및 배포를 해야한다.</li>
<li>배포와 업데이트 시간이 상대적으로 오래걸린다.</li>
<li>안드로이드, IOS에 대한 폴더 구조에 대한 기본지식이 필요하다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Recoil, 왜 사용해야할까?]]></title>
            <link>https://velog.io/@code_alpaca/Recoil1</link>
            <guid>https://velog.io/@code_alpaca/Recoil1</guid>
            <pubDate>Sat, 15 Oct 2022 07:21:46 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Recoil, 왜 사용할까?</p>
</blockquote>
<ul>
<li>Context API는 Provider 하위의 모든 컴포넌트가 상태 변화 시 리렌더링</li>
<li>전역 상태 관리 코드가 굉장히 간결하며, 사용이 간편함.</li>
<li>페이스북에서 공식적으로 만들었으며, 권장하는 전역 상태 관리 툴</li>
<li>서버 상태/클라이언트 상태를 분리할 때, 코드 복잡도가 매우 낮아짐.</li>
</ul>
<h2 id="1-redux보다-좋아">1. Redux보다 좋아?</h2>
<blockquote>
<h3 id="redux의-동작-원리">Redux의 동작 원리</h3>
</blockquote>
<ul>
<li>MVC패턴의 문제점<ul>
<li>페이스북에서 MVC패턴의 고질적인 문제를 해결하기 위해 만든 패턴<ul>
<li>규모가 커져 수많은 Models, Views가 생기면 복잡도가 엄청나게 증가함.</li>
</ul>
</li>
<li><img src="https://velog.velcdn.com/images/code_alpaca/post/d0dad85f-3fd6-48dc-8600-c235252fc6d0/image.png" alt=""></li>
<li>Model이 늘어날수록 전파해야할 대상도 증가해 신속하지 못하며, 모델에서 전파된 이벤트가 모든 Views에 예측이 불가하게 전파된다.</li>
</ul>
</li>
</ul>
<ul>
<li><p>Flux패턴</p>
<ul>
<li>View가 Model을 변경할 수 없는 단방향 데이터 흐름</li>
<li>Action: 상태 변화 담당</li>
<li>Dispatcher: 데이터 저장소(Store)로 Action의 메세지를 전달</li>
<li>Model: 데이터 저장소(Store) 역할. Action의 타입에 맞게 상태 변화</li>
<li>View: 컴포넌트 및 페이지. 상태 변화 시, 해당 상태를 가진 컴포넌트를 리렌더링
<img src="https://velog.velcdn.com/images/code_alpaca/post/e7256eda-2edf-47bf-a03a-22851f1d02a7/image.png" alt=""></li>
</ul>
</li>
<li><p>Redux는 Flux패턴과 유사하지만 다르다.</p>
<ul>
<li>Redux는 싱글톤패턴을 사용</li>
<li>Reducer로 상태 관리를 넘기고 그 조각들을 단 하나의 거대한 저장소에 묶어서 사용함. (Dispatch, Store)</li>
</ul>
</li>
</ul>
<blockquote>
<h3 id="recoil의-동작-원리">Recoil의 동작 원리</h3>
</blockquote>
<ul>
<li><p>Atoms</p>
<ul>
<li>Atom은 저장소의 역할을 하며, <strong>상태</strong>의 작은 단위임</li>
<li>Atom은 unique key로 구분되며, Atom의 상태가 바뀌면 구독하는 모든 컴포넌트가 리렌더링됨.(동일한 상태를 공유함)</li>
<li><img src="https://velog.velcdn.com/images/code_alpaca/post/26e3b982-d45c-4e4e-be0f-1e3d30145587/image.png" alt=""></li>
</ul>
</li>
<li><p>Selector</p>
<ul>
<li>Atom의 상태를 바탕으로 함수 연산을 통해 새로운 값을 반환하는 순수 함수. 기본적으로 연산된 값을 캐싱한다.</li>
<li>말이 어려워보이지만, 값을 가공해서 계산된 값을 내뱉는 함수임.</li>
<li>기존의 Atom의 상태가 변화하면 Atom을 구독하는 모든 Selector들도 다시 실행.(종속 관계)</li>
<li>Selector의 장점은 기존에는 상태를 보존하면서 값을 가공하기 불편했던 문제가 해결된다는 점이다.</li>
</ul>
</li>
<li></li>
</ul>
<h2 id="2-recoil-사용법">2. Recoil 사용법</h2>
<ul>
<li><p>Atom</p>
<ul>
<li><p>선언</p>
<pre><code class="language-jsx">export const smallState = atom({
      key: &#39;smallState&#39;, // 고유한 키 값
     default: &quot;작은 상태&quot;,
});</code></pre>
</li>
<li><p>참조 &amp; 상태 변화</p>
<pre><code class="language-jsx">function SmallStateComponent() {
  const [smallState, setSamllState] = useRecoilState(smallState);
  return (
  &lt;div&gt;{smallState}&lt;/div&gt;
    &lt;button onClick={() =&gt; setSmallState(&quot;다른 작은 상태&quot;)}&gt;
      상태를 바꿔보자
    &lt;/button&gt;
  );
}</code></pre>
</li>
<li><p>상당히 useState와 유사하다. Redux와 다르게 React스러운 상태관리임을 알 수 있다.</p>
</li>
</ul>
</li>
<li><p>Selector</p>
<ul>
<li>캐싱이 자동으로 이루어짐.</li>
<li>atom에 종속되어 항상 같은 값을 반환해야함</li>
<li>참조 시에, read-only<pre><code class="language-jsx">import { dataList } from &quot;./atom&quot;;
export const userSelector = selector({
  key: &quot;mySelector&quot;,
  get: (params) =&gt;
    ({ get }) =&gt; get(dataList).filter((myData)
}
);

</code></pre>
</li>
</ul>
</li>
</ul>
<ul>
<li>SelectorFamily<ul>
<li>파라미터를 통한 동적인 변화에 대응<pre><code class="language-jsx">import { dataList } from &quot;./atom&quot;;
export const userSelector = selectorFamily({
  key: &quot;mySelector&quot;,
  get: (params) =&gt;
    ({ get }) =&gt; get(dataList).filter((myData) =&gt; myData.id.includes(`${params}`))
}
);
</code></pre>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Query - 시작하기]]></title>
            <link>https://velog.io/@code_alpaca/React-Query1</link>
            <guid>https://velog.io/@code_alpaca/React-Query1</guid>
            <pubDate>Fri, 14 Oct 2022 18:50:24 GMT</pubDate>
            <description><![CDATA[<h2 id="제공하는-기능들">제공하는 기능들</h2>
<ul>
<li>React Query는 서버 상태를 관리하기 위해 아래와 같은 다양한 기능들을 지원한다.<blockquote>
<ul>
<li>로딩 및 에러 처리</li>
<li>페이지네이션 / 무한 스크롤</li>
<li>데이터 요청</li>
<li>데이터 사전 요청(Prefetching)</li>
<li>데이터 수정 및 업데이트(Mutations)</li>
<li>중복 요청 제거<ul>
<li>기존의 쿼리가 출력되는 동안 다른 컴포넌트에서 중복 요청이 일어나면 중복 요청을 제거한다.</li>
</ul>
</li>
<li>서버 요청 에러 재시도(Retry)</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="사용-방법">사용 방법</h2>
<h3 id="1-query-client-생성">1. Query client 생성</h3>
<blockquote>
<p>쿼리들과 캐시를 관리하는 클라이언트</p>
</blockquote>
<h3 id="2-queryprovider-적용">2. QueryProvider 적용</h3>
<blockquote>
<p>자식 컴포넌트들의 캐시와 클라이언트의 기본 설정값을 제공
query client에 값으로 적용</p>
</blockquote>
<pre><code class="language-jsx">import { QueryClient, QueryClientProvider } from &quot;@tanstack/react-query&quot;;

const queryClient = new QueryClient();

function App() {
  return (
    // provide React Query client to App
    &lt;QueryClientProvider client={queryClient}&gt;
      &lt;div className=&quot;App&quot;&gt;
        &lt;h1&gt;Blog Posts&lt;/h1&gt;
        &lt;Posts /&gt;
      &lt;/div&gt;
    &lt;/QueryClientProvider&gt;
  );
}</code></pre>
<h3 id="3-hook-사용">3. Hook 사용</h3>
<blockquote>
<p>useQuery를 기본적으로 데이터 패칭에 사용</p>
</blockquote>
<pre><code class="language-jsx">import { useState } from &quot;react&quot;;
import { useQuery } from &quot;@tanstack/react-query&quot;;

import { PostDetail } from &quot;./PostDetail&quot;;


//데이터를 요청해 캐싱할 값을 반환하는 함수
async function fetchPosts() {
  const response = await fetch(
    &quot;https://jsonplaceholder.typicode.com/posts?_limit=10&amp;_page=0&quot;
  );
  return response.json();
}

export function Posts() {
  //인자 1: 쿼리 키 배열, 2: 비동기 데이터 요청 함수
  const { data, isLoading } = useQuery([&quot;posts&quot;], fetchPosts);

  if (isLoading) {
    return (
      &lt;div&gt;로딩 중&lt;/div&gt;
    )
  }

  if (isError) {
    return &lt;div&gt;에러가 발생했습니다.&lt;/div&gt;;
  }

  return (
    &lt;&gt;
      &lt;ul&gt;
        {data.map((post) =&gt; (
          &lt;li
            key={post.id}
            className=&quot;post-title&quot;
          &gt;
            {post.title}
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/&gt;
  );
}
</code></pre>
<ul>
<li><p>여기서 중요한 점!</p>
<ul>
<li>비동기인 useQuery의 데이터 요청은 당연하지만 <code>data</code>를 undefined로 반환한다.</li>
<li>렌더링 시점이 요청을 받아오는 속도보다 빠르므로 기본 제공해주는 isLoading을 사용해 데이터를 받아오는 중에는 로딩중을 조기 반환해줬다.</li>
<li>에러 처리 또한 같은 방법으로 해줬다.</li>
</ul>
</li>
<li><p>참고 사항</p>
<ul>
<li><p><code>isFetching</code>과 <code>isLoading</code>과의 차이점</p>
<ul>
<li>isFetching: 아직 Axios, Fetch 등 요청이 끝나지 않았음. 더욱 포괄적인 개념.</li>
<li>isLoading: isFetching의 상태에서 캐싱된 데이터도 없는 상태를 의미함.
페이지네이션에서는 캐싱된 데이터가 존재하는지 여부가 중요하기도 함</li>
</ul>
</li>
<li><p><code>Retry 속성</code></p>
<ul>
<li>기본적으로 queryClient는 디폴트 값으로 retry를 3회 시도하도록 설정되어있다.
그러므로, isError에서 에러가 발생 시, 데이터를 가져오기 위해서 3회를 자동으로 재요청을 보낸다.</li>
</ul>
</li>
<li><p><code>error</code></p>
<ul>
<li>isError 외에도 구체적인 에러를 표시해주는 error, onError도 구조분해할당으로 사용이 가능하다.</li>
</ul>
</li>
<li><p>어? 다른 작업하다가 왔는데 왜 다시 데이터를 가져올까?</p>
<pre><code class="language-jsx">const queryClient = new QueryClient({
defaultOptions: {
queries: {
  refetchOnWindowFocus: true,
},
},
})</code></pre>
<p>그건 사용자가 윈도우 창을 집중해 사용할 때, 다시 데이터를 요청하는 옵션이 디폴트로 true로 설정된 상태이기 때문이다.</p>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React-query]]></title>
            <link>https://velog.io/@code_alpaca/React-query</link>
            <guid>https://velog.io/@code_alpaca/React-query</guid>
            <pubDate>Mon, 12 Sep 2022 09:06:44 GMT</pubDate>
            <description><![CDATA[<h1 id="react-query">React-query</h1>
<h3 id="사용-배경">사용 배경</h3>
<ul>
<li><p>전역에서 상태를 관리하는 Redux는 캐싱하는 개념이다.</p>
</li>
<li><p>그러나 정말 클라이언트(리액트)에서 수행하는 상태 관리로도 충분할까? No No</p>
<ul>
<li>예시<ul>
<li>모달의 오픈 여부</li>
<li>토큰값을 가지고 있는지(JWT)</li>
<li>인풋에 입력한 값의 상태 관리</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="1-서버-상태의-특징">1. 서버 상태의 특징</h3>
<ul>
<li>다른 사람들과 페이지에서 데이터를 공유하는 경우엔 서버에서 관리하는 데이터이므로 화면이 최신인지를 정확히 알 수 없음.</li>
<li>비동기 API인 Fetch, Update 등으로 관리함</li>
<li>클라이언트의 상태와는 별개임.</li>
<li>토큰, 캐시처럼 잠재적으로 만료되거나 사라질 수 있음. 리액트에서 관리하는 state들은 일종의 캐시라고 볼 수 있음.</li>
</ul>
<h3 id="2-클라이언트-상태의-특징">2. 클라이언트 상태의 특징</h3>
<ul>
<li>리액트, 뷰 등 클라이언트 자체가 온전히 제어가 가능함</li>
<li>초기값 설정 등 조작에 제약이 없음.</li>
<li>다른 사람들과 공유되지 않고 UI나 사용자의 인터렉션에 의해 변화함.</li>
<li>클라이언트 내에서는 최신 상태로 관리됨.</li>
</ul>
<h2 id="react-query란">React-Query란?</h2>
<ul>
<li>데이터 가져오기</li>
<li>캐시</li>
<li>동기화</li>
<li>데이터 업데이트</li>
</ul>
<p>위와 같은 작업을 수행해주는 라이브러리이다.</p>
<p><img src="https://user-images.githubusercontent.com/90893428/189592093-df065c63-29ba-41fa-b564-d09d514132f2.png" alt="image"></p>
<ul>
<li>여기서 잠깐! react-query를 사용하기 위해서는 <code>stale</code>과 <code>CacheTime</code>에 대하여 알 필요성이 있다.</li>
</ul>
<blockquote>
<p>데이터를 refetch(재요청)하는 주기를 판단해주는 개념인 stale과 fresh이다.</p>
<ol>
<li><p><code>fresh</code> - 데이터를 받아온 직후로 가장 데이터가 <strong>신선</strong>한 상태를 의미한다. fresh 상태일 경우엔 새롭게 mount 되어도 네트워크 요청이 일어나지 않는다. 그래서 <code>staletime</code>을 지정해야 한다.</p>
</li>
<li><p><code>stale</code> - 신선하지 않은, 즉, <strong>낡은 데이터</strong>를 의미하므로 refetch가 이루어짐을 알린다.</p>
</li>
<li><p><code>staleTime</code> - 기본 값은 0이며, 이는 받아옴과 동시에 낡은 데이터이므로 캐싱 데이터와 상관없이 계속해서 fetch를 한다. 즉, 서버의 부담이 늘지만 데이터 구조가 자주 바뀌는 경우엔 지정해주지 않으면 된다.</p>
<ol start="4">
<li><p><code>cacheTime</code> - 데이터가 <code>inactive</code>상태일 때, 캐싱된 상태로 남아있는 시간. 기본 값은 5분이다. 쿼리 인스턴스가 unmount되면 데이터는 <code>inactive</code>상태로 변경되고 <code>cacheTime</code>만큼 유지된다.</p>
<p><code>cacheTime</code>이 지나면 가비지 콜렉터로 수집된다.</p>
<p><code>cacheTime</code>이 지나기 전에 다시 쿼리 인스턴스가 마운트되면, 데이터를 fetch하는 사이에 캐시 데이터를 보여준다.</p>
<p><code>cacheTime</code>은 <code>staleTime</code>이 아무리 길어도(임시로 보관해도) <code>inactive</code>된 시점을 기준으로 데이터를 삭제하는 시점을 결정한다. 즉, <code>cacheTime</code>이 짧으면 데이터는 어차피 사라진다.</p>
<p><code>inactive</code>는 스크린에서 사용되지 않는 데이터임을 의미한다.</p>
<p><code>cacheTime</code>은 말 그대로 <code>신선한</code>데이터를 유지한다. 즉, 디폴트로 <code>staleTime</code>과 <code>cacheTime</code>을 사용하면, 캐싱이 되지 않는다.</p>
</li>
</ol>
</li>
</ol>
</blockquote>
<p><img src="https://user-images.githubusercontent.com/90893428/189597377-4717d84d-2f5a-4263-8d60-c0caf39b89d0.png" alt="image"></p>
<h4 id="주의점">주의점</h4>
<ul>
<li><p><code>enabled:false</code>로 설정하면 fetch 실패시 계속해서 <code>retry</code>하는 행위를 차단한다.</p>
<ul>
<li>이는 useQuery의 기능을 사용하지 않겠다는 것 이므로 수동으로 호출(refetch)을 해야한다.</li>
</ul>
</li>
<li><p><code>refetch</code>함수는 캐싱 결과와 무관하게 ajax요청을 날린다. 이미 해당 키 값이 QueryClient 객체에 저장되어 있어도 무시하고 재요청을 보낸다.</p>
<ul>
<li>즉, 캐싱을 구현하는 경우엔 <code>enabled:true</code>상태여야만 한다.</li>
</ul>
</li>
</ul>
<h2 id="usequery">useQuery</h2>
<ul>
<li>CRUD의 Read를 담당하고 데이터 요청을 담당함.</li>
</ul>
<pre><code class="language-js">import { useQuery } from &#39;react-query&#39;

function App() {
    //인자 1: 쿼리 키, 인자 2: 쿼리 함수(fetch, axios 요청)
    const info = useQuery(&#39;todos&#39;, fetchTodoList)
}</code></pre>
<ul>
<li><code>Query Key</code> - 이 데이터를 관리할 키 값 (위의 데이터는 <code>todos</code>키에 대한 데이터)<ul>
<li>파이썬 딕셔너리 생각하면 된다. (로컬 스토리지와도 같음)</li>
<li><code>Array</code>로 저장해 <code>[&#39;todos&#39;, 1]</code>처럼 저장해서 페이지네이션에도 활용이 가능함.</li>
</ul>
</li>
<li><code>useQuery</code>의 반환값<ul>
<li><code>data</code>: 요청에 성공한 데이터</li>
<li><code>error</code>: 에러 반환 객체</li>
<li><code>isFetching</code>: 요청 중일 때, <code>true</code></li>
<li><code>status, isLoading, isSuccess</code> 등의 현재 query 상태</li>
<li><code>refetch</code>: 해당 쿼리를 refetch하는 함수</li>
<li><code>remove</code>: 해당 쿼리를 캐시에서 지우는 함수</li>
<li>etc</li>
</ul>
</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/90893428/189600652-c6de8931-3554-4368-8853-c2ed0dcba112.png" alt="image"></p>
<ul>
<li><code>useQuery</code>의 옵션<ul>
<li><code>onSuccess onError, onSettled</code> 등 성공 실패 완료 시 실행할 Side Effect 정의</li>
<li><code>enabled</code>: 자동으로 query 실행할지 여부</li>
<li><code>retry</code>: query 실패 시, 자동으로 <code>retry</code>할건지 여부</li>
<li><code>select</code> 성공 시 가져온 data를 가공해서 전달</li>
<li><code>keepPreviousData</code>: 새롭게 fetching 시 이전 데이터 유지 여부</li>
<li><code>refetchInterval</code>: 주기적으로 refetch 할지 여부</li>
<li>etc</li>
</ul>
</li>
<li><img src="https://user-images.githubusercontent.com/90893428/189602088-b26fa30c-980d-4fc7-893d-e30ce46b30a4.png" alt="image"></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - JSX]]></title>
            <link>https://velog.io/@code_alpaca/React-JSX-yuf57hdv</link>
            <guid>https://velog.io/@code_alpaca/React-JSX-yuf57hdv</guid>
            <pubDate>Tue, 28 Jun 2022 06:30:28 GMT</pubDate>
            <description><![CDATA[<h2 id="1-jsx의-한계">1. JSX의 한계</h2>
<ul>
<li><p>JSX는 단 하나의 요소만 반환할 수 있다.</p>
</li>
<li><p>이 특성을 이용해 아래와 같은 방법들로 반환이 가능하다.</p>
<ul>
<li><p><code>div</code>태그로 묶어주기</p>
</li>
<li><p>여러 복합 요소들을 리스트 형태로 넘겨주기</p>
</li>
<li><p>wrapper 컴포넌트 만들기</p>
</li>
</ul>
</li>
</ul>
<h4 id="div-태그로-묶을-때는-아래와-같이-쓸모없는-div들을-많이-중첩하게-되기에-이상적이진-않다">div 태그로 묶을 때는 아래와 같이 쓸모없는 div들을 많이 중첩하게 되기에 이상적이진 않다.</h4>
<pre><code class="language-react">&lt;div&gt;
  &lt;div&gt;
      &lt;div&gt;
     &lt;h2&gt;깊이가 3인 컴포넌트 내부로 들어가봤습니다.&lt;/h2&gt;  
    &lt;/div&gt; 
  &lt;/div&gt;
&lt;/div&gt;</code></pre>
<h3 id="해결책">*해결책</h3>
<ul>
<li><code>wrapper</code>컴포넌트로 의미를 알 수 있는 구조 만들어주기.</li>
</ul>
<pre><code class="language-react">const Wrapper = props =&gt; {
    return props.children
}

export default Wrapper;</code></pre>
<h4 id="div-대신-wrapper로-감싸주면된다">div 대신 Wrapper로 감싸주면된다.</h4>
<ul>
<li><code>div</code>는 실제로 돔에 출력되지만 <code>Wrapper</code>는 아니다.</li>
<li>왜냐하면, <code>Wrapper</code>은 props.children을 통해 내용만 가져오며 직접적으로 <code>div</code>와 내부의 요소들을 가져온게 아닌, 간접적으로 내부의 요소들만 <code>Wrapper</code>내부에 불러왔기 때문이다.</li>
<li>그러므로, 실제 Wrapper 컴포넌트는 존재하지 않았던 것처럼 DOM에서 사라진다.</li>
</ul>
<pre><code class="language-react">&lt;Wrapper&gt; //실제로 DOM에 출력되지 않는 Wrapper 컴포넌트
  &lt;div&gt;
      &lt;div&gt;
     &lt;h2&gt;깊이가 3인 컴포넌트 내부로 들어가봤습니다.&lt;/h2&gt;  
    &lt;/div&gt; 
  &lt;/div&gt;
&lt;/Wrapper&gt;</code></pre>
<hr>
<h2 id="2-vite">2. Vite</h2>
<h3 id="기존-webpack">기존 webpack</h3>
<ul>
<li><code>CRA(Create React App)</code>는 Webpack 기반의 리액트 기본 보일러 플레이트(최소한의 변경으로 여러 곳에서 재사용되는 기능 및 코드)이다.</li>
<li>JS는 인터프리터 언어이기에 <code>low-level</code> 인 Go 언어보다 느릴 수 밖에 없다. </li>
<li>HMR(Hot Module Replacement) 사용 =&gt; 모듈 전체를 다시 로드하지 않고, 변경 부분만 교환, 추가, 제거하는 방식</li>
</ul>
<h3 id="vite">Vite</h3>
<ul>
<li>Webpack이 아닌 매우 빠른 Go 언어를 기반으로한 <code>EsBuild</code> 자바스크립트 빌드 툴을 사용</li>
<li>vite는 자바스크립트 파일을 두 개로 나눠 빌드한다.<ul>
<li>개발하는 동안 바뀌지 않는 의존성(<code>dependencies</code>)  ex) <code>node_modules</code>폴더<ul>
<li>라이브러리 설치 등 바뀌는 시점마다 매번 번들링을 해놔서 크기가 매우 큰 node_modules 폴더가 하나의 js파일로 합쳐지는 번들링에 시간을 잡아먹지 않음.</li>
<li>webpack은 브라우저 요청 이전에 모든 파일을 번들링해 하나로 모으지만, vite는 이 <code>node_modules</code>라는 의존성 폴더만 미리  <code>esbuild</code>를 이용해 빠르게 번들링함.</li>
</ul>
</li>
<li>소스코드<ul>
<li>자주 수정됨</li>
<li>소스코드 전체가 동시에 로드되지 않아도 된다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="방식의-차이">**방식의 차이</h4>
<ul>
<li><p><code>webpack</code></p>
<ul>
<li>기존에는 <code>dev server</code> 즉, 빌드 시작 시에 <code>webpack</code>이 모든 자바스크립트를 한 곳에 모아 번들링 한 후에 브라우저에 하나의 파일을 던져주는 방식이었음.</li>
</ul>
</li>
</ul>
<ul>
<li><p>vite는 <code>Native ESM</code> 즉, 자바스크립트 공식 모듈을 사용해 <strong>브라우저</strong>에서 필요한 소스코드만을 요청해 받아오는 방식을 사용한다.</p>
<ul>
<li><strong>Webpack</strong>은 소스코드를 업데이트하면 새로이 번들링을 진행한다. HMR을 사용하더라도 앱 사이즈가 커지면 무거워진 하나의 파일은 선형적으로 갱신 시간이 증가한다.</li>
<li><strong>Vite</strong>는 하나로 묶는 과정이 없이 브라우저가 교체된 모듈만을 요청해 가져오는 방식으로 HMR을 이용하므로 앱 사이즈가 커져도 갱신 시간에 영향이 없다.</li>
</ul>
</li>
</ul>
<p><img src="https://vitejs-kr.github.io/assets/bundler.37740380.png" alt="번들러 기반의 개발 서버"></p>
<p><img src="https://vitejs-kr.github.io/assets/esm.3070012d.png" alt="ESM 기반의 개발 서버"></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 동적 스타일링]]></title>
            <link>https://velog.io/@code_alpaca/React-%EB%8F%99%EC%A0%81-%EC%8A%A4%ED%83%80%EC%9D%BC%EB%A7%81</link>
            <guid>https://velog.io/@code_alpaca/React-%EB%8F%99%EC%A0%81-%EC%8A%A4%ED%83%80%EC%9D%BC%EB%A7%81</guid>
            <pubDate>Tue, 28 Jun 2022 06:28:38 GMT</pubDate>
            <description><![CDATA[<h2 id="dynamic-style">Dynamic style</h2>
<ul>
<li><p>리액트에서는 동적으로 스타일 클래스를 추가하고 제거할 수 있다.</p>
</li>
<li><p>아래의 코드를 보면, <code>input</code>태그에 값이 들어오지 않은 채로 제출을 누르면 <code>invalid</code>라는 css클래스가 동적으로 추가되며 빨간색으로 <code>input</code>과 <code>label</code> 태그를 바꿔준다.</p>
</li>
<li><p>그리고, 입력이 들어올 때마다, 공백인지 아닌지를 판단해 제대로된 값이 들어온다면 <code>invalid</code>클래스를 제거해주도록해 원상복구 시키도록 한다.</p>
</li>
<li><p>아래의 코드를 통해 동적으로 특정 상황에 맞게 스타일을 쿼리스트링을 이용해 삽입하거나 제거할 수 있다는 사실을 알 수 있다.</p>
</li>
</ul>
<pre><code class="language-react">const [isValid, setIsValid] = useState(true);

const goalInputChangeHandler = event =&gt; {
    if (event.target.value.trim().length &gt; 0) {
      setIsValid(true);
    }
    setEnteredValue(event.target.value);
  };


const formSubmitHandler = event =&gt; {
    event.preventDefault();
    if (enteredValue.trim().length === 0) {
      setIsValid(false);
      return;
    }
  };


&lt;div className={`form-control ${!isValid ? &#39;invalid&#39; : &#39;&#39;}`}&gt;</code></pre>
<pre><code class="language-css">.form-control.invalid input {
  border-color: red;
  background: #ffd7d7;
}

.form-control.invalid label {
  color: red;
}</code></pre>
<h2 id="styled-components">Styled Components</h2>
<ul>
<li>Styled Components 란? 스타일이 적용되는 컴포넌트에만 영향을 미치고 다른 곳에서는 영향을 미치지 않는 라이브러리이다.</li>
<li>설치는 다음과 같다. <code>npm install --save styled-components</code></li>
</ul>
<h4 id="tagged-template-literal">Tagged template Literal</h4>
<ul>
<li>메서드의 괄호 대신에 백틱으로 전달하는 구문이다.</li>
<li><code>styled.button</code> 은 신기하게도 새로운 <code>button</code>을 반환하는 메서드이다.<ul>
<li><code>h1 h2 p a button</code> 어떤 html 태그들을 포함하고 있다.</li>
</ul>
</li>
<li>이는 굳이 <code>.button</code>과 같은 선택자가 필요없고, 적용되는 추가적인 동작은 <code>&amp;</code>을 붙이면 된다.</li>
<li>이렇게 생성된 버튼은 동적으로 생성된 클래스를 가지게 된다. 그리고 그 스타일 클래스는 고유한 값이므로, 다른 컴포넌트에 영향을 주지 않는다.</li>
</ul>
<pre><code class="language-react">import styled from &#39;styled-components&#39;;

const Button = styled.button`
    font: inherit;
  padding: 0.5rem 1.5rem;
  border: 1px solid #8b005d;
  color: white;
  background: #8b005d;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
  cursor: pointer;
  &amp;:focus {
    outline: none;
  }
  &amp;:hover,
  &amp;:active {
    background: #ac0e77;
    border-color: #ac0e77;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
  }
`</code></pre>
<ul>
<li>그리고 동적으로 백틱 내부로 <code>props</code>를 넘길 수 있다. 생성된 <code>Button</code>을 사용할 때, <code>props</code>를 넘기고</li>
<li><code>border: 1px solid ${props =&gt; (props.전달받은 인자 ? &#39;red&#39; : &#39;blue&#39;)}</code>의 형태를 통해 동적으로 세부적인 css 요소에 접근할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 상향식 데이터 전달]]></title>
            <link>https://velog.io/@code_alpaca/React-%EC%83%81%ED%96%A5%EC%8B%9D-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EB%8B%AC</link>
            <guid>https://velog.io/@code_alpaca/React-%EC%83%81%ED%96%A5%EC%8B%9D-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EB%8B%AC</guid>
            <pubDate>Tue, 28 Jun 2022 06:27:32 GMT</pubDate>
            <description><![CDATA[<h2 id="5-상향식-데이터-전달">5. 상향식 데이터 전달</h2>
<ul>
<li>부모 컴포넌트는 <code>props</code>를 통해 데이터를 전달한다. 그렇다면 자식은 어떻게 데이터를 부모에게 전달할까?</li>
<li>아래와 같이 하면 된다.<ul>
<li>부모 컴포넌트에서 자식 컴포넌트의 데이터를 받아올 함수를 만들어 <code>props</code>로 넘긴다</li>
<li>자식 컴포넌트가 받은 함수에 데이터를 인자로 받는다.</li>
<li>인자로 받은 데이터를 처리한다.</li>
</ul>
</li>
</ul>
<pre><code class="language-react">//자식 컴포넌트에서 submit을 통해 데이터를 전달
const submitHandler = (e) =&gt; {
    e.preventDefault();
    //이곳에 post 요청을 보낼 수도 있음!
    //axios.post(&#39;URL&#39;)
    props.getDataOfChildren(userInput) // 제출한 값을 인자로 받음.
    setUserInput(&#39;&#39;)
}

/////////////////////////////////////////

// 부모 컴포넌트


//자식에게서 data를 받아올 함수
const getDataOfChildren =  (childrenData) =&gt; {
    const newDataForm = {
        ...childrenData, //인자를 객체로 받아와 id를 부여해 새로운 객체 생성
        id: Date.now()
    }
    //여기서 setState를 통해 새로 저장하거나 사용!
}

//props로 자식의 데이터를 가져올 함수를 전달
return (
    &lt;div&gt;
        &lt;ChildrenComponent getDataOfChildren={getDataOfChildren}/&gt;
    &lt;/div&gt;
)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - 양방향 바인딩]]></title>
            <link>https://velog.io/@code_alpaca/React-%EC%96%91%EB%B0%A9%ED%96%A5-%EB%B0%94%EC%9D%B8%EB%94%A9</link>
            <guid>https://velog.io/@code_alpaca/React-%EC%96%91%EB%B0%A9%ED%96%A5-%EB%B0%94%EC%9D%B8%EB%94%A9</guid>
            <pubDate>Tue, 21 Jun 2022 14:30:53 GMT</pubDate>
            <description><![CDATA[<h2 id="4-양방향-바인딩">4. 양방향 바인딩</h2>
<ul>
<li><p>리액트에서 양방향 바인딩은 어떻게 구현할까?</p>
</li>
<li><p>아래와 같이 값이 입력되어 <code>onChange</code>속성으로 상태 값을 변경시킴과 동시에 <code>value</code>를 <code>userInput</code>의 상태로 설정해준다.</p>
</li>
<li><p>그러면, input이 바뀔 때는 <code>userInput</code>  값이 바뀌고, 반대의 경우에도 <code>value</code>로 인하여 서로 값을 바꾸는 관계를 형성한다.</p>
</li>
</ul>
<pre><code class="language-react">const [userInput, setUserInput] = useState({
    name: &#39;chulsoo&#39;,
    age: 8,
    created_at: &#39;2021&#39;
})

const changeAge = (e) =&gt; {
    setUserInput((prevState) =&gt; {
        return {...userInput, age: 5}
    })
}

const submitHandler = (e) =&gt; {
    e.preventDefault();
    //이곳에 post 요청을 보낼 수도 있음!
    setUserInput(&#39;&#39;)
}


//value를 이용한 양방향 바인딩
&lt;form onSubmit=&quot;submitHandler&quot;&gt;
    &lt;input type=&quot;text&quot; value={userInput.name} onChange={changeAge}/&gt;
&lt;/form&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - State의 안전한 사용]]></title>
            <link>https://velog.io/@code_alpaca/React-State%EC%9D%98-%EC%95%88%EC%A0%84%ED%95%9C-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@code_alpaca/React-State%EC%9D%98-%EC%95%88%EC%A0%84%ED%95%9C-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Tue, 21 Jun 2022 14:30:27 GMT</pubDate>
            <description><![CDATA[<h2 id="3-state">3. State</h2>
<ul>
<li><p><code>useState</code>를 객체로 다루는 옳은 방법을 알아볼 것이다.</p>
</li>
<li><p>useState의 두 번째 인자는 무조건 그 안의 값으로 <strong>대체</strong>한다.</p>
</li>
<li><p>그 원리를 이용해 현재 첫 인자인 <code>userInput</code>을 가져와서 사용하게 된다.</p>
</li>
<li><p>그런데 비동기 작업 등 여러가지 상태 업데이트가 계획되어있다면, 잘못된 시점의 userInput을 받아 올 수 있다.</p>
<ul>
<li>1번 예시와 같이 사용하면 가장 최신의 <code>userInput</code>을 가져왔다고 확신할 수 없다.</li>
<li>2번 예시는 업데이트된 <code>userInput</code>을 인자로 받아와 새로 업데이트해 반환하므로 가장 최신의 값을 받아온다고 확신할 수 있다.</li>
</ul>
</li>
</ul>
<pre><code class="language-react">const [userInput, setUserInput] = useState({
    name: &#39;chulsoo&#39;,
    age: 8,
    created_at: &#39;2021&#39;
})
// spread 연산자 1
const exFunction = (e) =&gt; {
    setUserInput({
        ...userInput, //잘못된 시점의 userInput을 받아올 수 있음.
        age: 5,
    })
}

//spread 연산자 2
const exFunction = (e) =&gt; {
    setUserInput((prevState) =&gt; { //prevState는 따끈따근한 최신의 userInput 상태를 가져오므로 세이프한 방법임.
        return {...userInput, age: 5}
    })
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - JSX]]></title>
            <link>https://velog.io/@code_alpaca/React-JSX</link>
            <guid>https://velog.io/@code_alpaca/React-JSX</guid>
            <pubDate>Tue, 21 Jun 2022 14:29:32 GMT</pubDate>
            <description><![CDATA[<h2 id="2-jsx">2. JSX</h2>
<ul>
<li>JSX는 리액트에서 사용하는 UI를 정의할 때 사용하는 도구다.</li>
<li>JSX는 HTML 문법과도 같은 형태를 가졌지만 실제로는 JavaScript로써 export되는 동작 방식을 가지고 있다.</li>
<li>이는 브라우저에서 번들링되는 과정에서 Babel을 사용해 일반 JS 문법으로 변환해준다. <ul>
<li><strong>번들링이란?</strong> 기능별로 모듈화했던 JavaScript 파일을 묶어주는 작업</li>
<li><strong>번들러에 대하여</strong> =&gt; 웹팩(Webpack)과 같은 번들러의 주 역할은 서로 연관(의존성) 있는 여러 JS파일(모듈)들을 하나의 번들(Bundle) 파일로 묶어주는 역할을 한다.<ul>
<li>Webpack을 이용한 Bundling 작업 덕분에 한 파일(CSR의 가장 큰 특징)에서 모두 묶어 요청/응답을 받으므로 <strong>네트워크 코스트가 줄어든다</strong></li>
<li><strong>Webpack</strong>의 주요 구성 요소 중 하나인 로더(Loder)가 일부 브라우저에서 지원이 되지 않는 ES6 형식의 자바스크립트 파일을 ES5로 변환하여 사용가능하게 한다. 즉, 고전의 브라우저까지 모두 호환할 수 있도록 돕는 아주 효자스러운 기능을 가졌다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="예제">예제</h3>
<p>1.</p>
<pre><code class="language-react">import React from &#39;react&#39;;

return React.createElement(&#39;div&#39;, {}, 
            React.createElement(&#39;h2&#39;, {}, &quot;Let&#39;s get JSX!&quot;),
            React.createElement(Expenses, {item: expenses}, &quot;Let&#39;s get JSX2!&quot;) //Expenses는 컴포넌트
            )</code></pre>
<p>2.</p>
<pre><code class="language-react">return (
    &lt;div&gt;
      &lt;h2&gt;Let&#39;s get JSX!&lt;/h2&gt;
      &lt;Expenses items={expenses}/&gt;
    &lt;/div&gt;
)</code></pre>
<ul>
<li><p>위의 1과 2는 완전한 동치이다.</p>
</li>
<li><p>두 코드의 차이점은 2번은 React를 직접 가져오지 않아도 되는데 내부적으로는 1번과 같이 동작하고 있다.</p>
</li>
<li><p>위의 <code>return React.createElement</code> 구문을 보면 반환은 오직 하나의 div 태그이고 내부적으로 계속해서 하위 태그들을 만들어내는 것을 볼 수 있다. 이러한 이유로 <code>return</code>은 오직 한 개만 반환하기에 div로 감싸주는 것 이다.</p>
</li>
<li><p>그리고 1번과 같이 사용하기 위해서는 React를 명시적으로 import해서 사용해야만한다.</p>
</li>
</ul>
<h4 id="즉-보이지-않았겠지만-내부에서는-react가-jsx를-사용할-때-항상-동작하고-있었다는-것을-의미한다-왜-div와-같은-wrapper-태그가-필요했는지-이제야-이해할-수-있을-것이다">즉, 보이지 않았겠지만, 내부에서는 React가 JSX를 사용할 때 항상 동작하고 있었다는 것을 의미한다. 왜 div와 같은 wrapper 태그가 필요했는지 이제야 이해할 수 있을 것이다.</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[React - children prop]]></title>
            <link>https://velog.io/@code_alpaca/React-children-prop</link>
            <guid>https://velog.io/@code_alpaca/React-children-prop</guid>
            <pubDate>Tue, 21 Jun 2022 14:29:00 GMT</pubDate>
            <description><![CDATA[<h2 id="1-children-prop">1. Children Prop</h2>
<ul>
<li><p>div 태그로 감싸 리액트 컴포넌트를 전달해주는게 기본적이다.</p>
</li>
<li><p>하지만 <strong>박스</strong>의 역할을 하는 <code>Sidebar</code>, <code>Card</code>, <code>Box</code>, <code>Dialog</code> 등은 모두 각각의 컴포넌트 틀 및 스타일, 기능을 가지고 있다.</p>
</li>
<li><p>그렇게 div의 역할을 대신해 감싸주는 <code>wrapper</code>의 역할을 하는 컴포넌트가 <code>children prop</code>이다.</p>
</li>
<li><p>그렇게 다양하게 재사용할 수 있는 여지를 줍니다. <code>ul</code>태그가 꼭 필요한 <code>li</code>태그들은 <code>Category</code>라는 아래의 <code>wrapper</code>컴포넌트를 생성하면 재사용성과 코드의 가독성이 증가한다.</p>
</li>
</ul>
<pre><code class="language-react">const Category = (props) =&gt; {
  return &lt;ul&gt;{props.children}&lt;/ul&gt;;
};


const App = () =&gt; (
  &lt;Category&gt;
      &lt;li&gt;리스트 입니다!&lt;/li&gt;
      &lt;li&gt;리스트 입니다!&lt;/li&gt;
      &lt;li&gt;리스트 입니다!&lt;/li&gt;
      &lt;li&gt;리스트 입니다!&lt;/li&gt;
      &lt;li&gt;리스트 입니다!&lt;/li&gt;
  &lt;/Category&gt;
);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript - Enum]]></title>
            <link>https://velog.io/@code_alpaca/TypeScript-Enum</link>
            <guid>https://velog.io/@code_alpaca/TypeScript-Enum</guid>
            <pubDate>Wed, 15 Jun 2022 16:42:18 GMT</pubDate>
            <description><![CDATA[<h2 id="1-enum">1. Enum</h2>
<ul>
<li>Enum은 특정 값들의 집합을 의미하고 타입을 지정해줄 수 있다.</li>
<li>함수에서 인자를 받을 때, 타입을 enum으로 지정할 시, enum 내부의 속성만을 호출할 때, 인자로 받을 수 있다. 아래와 같이 <code>Answer</code>객체를 타입으로 지정하면, <code>Answer</code>내부의 <code>Answer.Yes</code> 와 <code>Answer.No</code>만 인자로 사용해 함수를 호출이 가능하다.<pre><code class="language-ts">//숫자형 enum
//별도의 값을 초기화하지 않으면 숫자형 enum임
enum Shoes {
Nike,
Adidas //목록이 추가되면 인덱스 처럼 수가 증가함
}
</code></pre>
</li>
</ul>
<p>let myShoes = Shoes.Nike;
console.log(myShoes) // 0</p>
<p>//문자형 enum
enum Shoes2 {
  Nike = &#39;나이키&#39;,
  Adidas = &#39;아디다스&#39; //목록이 추가되면 인덱스 처럼 수가 증가함
}
console.log(Shoes2.Nike) // 나이키</p>
<p>// ex
enum Answer {
  Yes = &#39;yes&#39;,
  No = &#39;no&#39;
}</p>
<p>function askQuestion(answer: Answer) {
  if (answer === Answer.Yes) {
    console.log(&#39;정답&#39;)
  }
  if (answer === Answer.No) {
    console.log(&#39;오답&#39;)
  }
}</p>
<p>askQuestion(Answer.Yes) //파라미터의 타입이 Answer인 값만 넘길 수 있다.
askQuestion(Answer.No)
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript - 인터페이스 & 타입 별칭]]></title>
            <link>https://velog.io/@code_alpaca/TypeScript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%ED%83%80%EC%9E%85-%EB%B3%84%EC%B9%AD</link>
            <guid>https://velog.io/@code_alpaca/TypeScript-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%ED%83%80%EC%9E%85-%EB%B3%84%EC%B9%AD</guid>
            <pubDate>Wed, 15 Jun 2022 15:53:34 GMT</pubDate>
            <description><![CDATA[<h2 id="1-interface">1. Interface</h2>
<ul>
<li>인터페이스는 커스텀 타입을 정의 및 상속을 통해 확장할 수 있고 재사용성이 높다.</li>
<li>인덱싱이나 딕셔너리 패턴과 같이 key 혹은 value에 타입을 지정해주고 그 값에도 타입을 지정할 수 있다.<pre><code class="language-ts">interface User {
age: number;
name: string;
}
</code></pre>
</li>
</ul>
<p>// 변수에 활용한 인터페이스
var seho: User = {
  age: 33,
  name: &#39;세호&#39;
}</p>
<p>// 함수에 인터페이스 활용
function getUser(user: User) {
  console.log(user)
}</p>
<p>const capt = {
  name: &#39;캡틴&#39;,
  age: 100
}</p>
<p>getUser(capt)</p>
<p>//함수의 스펙(구조)에 인터페이스 사용
interface SumFunction {
  (a: number, b: number)
}</p>
<p>var sum: SumFunction;
sum = function(a: number, b: number): number {
  return a + b
}</p>
<p>//인덱싱
interface StringArray {
  [index: number]: string;
}</p>
<p>var arr1: StringArray = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;];
arr1[0] = &#39;a&#39;;</p>
<p>//딕셔너리 패턴
interface StringRegexDictionary {
  [key: string]: RegExp; //정규표현식 생성자 RegexExpression
}</p>
<p>let obje: StringRegexDictionary = {
  // sth: /abc/,
  cssFile: /.css$/,
  jsFile: /.js$/,
}</p>
<p>// obje[&#39;cssFile&#39;] = &#39;a&#39; Regex가 들어와야하는데 문자열이라 에러가 뜸 </p>
<p>Object.keys(obj).forEach(function(val) {})</p>
<p>//인터페이스 확장</p>
<p>interface Person {
  name: string;
  age: number;
}</p>
<p>interface Developer extends Person {
  language: string;
}</p>
<p>let captain: Developer = {
  name: &#39;캡틴&#39;,
  age: 100,
  language: &#39;영어&#39;
}</p>
<pre><code>
## 2. Union &amp; Interface
- Union
  - 기본 타입 - 여러 종류의 타입을 선택할 수 있음.
  - 객체 형태의 함수 인자 - 표기한 객체들에 모두 해당되는 속성만 사용 가능함.
    - 그 이유는, 두 객체 중에 한 객체를 선택했을 때, 다른 객체의 인자에 참조하게되면 안전하지 않기 때문이다.

  - 호출하는 관점에서는, 한 객체에 해당하는 모든 속성을 인자로 넘겨줘야만 한다. `겹치지 않는 속성은 사용하지 않는데 왜 인자로 넘겨야하지?` 라고 이상하게 느껴질 수 있지만, `내가 이 객체를 사용할 거야!`라는 것을 함수에 알려주기 위해서이다.
- Intersection
  - 객체 형태의 함수 인자 - 표기한 객체들의 모든 속성을 사용할 수 있다.
  - 중요한 점은, 함수를 호출할 때, 무조건 함수 내에서 사용되는 모든 객체에 포함되는 속성을 인자로 넘겨줘야만 한다는 것이다.
```ts
let sihyun: string | number | boolean;
function logMessage(value: string | number) { //Union Type은 하나의 타입 이상을 쓸 수 있음
  if (typeof value === &#39;number&#39;) {
    value.toLocaleString();
  }
  if (typeof value === &#39;string&#39;) {
    value.toString();
  }
  throw new TypeError(&#39;value must be string or number&#39;)

}
logMessage(&#39;hello&#39;);

interface Developers {
  name: string;
  skill: string;
}

interface Person2 {
  name: string;
  age: number;
}

function askSomeone(someone: Developers | Person2) {
  someone.name //공통 속성만 접근가능
  // someone.age
  // someone.skill
}


//인터섹션

let unionA: string | number | boolean;
let interB: string &amp; number &amp; boolean;

function askSomeone2(someone: Developers &amp; Person2) {
  someone.name //공통 속성만 접근가능
  someone.age
  someone.skill
}

askSomeone({name: &#39;developer&#39;, skill: &#39;web development&#39;})
askSomeone({name: &#39;sehan&#39;, age: 100})

askSomeone2({name: &#39;developer&#39;, skill: &#39;web development&#39;, age: 100}) //세 인자가 다 들어와야만 intersectio 함수가 동작함
let sihyun: string | number | boolean;
function logMessage(value: string | number) { //Union Type은 하나의 타입 이상을 쓸 수 있음
  if (typeof value === &#39;number&#39;) {
    value.toLocaleString();
  }
  if (typeof value === &#39;string&#39;) {
    value.toString();
  }
  throw new TypeError(&#39;value must be string or number&#39;)

}
logMessage(&#39;hello&#39;);

interface Developers {
  name: string;
  skill: string;
}

interface Person2 {
  name: string;
  age: number;
}

function askSomeone(someone: Developers | Person2) {
  someone.name //공통 속성만 접근가능
  // someone.age
  // someone.skill
}


//인터섹션

let unionA: string | number | boolean;
let interB: string &amp; number &amp; boolean;

function askSomeone2(someone: Developers &amp; Person2) {
  someone.name //공통 속성만 접근가능
  someone.age
  someone.skill
}

askSomeone({name: &#39;developer&#39;, skill: &#39;web development&#39;})
askSomeone({name: &#39;sehan&#39;, age: 100})

askSomeone2({name: &#39;developer&#39;, skill: &#39;web development&#39;, age: 100}) //세 인자가 다 들어와야만 intersectio 함수가 동작함</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript - 기본 타입]]></title>
            <link>https://velog.io/@code_alpaca/TypeScript-%EA%B8%B0%EB%B3%B8-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@code_alpaca/TypeScript-%EA%B8%B0%EB%B3%B8-%ED%83%80%EC%9E%85</guid>
            <pubDate>Tue, 14 Jun 2022 17:21:38 GMT</pubDate>
            <description><![CDATA[<h2 id="1-문자열-숫자-배열">1. 문자열, 숫자, 배열</h2>
<ul>
<li>다른 타입에 해당할 경우는 빨간 줄을 표시한다.<pre><code class="language-ts">let str: string = &#39;hello&#39;;
let num: number = 10;
</code></pre>
</li>
</ul>
<p>let arr: Array<number> = [1, 2, 3];
let arr2: Array<string> = [&#39;A&#39;, &#39;B&#39;, &#39;C&#39;];
let items: number[] = [1, 2, 3];</p>
<pre><code>
## 2. 튜플, 객체, 진위값
- 튜플은 모든 값에 타입을 각각 지정해준 배열임.
- 객체는 내부에 속성 타입을 지정하지 않아도 상관이 없음.
```ts
//튜플
let address: [string, number] = [&#39;gang&#39;, 1]; //순서에 맞는 타입까지 지정하는 것이 튜플

//객체
let obj: object = {};
let person: object = {
  name: &#39;capt&#39;,
  age: 30
};

//객체 내부에 있는 속성 또한 타입 지정이 가능
let person2: { name: string, age: number } = {
  name: &#39;capt&#39;,
  age: 30
}

//진위값
let show:boolean = true
</code></pre><h2 id="3-함수-타입">3. 함수 타입</h2>
<pre><code class="language-ts">// 함수의 파라미터에 타입 정의
function add(a: number, b: number) {
  return a + b;
}

add(10, 20);

//반환 값에 타입을 정의
function add2(): number {
  return 10 + 20;
}

//두 방식을 조합

function add3(a: number, b: number): number {
  return a + b;
}

//파라미터의 유연함과 제약
function add4(a: number, b: number): number {
  return a + b;
}

add4(10, 20, 30, 40) 
//에러 발생. 30, 40은 더 들어갈 수 없음. JS는 그냥 유연하게 무시함

add4(10)
//에러 발생. 인자가 부족함


//함수의 옵셔널 파라미터
function log(a: string, b?: string, c?: string) {

}

log(&#39;hello&#39;)
log(&#39;hello&#39;, &#39;world&#39;) //하나의 인자는 필수이지만, 두 개, 세 개는 필수가 아니게 되는 방식</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript - 병렬 평가]]></title>
            <link>https://velog.io/@code_alpaca/JavaScript-%EB%B3%91%EB%A0%AC-%ED%8F%89%EA%B0%80</link>
            <guid>https://velog.io/@code_alpaca/JavaScript-%EB%B3%91%EB%A0%AC-%ED%8F%89%EA%B0%80</guid>
            <pubDate>Sat, 11 Jun 2022 08:02:57 GMT</pubDate>
            <description><![CDATA[<h2 id="비동기-프로그래밍4">*비동기 프로그래밍(4)</h2>
<h3 id="1-지연된-함수열을-병렬적으로-평가하기---creduce-ctake">1) 지연된 함수열을 병렬적으로 평가하기 - C.reduce, C.take</h3>
<ul>
<li>현재는 싱글스레드의 특성상 한 작업이 끝나면 다음 작업으로 넘어가는 식으로 작업한다. 하지만 한꺼번에 병렬적으로 연산하면 부하는 커지지만 훨씬 빠른 속도로 처리할 수 있다.</li>
</ul>
<pre><code class="language-js">  const C = {};

  function noop() {
  }

  const catchNoop = ([...arr]) =&gt;
    (arr.forEach(a =&gt; a instanceof Promise ? a.catch(noop) : a), arr);

  C.reduce = curry((f, acc, iter) =&gt; iter ?
    reduce(f, acc, catchNoop(iter)) :
    reduce(f, catchNoop(acc)));

  C.take = curry((l, iter) =&gt; take(l, catchNoop(iter)));

  C.takeAll = C.take(Infinity);

  C.map = curry(pipe(L.map, C.takeAll));

  C.filter = curry(pipe(L.filter, C.takeAll));

  const delay1000 = a =&gt; new Promise(resolve =&gt; {
    console.log(&#39;hi~&#39;);
    setTimeout(() =&gt; resolve(a), 1000);
  });

    go([1, 2, 3, 4, 5, 6, 7, 8, 9],
      L.map(a =&gt; delay1000(a * a)),
      L.filter(a =&gt; delay1000(a % 2)),
      L.map(a =&gt; delay1000(a * a)),
      // C.take(2),
      C.reduce(add),
      log,
      _ =&gt; console.timeEnd(&#39;&#39;));</code></pre>
<ul>
<li>기존의 reduce는 배열의 하나씩 꺼내서 acc에 더해주는 식으로 연산했다면, C.reduce는 배열의 모든 값을 한꺼번에 출발시켜 병렬적으로 동시에 연산한다. </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript - 비동기(3)]]></title>
            <link>https://velog.io/@code_alpaca/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B03</link>
            <guid>https://velog.io/@code_alpaca/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B03</guid>
            <pubDate>Sat, 11 Jun 2022 08:02:22 GMT</pubDate>
            <description><![CDATA[<h2 id="비동기-프로그래밍3">*비동기 프로그래밍(3)</h2>
<h3 id="1-promise--지연평가">1) Promise + 지연평가</h3>
<ul>
<li>take와 map은 기본적으로 Promise를 이용해 비동기로 처리해주는 로직이 내부에 필요하다.</li>
<li>그렇기에 map에서는 받은 함수를 Promise인지 판별해 then을 통해 값을 가져올 수 있게 해줘야하고, take 또한 마찬가지로 비동기 상황에서 연산의 순서를 보장하는 then을 재귀를 통해 해결할 수 있다.</li>
</ul>
<pre><code class="language-js">     go(
      [1, 2, 3],
      L.map(a =&gt; Promise.resolve(a + 10)),
      take(2),
      log);
    go(
      [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)],
      L.map(a =&gt; a + 10),
      take(2),
      log);
    go(
      [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)],
      L.map(a =&gt; Promise.resolve(a + 10)),
      take(2),
      log);
    go(
      [1, 2, 3],
      map(a =&gt; Promise.resolve(a + 10)),
      log);
    go(
      [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)],
      map(a =&gt; a + 10),
      log);
    go(
      [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)],
      map(a =&gt; Promise.resolve(a + 10)),
      log);</code></pre>
<ul>
<li>then으로만 재귀 없이 처리해준다면, go를 통한 연산 중간에 비동기 연산을 하면, 그 아래의 모든 연산이 then으로 비동기적으로 묶여버린다. 그렇기에 재귀를 통해 Promise 구문의 연산이 끝나면, <strong>재귀를 통해 다음 구문이 Promise인지 즉시 판단</strong>해줄 수 있다.</li>
</ul>
<h3 id="2-kleisli-composition---lfilter-filter-nop-take">2) Kleisli Composition - L.filter, filter, nop, take</h3>
<ul>
<li><p>세이프 코딩을 하기위해선 Promise를 통해 비동기적으로 반환하는 값이 조건에 해당하지 않으면 reject를 넘겨 다음 <code>then</code>이 아닌 <code>catch</code>로 흘러간다는 보장이 있어야한다. </p>
</li>
<li><p>그렇기에 아래의 코드를 보면, 1은 문제가 없지만 2는 filter에서 <code>a % 2</code>에서 걸리므로 reject를 반환하고 다음 L.map 등을 모두 지나쳐 <code>take</code>안에서 catch를 통해 미리 reject에 담아놓은 <code>nop</code> 이라는 표시를 받았다면 다음으로 넘어가 3에 대한 연산을 시작한다.</p>
</li>
<li><p>즉, 평가에 가까운 <code>take</code>  <code>log</code> 등의 연산에서 reject를 통해 빠져나온 연산을 받아 재귀를 통해 다음 연산으로 넘기도록 처리해줘야 정상적으로 작동한다.</p>
</li>
</ul>
<pre><code class="language-js">&lt;script&gt;
  go([1, 2, 3, 4, 5, 6],
    L.map(a =&gt; Promise.resolve(a * a)),
    // L.map(a =&gt; a * a),
    filter(a =&gt; Promise.resolve(a % 2)),
    // L.map(a =&gt; a * a),
    /*L.map(a =&gt; {
      log(a);
      return a * a;
    }),
    L.map(a =&gt; {
      log(a);
      return a * a;
    }),*/
    // take(4),
    /*log*/);
&lt;/script&gt;

## reduce에서 nop 지원

&lt;script&gt;
  go([1, 2, 3, 4, 5],
    L.map(a =&gt; Promise.resolve(a * a)),
    L.filter(a =&gt; Promise.resolve(a % 2)),
    reduce(add)/*,
    log*/);
&lt;/script&gt;

&lt;script&gt;
  go([1, 2, 3, 4, 5, 6, 7, 8],
    L.map(a =&gt; {
      log(a);
      return new Promise(resolve =&gt; setTimeout(() =&gt; resolve(a * a), 1000))
    }),
    L.filter(a =&gt; {
      log(a);
      return new Promise(resolve =&gt; setTimeout(() =&gt; resolve(a % 2), 1000))
    }),
    take(2),
    reduce(add),
    log);
&lt;/script&gt;</code></pre>
]]></description>
        </item>
    </channel>
</rss>