<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>beom_pie.log</title>
        <link>https://velog.io/</link>
        <description> </description>
        <lastBuildDate>Thu, 15 Jun 2023 07:16:23 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. beom_pie.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/beom_pie" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[useMemo ]]></title>
            <link>https://velog.io/@beom_pie/useMemo-7xb9ej0c</link>
            <guid>https://velog.io/@beom_pie/useMemo-7xb9ej0c</guid>
            <pubDate>Thu, 15 Jun 2023 07:16:23 GMT</pubDate>
            <description><![CDATA[<h3 id="usememo">useMemo()</h3>
<pre><code class="language-javascript">  const getDiaryAnaylysis = () =&gt; {
    const goodCount = data.filter((it) =&gt; it.emotion &gt;= 3).length;
    const badCount = data.length - goodCount;
    const goodRatio = (goodCount / data.length) * 100;
    return { goodCount, badCount, goodRatio };
  });

  const { goodCount, badCount, goodRatio } = getDiaryAnaylysis();

</code></pre>
<p>일기에 좋은감정 + 나쁜감정 + 좋은 감정의 일기 비율에 대해서 보여주려고 한다</p>
<p>다만, 콘솔을 찍어서 확인해보니</p>
<p>일기를 수정할 때에도 호출이 되는 등 함수가 호출될 필요가 없는 상황에서도 불필요하게 호출이 되고 있었다</p>
<p>이럴 때 값을 기억하고 있는 useMemo 훅을 사용해보자 (연산결과 저장)</p>
<pre><code class="language-javascript">
  const getDiaryAnaylysis = useMemo(() =&gt; {
    const goodCount = data.filter((it) =&gt; it.emotion &gt;= 3).length;
    const badCount = data.length - goodCount;
    const goodRatio = (goodCount / data.length) * 100;
    return { goodCount, badCount, goodRatio };
  }, [data.length]);

  const { goodCount, badCount, goodRatio } = getDiaryAnaylysis;

</code></pre>
<p>useMemo로 감싼 후에는 더이상 함수가 아니기에 실행시키면 안됨</p>
<p>useMemo로 감싼 뒤에는 의존성 배열에 무엇이 바뀔때 호출이 될지를 적어두어야 함</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL]]></title>
            <link>https://velog.io/@beom_pie/TIL-b4i13r3c</link>
            <guid>https://velog.io/@beom_pie/TIL-b4i13r3c</guid>
            <pubDate>Wed, 31 May 2023 10:13:33 GMT</pubDate>
            <description><![CDATA[<p>결제하기 버튼을 눌렀을 때 주문 페이지로 이동
useLocation 을 활용한 데이터 스테이트 값 가져오기</p>
<p>우선 라우트 지정을 해준다</p>
<pre><code class="language-javascript">&lt;Route path=&quot;order-summary&quot; 
    element={ 
      &lt;ProtectedRoute&gt; 
          &lt;Order/&gt; 
      &lt;/ProtectedRout&gt; }
                            /&gt;
</code></pre>
<hr>
<p>[Checkout.js]
결제 모달창에서 결제하기 버튼을 클릭했을 때 state 값으로 useEffect를 통해 가져온 데이터와 상태값을 넘겨준다 (true / false)</p>
<pre><code class="language-javascript"> navigate(&quot;/order-summary&quot;, {
        state: {
          data: data,
          status: true,
        },
      });
</code></pre>
<hr>
<p>[Order.js]</p>
<pre><code class="language-javascript">export const Order = () =&gt; {
  const { state } = useLocation();
  return &lt;main&gt;{state ? &lt;Success data={state.data} /&gt; : &lt;Fail /&gt;}&lt;/main&gt;;
};
</code></pre>
<p>주문 페이지에서는 가져온 데이터는 받아온 status 값에 따라 보여지며 성공했을 때 받아온 state 값으로 데이터를 불러올 수 있다</p>
<p>Success 컴포넌트에는 받아온 데이터를 뿌려서 작성해준다</p>
<hr>
<p>주문완료 후 주문내역 페이지 만들기</p>
<p>[Dashboard.js]</p>
<pre><code class="language-javascript">const response = await fetch(
        `http://localhost:8000/660/orders?user.id=${cbid}`,
</code></pre>
<p>api 엔드포인트는 json-server-auth 에서 사용한 660 번에 유저 아이디를 가져와서 데이터를 가져올 수 있다</p>
<p>가져온 데이터를 통해서 빈 카트 또는 가져온 데이터에서 카트 데이터를 뽑아내서 뿌려주어 주문내역 카드 컴포넌트를 만들 수 있다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL]]></title>
            <link>https://velog.io/@beom_pie/TIL-koqirzhq</link>
            <guid>https://velog.io/@beom_pie/TIL-koqirzhq</guid>
            <pubDate>Tue, 30 May 2023 11:50:07 GMT</pubDate>
            <description><![CDATA[<p>장바구니 등 토큰이 필요한 화면 그려줄 때 계속 token 의 여부에 따라 조건문으로 사용하면 계속 반복된 코드의 사용이 일어난다 -&gt; 하나의 컴포넌트로 묶자</p>
<p>[ routes &gt; ProtectedRoute.js ]</p>
<pre><code class="language-javascript">export const ProtectedRoute = ({ children }) =&gt; {
  const token = JSON.parse(sessionStorage.getItem(&quot;token&quot;));
  return token ? children : &lt;Navigate to=&quot;/login&quot; /&gt;;
};
</code></pre>
<p>이걸 다시 모든 라우트들이 있는 파일에서 장바구니 페이지를 감싸주면 된다</p>
<hr>
<p>장바구니에 있는 상품들을 결제 창으로 정보를 넘길 때</p>
<p>라우트 JSON 파일을 만들어 
 routes.json
 { &quot;/users*&quot;: &quot;/600&quot; }</p>
<p>json-server-auth 600으로 하면 토큰을 가지고 있어야 정보 접근 가능하도록 해준다 (각각 번호를 다르게 하면 다른 설정이 가능)</p>
<p><a href="https://github.com/jeremyben/json-server-auth">JSON SERVER AUTH</a></p>
<p> npx json-server data/db.json -m ./node_modules/json-server-auth -r data/routes.json --port 8000 로 서버를 열어주자 (예전엔 -r routes.json 부분이 없었음 !)</p>
<hr>
<p>[Checkout.js]</p>
<pre><code class="language-javascript">const [user, setUser] = useState({});

  useEffect(() =&gt; {
    const token = JSON.parse(sessionStorage.getItem(&quot;token&quot;));
    const cbid = JSON.parse(sessionStorage.getItem(&quot;cbid&quot;));
    async function getUser() {
      const response = await fetch(`http://localhost:8000/600/users/${cbid}`, {
        method: &quot;GET&quot;,
        headers: {
          &quot;Content-Type&quot;: &quot;application/json&quot;,
          Authorization: `Bearer ${token}`,
        },
      });
      const data = await response.json();
      setUser(data);
    }
    getUser();
  }, []);</code></pre>
<p>회원가입 할 때 세션 스토리지에 있는 cbid 와 토큰을 가져와서 결제 모달창을 열었을 때 useEffect 로 가져온다</p>
<p>url 은 위 routes.json 에서 설정하였듯 /600/users/cbid 로 하여 해당 아이디의 정보를 가져온다</p>
<p>헤더에 있는 인가는 토큰을 넘긴다</p>
<hr>
<p>[Checkout.js]</p>
<p>결제모달 창에서 결제하기 버튼을 눌렀을 때 이름,이메일,상품 정보 등등을 넘겨야 한다</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/fb4543af-6107-4633-8341-6ffab18cbc1d/image.png" alt=""></p>
<p>useCart를 사용해서 가져온 정보들을 넘겨주자
user 의 값은 위에서 useEffect를 통해 가져온 유저 정보를 넘겨주면 된다</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/309e0e7f-fde9-4330-a28c-3cf5dfc5fc30/image.png" alt=""></p>
<p>위에서 설정한 인가 번호 660을 사용한 엔드포인트로 정보를 넘기기에 POST 를 사용한다</p>
<p>결제하기를 눌렀을 때 정보를 다 넘겼으므로 다시 장바구니는 비워주어야 한다
useCart로 가져온 clearCart 함수를 실행하여 장바구니를 비워주고 홈으로 돌려보내자</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL]]></title>
            <link>https://velog.io/@beom_pie/TIL-cs4qvsov</link>
            <guid>https://velog.io/@beom_pie/TIL-cs4qvsov</guid>
            <pubDate>Mon, 29 May 2023 13:23:06 GMT</pubDate>
            <description><![CDATA[<p>카트에 상품이 들어있는지 여부에 따른 버튼 바꾸기</p>
<pre><code class="language-javascript">const [isCart, setIsCart] = useState(false)

useEffect(() =&gt; {
  const productInCart = cartList.find(item =&gt; item.id === product.id);

  if(productInCart){
    setInCart(true);
  }else{
    setInCart(false);
  }
}, [cartList, product.id]);
</code></pre>
<p>카트에 들어있는지 없는지에 대한 useState로 조건 확인 만들어준 다음</p>
<p>useEffect를 통해서 카트 리스트에 접근하여 일치하는 아이템의 id 가 있는지 확인</p>
<p>inCart의 참 거짓 여부로 보여주는 버튼 다르게 하기</p>
<hr>
<p>재고 없는 상품 버튼 비활성화하기 (단순 css 조건 추가)</p>
<pre><code class="language-javascript">className={`product.in_stock ? &quot;&quot; : &quot;cursor-not-allowed&quot;`}
disabled={product.in_stock ? &quot;&quot; : &quot;disabled&quot;}</code></pre>
<p>cursor-now-allowed 조건 추가 시 마우스 포인터에 금지표시(?) 가 추가된다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[3/30 - TIL (React Query)]]></title>
            <link>https://velog.io/@beom_pie/330-TIL-React-Query</link>
            <guid>https://velog.io/@beom_pie/330-TIL-React-Query</guid>
            <pubDate>Thu, 30 Mar 2023 07:39:52 GMT</pubDate>
            <description><![CDATA[<p>#Section 4 : React Query in Larger App (커스텀 훅 작성, 에러 핸들링하기)</p>
<ul>
<li>강의에서 기본으로 제공된 파일들을 제외하고 React-Query 사용 부분만 보기 !</li>
</ul>
<hr>
<h4 id="커스텀-훅">커스텀 훅</h4>
<p>커스텀 훅을 만들면 다양한 컴포넌트에서 사용이 가능하다
또한 키가 섞이는 걸 방지하며 함수가 섞이는 것 또한 방지할 수 있다</p>
<hr>
<h3 id="기초세팅">기초세팅</h3>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/a4a14f91-4148-4fc7-92f2-80369d6ce1ff/image.png" alt=""></p>
<p>우선 빈 파일을 export const queryClient = new QueryClient(); 로 설정</p>
<p>메인 App 파일에서 QueryClientProvider 태그 안에 클라이언트는 위에 선언한 파일을 제공해주자</p>
<p>queryKeys 의 경우 키값들을 명시하여 오타 및 오류를 방지하는 용도로 사용 !</p>
<hr>
<h3 id="useisfetching-훅을-사용해보자">useIsFetching 훅을 사용해보자</h3>
<p>작은 애플리케이션</p>
<ul>
<li>useQuery 가 반환하는 객체에서 isFetching 을 사용해서 (구조분해할당) fetching 에 대한 핸들링을 했었다</li>
<li>isLoading은  ( isFetching + no cached data )</li>
</ul>
<p>큰앱</p>
<ul>
<li>현재 프로젝트에서는 로딩스피너로 fetching 중일 때 보여줄 것이다</li>
<li>useisfFetching은 현재 fetching 중인지 아닌지 알 수 있다</li>
<li>또한 모든 커스텀 훅에 대한 isFetching 매번 쓸 필요없어진다</li>
<li>useisFetching의 값이 0보다 크면 참으로 평가된다</li>
</ul>
<pre><code class="language-javascript">import { useIsFetching } from &#39;react-query&#39;;

export function Loading(): ReactElement{
  const isFetching = useIsFetching();

  const display = isFetching ? &#39;inherit&#39; : &#39;none&#39;;

  return (spinner)
}
</code></pre>
<hr>
<h3 id="에러-핸들링">에러 핸들링</h3>
<p>쿼리 함수가 에러를 발생시키면 onError이 실행된다
React-Query 가 콜백에 에러 매개변수를 전달하기 때문에 다양한 방식으로 에러 처리가 가능하다</p>
<p>passing errors to toasts
useQuery error 을 chakra UI toast에 넘겨주자
처음엔 싱글콜 -&gt; 중앙화 centralized
onerror 콜백 (과거엔 useQuery 가 반환하는 isError, error 을 사용했다) -&gt; 에러 발생 시 run 한다
error parameter to callback
toast = 메세지가 바닥에 튀어올라오는 것 (charkra ui가 같이 들고옴)</p>
<pre><code class="language-javascript">//useTreatments.ts

async function getTreatments(){
  ///data fetching
}

export function useTreatments(){
  const fallback = [];
  const { data = fallback } = useQuery(queryKeys.treatments, getTreatments);
  //fallback = 데이터를 가져올 때까지는 데이터가 없기에 (안하면 Undefinted 출력됨)
  return data
}

</code></pre>
<p>Global Error Handler 만들기
queryCache 디폴트로 전역 에러 핸들러를 포함하기
이렇게 하면 쿼리 캐시에 핸들러가 묶이게 된다 (개별 쿼리가 아닌)</p>
<pre><code class="language-javascript">//queryClient.ts

const toast = createStandaloneToast({theme});

function queryErrorHandler(){
  const title = error instanceof Error ? error.message : &#39;error connecting&#39;;
  toast({ title, status : &#39;error&#39;, variant: &#39;subtle&#39;, isClosable:true )}       
}

export const queryClient = new QueryClient({
        queryCache : new QueryCache({
            onError : queryErrorHandler,
        }),
});

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[1/18 - TIL]]></title>
            <link>https://velog.io/@beom_pie/118-TIL</link>
            <guid>https://velog.io/@beom_pie/118-TIL</guid>
            <pubDate>Thu, 19 Jan 2023 05:12:36 GMT</pubDate>
            <description><![CDATA[<h4 id="홈-화면-구현하기">홈 화면 구현하기</h4>
<p>구현해야 할 항목들을 나누어서 시작해보자 !</p>
<p>홈 화면 </p>
<ol>
<li>최상단 -&gt; 헤더 (좌우 버튼 클릭 시 월 단위 이동 가능하도록)</li>
<li>버튼 -&gt; 필터링 (최신순, 감정 점수에 따라 다르게 보이게)</li>
<li>일기 보이기 (날짜, 내용, 감정에 따른 색깔 변화)</li>
</ol>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/9c108b79-a519-47ab-bc17-8295c635545c/image.png" alt=""></p>
<p>단, 필터링의 경우 데이터가 있어야 하니 일기 리스트를 먼저 구현 후 필터링을 구현하자!</p>
<hr>
<p>[Home.js]</p>
<h4 id="헤더에-있는-날짜-구현하기">헤더에 있는 날짜 구현하기</h4>
<p>오늘 날짜를 스테이트에 담아서 사용</p>
<p>현재날짜를 curDate 스테이트에 보관하여 사용</p>
<p>getMonth()의 경우 0월부터 시작하므로 + 1 을 해줘야 한다 !</p>
<p>버튼을 눌렀을 때 다음달, 전달로 이동하도록 increaseMonth, decreaseMonth 함수 작성 !
<img src="https://velog.velcdn.com/images/beom_pie/post/443798eb-df22-4c14-88be-cc6cbb4bcce7/image.png" alt=""></p>
<hr>
<h4 id="일기-리스트-구현하기">일기 리스트 구현하기</h4>
<p>먼저 데이터가 필요하므로 -&gt; [Emotion.js] 로 이동하여 더미 데이터를 작성, 활용하여 데이터 스테이트에 집어넣어준다</p>
<pre><code>const [data,dispatch] = useReducer(reducer, dummyData);</code></pre><p>다시 [Home.js] 로 돌아와 useContext 를 활용하여 데이터를 가져오자</p>
<pre><code>const diaryList = useContext(DiaryStateContext)</code></pre><p><img src="https://velog.velcdn.com/images/beom_pie/post/583a30bd-fcd9-44a8-8ed7-9e0f8968095b/image.png" alt=""></p>
<ul>
<li><p>가져왔지만 그냥 쓰면 안되고 날짜에 따라 가공해야 함</p>
</li>
<li><p>버튼을 눌렀을 떄 해당하는 연,월의 데이터만 뽑아야 하기 때문에 useEffect 사용하자 (curDate 가 변하는 순간에만 diaryList 에서 데이터 뽑아오기)</p>
</li>
<li><p>첫날, 마지막날을 구해서 그 사이 데이터만 뽑아내면 된다 !</p>
</li>
<li><p>의존성 배열 -&gt; diaryList 넣어줘야함, 일기가 변경되었다는걸 뜻하기 때문에</p>
</li>
<li><p>콘솔에 찍어서 날짜에 따른 다이어리가 제대로 나오는지 확인해보자</p>
</li>
<li><p>근데 두번씩 실행된다 -&gt; 처음에 빈 배열을 주었기 때문에 (길이가 &gt;= 1 일때 실행할 수 있도록 조건문 추가 !)</p>
</li>
</ul>
<hr>
<p>일기를 뽑아냈고 리스트를 만들기 전에 필터링 기능을 만들어보자</p>
<p>[DiaryList.js]</p>
<h4 id="최신순-오래된-순-필터링-만들기">최신순, 오래된 순 필터링 만들기</h4>
<p>select 테그를 활용하여 선택메뉴를 만들자</p>
<p> <img src="https://velog.velcdn.com/images/beom_pie/post/d7be1e34-29d3-4c6b-a43c-7a1516fa8f29/image.png" alt=""></p>
<p>프롭으로 받는 값들은 value, onChange, optionList 이다</p>
<p>value 는 어떤걸 선택하고 있는지
onChange 는 값이 변했을 때 바꿀 기능
optionList 는 옵션들을 받는다</p>
<pre><code>const [soryType, setSortType] = useState(&#39;latest&#39;);

&lt;ControlMenu
    value={sortType}
    onChanges={setSortType}
    optionList={sortOptionList}
/&gt;</code></pre><p>onChange 이벤트가 일어나게 되면 e.target.value 를 통해서 sortType의 값을 바꾸게 되고 선택한 값에 따라 sortOptionList 의 객체 값이 바뀌게 된다</p>
<hr>
<p>바뀐 값에 따라 일기들이 필터에 따라 바뀌어야 한다</p>
<p>sort 함수는 원본 배열 자체를 정렬시킴 -&gt; 깊은 복사를 해서 사용하자</p>
<pre><code>const copyList = JSON.parse(JSON.stringify(diaryList))</code></pre><p>stringify -&gt; 배열인 diaryList 를 문자열로 바꿔줌 -&gt; parse -&gt; 다시 복호화 시켜줌</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/87a26dbf-6ef7-4f62-89e0-fc477fd8dce6/image.png" alt=""></p>
<p>filter 값에 따른 필터링이 달라지기 때문에 함수 새로 작성</p>
<p>filterCallBack 에 item 을 전달 받았을 때 필터가 좋음일 때 감정점수가 3 이하인 경우 / 아닐 경우 3 보다 클 경우를 반환</p>
<p>filteredList 는 누른 값에 따른 필터링 실행시켜 준다
-&gt; 전부라면 그대로 반환, 아니라면 필터를 적용 (copyList.filter((emotion) =&gt; filterCallBack(emotion)) 가 참인 경우만 반환</p>
<hr>
<p>출처
<a href="https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard">한입리액트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1/14 - TIL]]></title>
            <link>https://velog.io/@beom_pie/114-TIL</link>
            <guid>https://velog.io/@beom_pie/114-TIL</guid>
            <pubDate>Thu, 19 Jan 2023 04:01:14 GMT</pubDate>
            <description><![CDATA[<h3 id="🛠기초공사-항목">🛠기초공사 항목</h3>
<ol>
<li><p>상태 관리 세팅하기
프로젝트 전반적으로 사용될 일기 데이터 state 관리 로직 작성하기</p>
</li>
<li><p>프로젝트 state context 세팅하기
일기 데이터 state를 공급할 context를 생성하고 provider로 공급하기</p>
</li>
<li><p>프로젝트 dispatch context 세팅하기
일기 데이터 state의  dispatch 함수들을 공급할 context를 생성하고 provider로 공급하기
<img src="https://velog.velcdn.com/images/beom_pie/post/3fcafd13-41fe-4ddc-ab5d-971b0d1484f2/image.png" alt=""></p>
</li>
</ol>
<hr>
<h3 id="상태-관리-세팅하기">상태 관리 세팅하기</h3>
<p>[emotion.js]</p>
<p>일기 관리 스테이트를 작성하자</p>
<ol>
<li>useReducer 함수 로직을 작성하고 reducer 함수와 일단 빈 배열을 전달해주자</li>
</ol>
<pre><code>const [data,dispatch] = useReducer(reducer,[])</code></pre><ol start="2">
<li>다음으로 reducer 함수를 작성해보자</li>
</ol>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/29912961-33d9-4a5b-b1a3-a66cdf63cec3/image.png" alt=""></p>
<ol start="3">
<li>리듀서에 맞춰 dispatch 함수를 만들어보자</li>
</ol>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/c36083ef-cdc4-4f73-aedf-be980ed33845/image.png" alt=""></p>
<p>dataId 를 useRef 로 0을 입력함으로써 데이터 아이디로 사용</p>
<p>onCREATE 작성시 date 까지 받는 이유는 언제 작성했는지까지 받을것이기 때문
onRemove 는 targetId 를 받아와 어떤 아이디의 일기를 삭제할 것인지 결정
onEdit targetId, content, data, emotion 다 받아와야 한다 -&gt; 수정할 것이기 때문</p>
<hr>
<h3 id="state-context-세팅하기">state Context 세팅하기</h3>
<p>만든 data state 를 컴포넌트 전역에 공급해보자</p>
<pre><code>export const DiaryStateContext = React.createContext()</code></pre><p>컴포넌트 전체를 provider 로 감싸주고 value 는 data 를 제공</p>
<hr>
<h3 id="dispatch-context-세팅하기">dispatch Context 세팅하기</h3>
<p>만든 함수들을 공급해주자</p>
<pre><code>export const DiaryDispatchContext = React.createContext()</code></pre><p>Provider 로 감싸주고 value 는 만든 함수들을 제공 (onCreate, onEdit, onRemove);</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/c6732d1c-464b-4dca-b16f-c15ce6e2654b/image.png" alt=""></p>
<hr>
<p>출처
<a href="https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard">한입리액트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1/12 - TIL (React Router)]]></title>
            <link>https://velog.io/@beom_pie/112-TIL-React-Router</link>
            <guid>https://velog.io/@beom_pie/112-TIL-React-Router</guid>
            <pubDate>Thu, 12 Jan 2023 03:10:37 GMT</pubDate>
            <description><![CDATA[<h3 id="react-router-dom의-유용한-기능">React Router Dom의 유용한 기능</h3>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/5dc6b48a-3df5-48c2-86e3-4f7ee27cf363/image.png" alt=""></p>
<h4 id="1-path-variables-useparams">1. Path Variables (useParams)</h4>
<ul>
<li>몇번째 일기로 이동하고 싶을 때 -&gt; /diary/:id</li>
<li>diary에서 -&gt; 몇번째 아이디를 넣기 위해선느 뒤에 / :id 를 작성하여 값을 전달하겠다 선언</li>
<li>path variable (id) 객체를 useParams에 전달해준다</li>
</ul>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/dc52bb32-7f40-4bd3-8e54-8e58f97416dc/image.png" alt=""></p>
<hr>
<h4 id="2-query-string-usesearchparams">2. Query String (useSearchParams)</h4>
<ul>
<li>예시 : /edit?id=10&amp;mode=dark (?이후 모든 문자가 query string 이다)</li>
</ul>
<p><code>const [searchParmas, setSearchParmas] = useSearchParams();</code></p>
<ul>
<li><p>searchParams를 사용하면 아이디 값을 가져올 수 있다
<code>const id = searchParmas.get(&#39;id&#39;);</code>
위의 예시에서 id 값으로 10이 출력된다</p>
</li>
<li><p>searchPamas, setSearchParams는 배열을 반환한다
첫번째 반환 인덱스 = get을 통해 쿼리스트링을 꺼내 쓸 수도 있다</p>
</li>
<li><p>setSearchParmas = useState 처럼 searchParams 변경시킬수도 있다! 
( = 쿼리스트링을 바꿀 수 있다)</p>
</li>
</ul>
<h4 id="3-page-moving-usenavigate">3. Page Moving (useNavigate)</h4>
<ul>
<li>useNavigate 는 페이지를 이동시킬 수 있는 함수를 반환</li>
<li>함수를 navigate로 받고 인자로 경로를 적어주면 해당 경로 페이지로 이동시켜준다</li>
<li>뒤로가기려면 navigate(-1) 로 작성해주면 된다</li>
</ul>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/5c26efc7-612e-4e18-bde0-c37c6dc35e32/image.png" alt=""></p>
<hr>
<p>출처
<a href="https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard">한입리액트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1/11 - TIL (Context API)]]></title>
            <link>https://velog.io/@beom_pie/111-TIL-Context-API</link>
            <guid>https://velog.io/@beom_pie/111-TIL-Context-API</guid>
            <pubDate>Wed, 11 Jan 2023 07:34:24 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/beom_pie/post/6be229bc-6f63-4d4f-ab94-50449c3e4c66/image.png" alt="">
현재까지의 파일 계층 구조는 위와 같다
onRemove, onEdit 함수는 실제로 해당 파일에서 사용하지 않지만 props로 내려주기 위해 존재하고 있다
props drilling 을 막기 위해 등장한 것이 context API 이다</p>
<hr>
<h3 id="context-api">context API</h3>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/78c30989-53b5-4a55-89c4-2e07f1a5b27a/image.png" alt="">
모든 데이터를 가지고 있는 컴포넌트가 Provider 라는 공급자에게 데이터를 넘겨준다
공급자는 자식 뿐만 아니라 자손까지 데이터를 직접 전달할 수 있다 (props 전달 필요 없다!!)</p>
<p>사용하기 위해서는</p>
<ol>
<li>context 생성 
<code>const MyContext = React.createContext(defaultValue);</code></li>
<li>context provider 를 통한 데이터 공급<pre><code>&lt;MyContext.Provider value={전달하고자 하는 값}&gt;
{자식 컴포넌트들}
&lt;/MyContext.Provider&gt;</code></pre></li>
</ol>
<hr>
<h3 id="simplejs">[simple.js]</h3>
<pre><code>export const DiaryStateContext = React.createContext();</code></pre><p>공급자를 만들고 데이터를 공급해보자
simple 컴포넌트가 리턴하고 있는 최상위에 provider를 작성
value={data}</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/c684f2cc-aeae-4397-8664-5e3f48fd6888/image.png" alt=""></p>
<hr>
<h3 id="diarylistjs">[DiaryList.js]</h3>
<p>이제는 데이터를 더이상 프롭으로 받지않고 context에서 공급받으면 된다</p>
<p>context에서 데이터를 받아오기 위해서는 useContext 훅을 사용해야 한다</p>
<p>useContext에는 한가지 인자를 전달해야 한다 (값을 꺼내고 싶은 context - DiaryContext - simple.js에 있는 &lt;- import 해야함)</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/8c3555b3-71e2-417b-bc67-3ef746e9dda8/image.png" alt=""></p>
<hr>
<p>DiaryList 는 사실 Props drilling 이 일어나고 있지는 않았다, 한 단계만 내려오면 됐기 때문에</p>
<p>반면 onRemove,onEdit같은 상태변화 함수에도 사용해보자</p>
<p>단순히 value prop으로 데이터 뿐만 아니라 함수도 내려보내면 될거같지만,,</p>
<h4 id="안된다">안된다!!!</h4>
<p>provider도 컴포넌트이기 때문에 prop이 바뀌면 재생성된다 -&gt; 밑에 있는 컴포넌트도 모두 재생성되면서 그동안의 최적화가 다 풀리게 된다</p>
<hr>
<h3 id="context-하나-더-만들기">context 하나 더 만들기!!</h3>
<p>dispatch 함수 전용으로 DiaryStateContext 아래에 자식요소로 추가해주자</p>
<p><code>export const DiaryDispatchContext = React.createContext();</code></p>
<p>onRemove, onCreate, onEdit 함수를 묶어서 전달해주자</p>
<pre><code>const memoizedDispatches = useMemo(()=&gt;{
    return {onCreate, onRemove, onEdit}
    } ,[]) </code></pre><p>useMemo를 사용하는 이유 -&gt; memo사용하지 않는 경우 Simple 컴포넌트가 재생성될 때 이또한 재생성 됨 -&gt; 의존성 배열은 빈배열로 재생성되지 않게</p>
<p>value로 전달해준 다음 props으로 전달하였던 모든 함수들을 지워준다</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/3863df02-3bc8-4cb9-865b-dfa9df9e1577/image.png" alt=""></p>
<hr>
<h3 id="diaryeditorjs">[DiaryEditor.js]</h3>
<p>이제 props를 전달받았었던 파일로 이동하여 useContext 훅을 사용하여 simple.js 에서 만들었던 context를 가지고와 사용면 된다!
<img src="https://velog.velcdn.com/images/beom_pie/post/ca44d3d1-cb94-422a-b422-e85de2aa876b/image.png" alt=""></p>
<hr>
<p>출처
<a href="https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard">한입리액트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1/11 - TIL (상태변화 로직 분리하기, useReducer)]]></title>
            <link>https://velog.io/@beom_pie/111-TIL-%EC%83%81%ED%83%9C%EB%B3%80%ED%99%94-%EB%A1%9C%EC%A7%81-%EB%B6%84%EB%A6%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@beom_pie/111-TIL-%EC%83%81%ED%83%9C%EB%B3%80%ED%99%94-%EB%A1%9C%EC%A7%81-%EB%B6%84%EB%A6%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 11 Jan 2023 04:46:57 GMT</pubDate>
            <description><![CDATA[<p>useReducer 리액트 상태관리를 돕는 리액트 훅이다</p>
<p>사용하면 상태변화 로직을 분리할  수 있기 때문에 컴포넌트를 간결하게 작성 가능하다</p>
<p>컴포넌트 바깥에서 작성하며 switch 케이스 문법 사용한다</p>
<hr>
<h4 id="사용법">사용법</h4>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/90ab847c-4e86-433e-b613-d57c9648bfa3/image.png" alt="">
0번째 인덱스인 count = 스테이트다 (useState에서 사용했던 것 처럼 {count} 이렇게 사용 가능)</p>
<p>첫번째 인덱스인 dispatch = 상태를 변화시키는 액션을 발생시키는 함수이다</p>
<p>useReducer 함수 호출 시 reducer 꼭 전달해야함!!
(dispatch 되어 액션이 발생한 것을 reducer 함수가 처리해준다)</p>
<p>두번째로 전달하는 인자 (여기서 1)는 counter 스테이트의 초기값이다</p>
<h4 id="정리">정리</h4>
<p>useReducer을 이용해서 counter 스테이트를 만들고</p>
<p>초기값(여기서는 1)이 할당된다</p>
<p>초기값을 바꿔주고 싶으면 상태변화 함수인 dispatch를 호출한다</p>
<p>상태변화 처리 함수인 reducer가 액션 타입에 따른 처리를 한다 -&gt; counter 스테이트 업데이트 </p>
<p>dispatch 함수 호출 시 객체(액션 객체, type 프로퍼티가 들어있다)를 리듀서 함수에 전달됨</p>
<hr>
<h4 id="reducer-함수">reducer 함수</h4>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/f6b82a09-5759-4143-9849-a7cbbbea8343/image.png" alt=""></p>
<p>첫번째 인자 = 현재 가장 최신의 인자</p>
<p>두번째 인자 = dispatch 호출할때 전달되었던 액션 객체를 전달받는다</p>
<p>전달받은 액션타입을 토대로 케이스에 따른 스테이트가 바뀐다</p>
<hr>
<p>보통 가장 복잡한 상태 로직을 갖고 있는 것 = 부모 컴포넌트 (여기서는 Simple.js)이다</p>
<p>[simple.js]</p>
<p><code>const [data, dispatch] = useReducer(reducer, [])</code>
위처럼 작성하여 useReducer을 사용해보자</p>
<p>우선 simple.js 에서 데이터 스테이트에 어떠한 액션이 존재할 수 있는지 탐색해야한다</p>
<p>그리고 setData가 했었던 역할을 reducer / dispatch로 나눠주자</p>
<p>getData 함수에서 initData를 setData에 넘겨주었다</p>
<p>dispatch({type:&quot;INIT&quot;}) -&gt; 액션 타입은 &#39;INIT&#39; -&gt; 데이터 초기화하는 작업, data:initData</p>
<p>reducer는 액션 객체를 받는다 -&gt; tpye:&#39;INIT&#39; -&gt; 필요한 데이터는 initData다</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/b56e4145-416f-4d38-ac55-6970d8dbe195/image.png" alt=""></p>
<p>이제 reducer 함수에서 INIT 타입 액션을 받았을 때 스테이트 변화 시켜주는 코드를 작성하자</p>
<p>왜 Action.data를 반환해줄까?</p>
<p>getData 함수에서 dispatch를 일으켰을때 타입 : init이고 초기화 : data:initData로 했기 때문에</p>
<p>reducer에서 받았을 때 액션 객체에서 data 프로퍼티를 꺼내서 그 값을 반환해주어 새로운 스테이트가 된다</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/238f16a2-f290-4846-8327-979c91f3c7d3/image.png" alt=""></p>
<hr>
<h4 id="oncreate">onCreate</h4>
<p>바로 dispatch를 작성해보자</p>
<pre><code>    dispatch({
      type: &quot;CREATE&quot;,
      data: {
        author,
        content,
        emotion,
        id: dataId.current,
      },
    });</code></pre><p>원래 있던 작성날짜는 reducer 함수에서 만들어줄것</p>
<pre><code>case &quot;CREATE&quot;:{
      const created_date = new Date().getTime();
      const newItem = {
        ...action.data,
        created_date
      }
      return [newItem, ...state]
    }</code></pre><p><img src="https://velog.velcdn.com/images/beom_pie/post/0ca1f846-f615-4f2d-ba58-68b3bf558aed/image.png" alt=""></p>
<hr>
<h4 id="onremove">onRemove</h4>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/e347d1a4-c0c8-4dcb-aa7a-b699f9967fff/image.png" alt=""></p>
<p>targetId 만 전달해주어 reducer 함수가 삭제해서 새로운 스테이트를 반환하도록 해주자</p>
<hr>
<h4 id="onedit">onEdit</h4>
<p>edit 타입의 액션이 발생했을 때 targetId + newContent를 전달받는다</p>
<p>기존 스테이트에서 map을 통해 targetId와 일치하는 요소를 찾아주어 content : newContent로 수정해주고 나머지 요소는 그대로 돌려준다</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/46443796-3a35-46e7-9338-d3b45aa5840e/image.png" alt=""></p>
<hr>
<h4 id="reducer-함수-1">reducer 함수</h4>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/0c89d9c2-f40c-45c9-b994-3a411669b293/image.png" alt=""></p>
<hr>
<p>출처
<a href="https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard">한입리액트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1/9 - TIL]]></title>
            <link>https://velog.io/@beom_pie/111-TIL</link>
            <guid>https://velog.io/@beom_pie/111-TIL</guid>
            <pubDate>Wed, 11 Jan 2023 03:10:03 GMT</pubDate>
            <description><![CDATA[<p>오늘도 최적화를 진행해보자!</p>
<p>일기 아이템 하나만 삭제해도 나머지 일기들이 모두 재렌더링이 되고있다 </p>
<p>오늘은 다이어리 아이템에 초점을 맞춰 최적화를 진행해보자!</p>
<p>프롭으로 받고 있는 것 중 두가지 (onEdit, onRemove)는 함수, 나머지는 데이터다</p>
<p>데이터 중 내용인 Content 를 제외하고는 모두 변할 수 없는 데이터다</p>
<p>오늘의 최적화 : onEdit, onRemove</p>
<hr>
<p>최적화의 시작은 React.memo로 컴포넌트를 묶어주는것이다!</p>
<p><code>React.memo(DiaryItem)</code></p>
<p> 그리고 언제나 그랬듯 useEffect로 어떤 아이템들이 재렌더링이 일어나고 있는지 확인해보자</p>
<p>onCreate, onRemove -&gt; 데이터 스테이트가 변하면 재생성 될 수 밖에 없는 함수이다</p>
<p>부모 컴포넌트인 Simple.js로 가서 저번에 했던것과 마찬가지로 onCreate, onRemove 함수에 최적화를 시켜보자</p>
<p>onRemove -&gt; setData() &lt;-에 함수형으로 업데이트 하도록 지시해야한다, 의존성 배열은 빈값</p>
<p>파라미터로 전달되는 data는 최신 데이터를 전달해야 한다 (함수형 업데이트 인자 부분에 데이터를 사용하자)</p>
<p>onEdit도 마찬가지로 함수형 업데이트 실행!</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/d4057900-37d5-4b63-b884-2fe7cdb2e8c2/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1/8 - TIL (최적화, useCallback)]]></title>
            <link>https://velog.io/@beom_pie/18-TIL-%EC%B5%9C%EC%A0%81%ED%99%94-useCallback</link>
            <guid>https://velog.io/@beom_pie/18-TIL-%EC%B5%9C%EC%A0%81%ED%99%94-useCallback</guid>
            <pubDate>Sun, 08 Jan 2023 03:54:51 GMT</pubDate>
            <description><![CDATA[<h4 id="컴포넌트-최적화하기">컴포넌트 최적화하기</h4>
<p>최적화 되어야 할 부분을 어떻게 찾지?
React development tools &gt; components 탭 &gt; 렌더할때 하이라이트 기능 켜기 &gt; 어디서 변화가 일어나는지 찾기 쉽다 !
오늘의 최적화 : 일기를 하나 삭제했을 때 &gt; 일기 작성 컴포넌트도 깜빡임 
(그럴 필요가 전~혀 없는데??)
<img src="https://velog.velcdn.com/images/beom_pie/post/396f17db-32a3-46a2-8107-275f7a9f4936/image.png" width="60%"></p>
<blockquote>
<p>렌더링은 언제 일어날까?</p>
</blockquote>
<ul>
<li>본인이 가진 스테이트가 변경될 때</li>
<li>자신이 받은 프롭이 변경될 때</li>
<li>부모가 리랜더링 되었을 때</li>
</ul>
<hr>
<p>일기를 작성하여 저장하는데 작성 컴포넌트가 왜 리렌더링 될까?? 그것은 바로 작성 컴포넌트에서 받고 있는 onCreate 함수 때문!</p>
<p>[DiaryEditor.js]
<img src="https://velog.velcdn.com/images/beom_pie/post/6a839c72-335d-49c9-b8f8-18cd07d8e899/image.png" alt="">
코드가 긴 전체 컴포넌트를 React.memo로 감쌀 경우 -&gt; export default 하는 부분을 전체 감싸주는 것도 가능!
<code>export default React.memo(DiaryEditor)</code></p>
<hr>
<p>[Simple.js]</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/448cf868-64dc-4c48-a202-769a495fc6b2/image.png" alt=""></p>
<p>onCreate 함수는 일기 저장시 데이터에 아이템 추가하는 역할을 한다</p>
<p>[DiaryEditior.js] 에서 useEffect로 컴포넌트가 언제 렌더되는지 확인해보자
총 두번 발생하는 것을 확인할 수 있다 (왜?? 부모컴포넌트 -&gt; 초기 데이터 스테이트 초기값이 빈값인 상태로 처음 랜더링이 일어나고 (빈배열상태) -&gt; getData 하여 값을 가져오면 데이터 스테이트가 한번 더 바뀌게 된다</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/66fed084-cd61-46b7-b04b-a9762a84d00c/image.png" alt=""></p>
<hr>
<p>그렇다면 그냥 onCreate 함수를 react.memo로 감싸면 되는 것 아닌가?!?!</p>
<p>아니다!!! onCreate 함수가 참조하는 것은 비원시 타입으로 얕은 비교를 함으로 react.memo로 할 수 없다! </p>
<p>oncreate 함수를 react.memo로 감싸게 된다면 만들어질때마다 리렌더 될 수 밖에 없다! simple 컴포넌트가 재생성될때마다 리렌더링 계속 될 것이다!</p>
<p>-&gt; oncreate 함수가 재생성 안되어야! 에디터 컴포넌트 리렌더 막을 수 있으며 최적화가 가능하다 !!!</p>
<hr>
<p>그럼 어떻게 하지?? useMemo (함수가 반환하는 값을 다시 사용할 수 있도록 의존성 배열을 기준으로) 를 사용해볼까??</p>
<p>사용하면 안된다!!! 함수 반환이 아니라 값을 반환하기 때문이다</p>
<p>우리가 원하는 것은? oncreate 함수 그잡채를 반환하는 것이지 값이 아니다!</p>
<p>-&gt; useCallback이 답이다! (메모이제이션된 콜백을 반환한다,,,의존성 배열 값이 변하지 않으면 첫번째 인자로 전달한 콜백함수를 재사용 할 수 있도록 도와준다)</p>
<hr>
<p>[Simple.js]</p>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/75d668bb-da93-4867-8d34-9a930503d242/image.png" alt=""></p>
<p>onCreate 함수를 useCallback으로 감싸보자 (일단은 의존성 배열은 빈값으로)</p>
<p>일기를 작성해보면 있엇던 데이터들이 없어지고 만든 일기 하나만 남는다 </p>
<p>왜냐하면 의존성배열에 아무값도 없어서 그런 것이다
맨 처음에 oncreate 함수가 만들어지는 것은 빈 배열을 기준으로 처음 만들어진다</p>
<p>그렇다면 의존성 배열에 data 를 넣어볼까?? </p>
<p>그래도 안된다! 이렇게 작성하면 우리가 원하는대로 작동하지 않는다!</p>
<p>우리는 데이터 스테이트가 변해도 재생성되지 않기를 바라는 것이다</p>
<p>재생성되지 않으면서 최신값을 어떠케 참조하지?? 함수형 업데이트를 활용하자!!!</p>
<p><code>setData (()=&gt;{}) 콜백함수를 전달해보자 ((data) =&gt; [newItem, ...data])</code> 상태변화 함수에 함수를 전달하는 것 = 함수형 업데이트 (의존성 배열을 비워놔도 인자를 참고하여 최신 데이터 참조한다)</p>
<hr>
<p><img src="https://velog.velcdn.com/images/beom_pie/post/0f70bbff-a063-4476-b540-fc0faf15afe4/image.jpeg" alt="">
이로써 일기를 작성할 때 작성 컴포넌트가 재렌더링 되는 것을 막을 수 있었다</p>
<p>정리해보자면</p>
<ol>
<li><p>최적화를 위해 어떠한 기능을 수행하는 데 있어 불필요한 렌더링이 발생하는 부분이 있는지 확인해보자 (React Development tools)</p>
</li>
<li><p>불필요한 재렌더링을 유발하는 원인을 찾는다</p>
</li>
<li><p>값이라면 useMemo / 함수 그 자체를 반환해야 하는 경우 useCallback 으로 감싸준다</p>
</li>
</ol>
<p><a href="https://github.com/BEOOM/Diary">깃허브 코드</a>
<a href="https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%EB%A6%AC%EC%95%A1%ED%8A%B8/dashboard">한입크기로 잘라먹는 리액트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[async & await]]></title>
            <link>https://velog.io/@beom_pie/async-await</link>
            <guid>https://velog.io/@beom_pie/async-await</guid>
            <pubDate>Thu, 05 Jan 2023 03:10:37 GMT</pubDate>
            <description><![CDATA[<h4 id="async">async</h4>
<p>promise를 더 가독성 좋게 만들어준다</p>
<pre><code>async function hello(){
    return &#39;hello async&#39;;
}
</code></pre><p>결과로 Promise{pending}이 출력됨 -&gt; .then 사용가능한 것을 알 수 있다</p>
<pre><code>hello().then((res) =&gt; {
  console.log(res);
});</code></pre><p>결과는 hello async가 출력됨</p>
<hr>
<h4 id="await">await</h4>
<pre><code>function delay(ms) {
  return new Promise((resolve) =&gt; {
    setTimeout(resolve, ms);
  });
}

async function helloAsync() {
  // return delay(3000).then(() =&gt; {
  //   return &quot;hello Async&quot;;
  // });
  await delay(3000);
  return &quot;hello async&quot;;
}

async function main() {
  const res = await helloAsync();
  console.log(res);
}

main();</code></pre><p>await 을 비동기함수 호출 앞에 붙이면 비동기 함수가 동기처럼 사용 가능</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Promise]]></title>
            <link>https://velog.io/@beom_pie/Promise</link>
            <guid>https://velog.io/@beom_pie/Promise</guid>
            <pubDate>Tue, 03 Jan 2023 04:16:35 GMT</pubDate>
            <description><![CDATA[<p>비동기를 돕는 객체
비동기 처리에 콜백을 넘겨줄 필요가 없다</p>
<hr>
<h4 id="비동기-작업이-가질-수-있는-3가지-상태">비동기 작업이 가질 수 있는 3가지 상태</h4>
<ol>
<li>pending (대기 상태) - 현재 작업이 진행중 or 시작도 못하는 상태
pending - resolve (해결) - fulfilled</li>
<li>fulfilled (성공) - 비동기 작업이 정상적으로 완료 됨
pending - reject (거부) - rejected</li>
<li>rejected (실패) - 어떠한 이유로 실패함</li>
</ol>
<p>ex) 콜백을 통해서 비동기 처리하기</p>
<pre><code>function isPositive(number){
    setTimeout(() =&gt; {
        if(typeof number === &#39;number&#39;){
            //성공 -&gt; resolve
            resolve(number &gt;= 0 ? &quot;양수&quot; : &quot;음수&quot;);
        } else{
            //실패 -&gt; reject
            reject(&#39;주어진 값이 숫자형 값이 아닙니다&#39;);
        }
    }, 2000);
}

isPositive(
    10,
    (res)=&gt;{
        console.log(&#39;성공적으로 수행함 : &#39;, res
     },
     (err)=&gt;{
         console.log(&#39;실패함:&#39;, err)
     }
);</code></pre><p>성공적으로 수행함 : 양수</p>
<hr>
<pre><code>function isPositiveP(number) {
    //비동기 작업을 실행하는 함수 = executor
    const executor = (resolve, reject) =&gt; {
        setTimeout(() =&gt; {
               if(typeof number === &#39;number&#39;){
                //성공 -&gt; resolve
                resolve(number &gt;= 0 ? &quot;양수&quot; : &quot;음수&quot;);
             } else{
                //실패 -&gt; reject
                reject(&#39;주어진 값이 숫자형 값이 아닙니다&#39;);
             }
         }, 2000);
    };
    //isPositiveP에서 executor 실행하기
    //비동기작업 자체인 프라미스를 저장할 상수를 만들고 new 키워드로 프라미스 객체를 생성(실질적인 실행자 함수 executor 을 넘겨줌)
    const asyncTask = new Promise(executor)
    return asyncTask;
    //isPositiveP의 반환값이 Promise로 변함
}

const res = isPositiveP(101);
//res라는 상수가 반환받은 promise 객체를 통해서 resolve/reject의 결과값을 아무데서나 사용 가능

res
    .then((res)=&gt;{
        console.log(&#39;작업성공: &#39;,res);
     })
    .catch((err)=&gt;{
        console.log(&#39;작업실패 :&#39;, err);
     });
</code></pre><p>작업 성공 : 양수
resolve에서 전달한 양수라는 값이 콜백함수에 들어온 것을 확인 가능
reject -&gt; catch에서 받을 수 있음</p>
<pre><code>function taskA(a, b) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      const res = a + b;
      resolve(res);
    }, 3000);
  });
}

function taskB(a) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      const res = a * 2;
      resolve(res);
    }, 1000);
  });
}

function taskC(a) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      const res = a * -1;
      resolve(res);
    }, 2000);
  });
}

// taskA(5, 1).then((a_res) =&gt; {
//   console.log(a_res);
//   taskB(a_res).then((b_res) =&gt; {
//     console.log(b_res);
//     taskC(b_res).then((c_res) =&gt; {
//       console.log(c_res);
//     });
//   });
// });

taskA(5, 1)
  .then((a_res) =&gt; {
    console.log(a_res);
    return taskB(a_res);
  })
  .then((b_res) =&gt; {
    console.log(b_res);
    return taskC(b_res);
  })
  .then((c_res) =&gt; {
    console.log(c_res);
  });
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[동기 vs 비동기]]></title>
            <link>https://velog.io/@beom_pie/%EB%8F%99%EA%B8%B0-vs-%EB%B9%84%EB%8F%99%EA%B8%B0</link>
            <guid>https://velog.io/@beom_pie/%EB%8F%99%EA%B8%B0-vs-%EB%B9%84%EB%8F%99%EA%B8%B0</guid>
            <pubDate>Tue, 03 Jan 2023 03:20:09 GMT</pubDate>
            <description><![CDATA[<h4 id="자바스크립트의-싱글-스레드-작업-수행-방식">자바스크립트의 싱글 스레드 작업 수행 방식</h4>
<ul>
<li>자바스크립트는 코드가 작성된 순서대로 작업을 처리한다</li>
<li>이전 작업을 진행 중일 때는 다음 작업을 수행하지 않고 기다린다</li>
<li>먼저 작성된 코드를 다 실행하고 나서 뒤에 작성된 코드를 실행한다</li>
<li>연산과정을 하는 일꾼 = 스레드 (코드 한줄한줄 실행하는)</li>
<li><blockquote>
<p>동기 방식의 처리</p>
</blockquote>
</li>
</ul>
<h4 id="단점">단점</h4>
<ul>
<li>동기적 처리는 하나의 작업이 너무 오래 걸리게 되면 하나의 작업이 종료될 때까지 뒤에 작업이 멈춰있기 때문에 전반적인 흐름이 느려진다</li>
</ul>
<hr>
<h4 id="멀티스레드">멀티스레드</h4>
<ul>
<li>코드를 실행하는 일꾼(스레드)을 여러 개 사용하는 방식으로 작업의 분할이 가능하다</li>
<li>다만 자바스크립트는 싱글스레드 방식이다!!</li>
</ul>
<hr>
<h4 id="비동기-작업-동기-방식-단점의-극복">비동기 작업 (동기 방식 단점의 극복)</h4>
<ul>
<li>여러개의 작업을 동시에 실행시킨다</li>
<li>먼저 작성된 코드의 결과를 기다리지 않고 다음 코드를 바로 실행한다</li>
<li>하나의 작업이 스레들르 점유하지 않는, 블로킹하지 않는 방식 (=논블로킹 방식)</li>
<li>작업의 결과 확인 -&gt; 콜백 함수를 넣어준다</li>
</ul>
<hr>
<h4 id="heap--call-stack">Heap &amp; Call Stack</h4>
<ul>
<li>자바스크립트 엔진은 힙과 콜스텍으로 구성되어 있다</li>
<li>힙 (변수/상수를 저장하는 메모리)</li>
<li>콜스택 (작성한 코드를 실행하는)</li>
</ul>
<hr>
<h4 id="콜백지옥">콜백지옥</h4>
<ul>
<li>비동기 처리의 결과를 또다른 비동기 결과로 이용하는 로직</li>
<li>해결방법 -&gt; Promise 객체</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL - 12/29]]></title>
            <link>https://velog.io/@beom_pie/TIL-1229</link>
            <guid>https://velog.io/@beom_pie/TIL-1229</guid>
            <pubDate>Thu, 29 Dec 2022 06:49:06 GMT</pubDate>
            <description><![CDATA[<p>Udemy [리액트 완벽 가이드]
#247 ~</p>
<hr>
<p>[components &gt; Counter.js]</p>
<pre><code>import { useSelector, useDispatch} from &quot;react-redux&quot;;

const Counter = () =&gt; {
  const dispatch = useDispatch();

  const counter = useSelector((state) =&gt; state.counter.counter);
  const show = useSelector((state) =&gt; state.counter.showCounter);

  const incrementHandler = () =&gt; {
 dispatch({ type: &quot;increment&quot; });
  };

  const increaseHandler = () =&gt; {
    dispatch({ type: &quot;decrement&quot; });
  };

  const decrementHandler = () =&gt; {
    dispatch(counterActions.decrement());
  };

  const toggleCounterHandler = () =&gt; {
    dispatch(counterActions.toggleCounter());
  };

  return (
    &lt;main className={classes.counter}&gt;
      &lt;h1&gt;Redux Counter&lt;/h1&gt;
      {show &amp;&amp; &lt;div className={classes.value}&gt;{counter}&lt;/div&gt;}
      &lt;div&gt;
        &lt;button onClick={incrementHandler}&gt;Increment&lt;/button&gt;
        &lt;button onClick={increaseHandler}&gt;Increase by 5&lt;/button&gt;
        &lt;button onClick={decrementHandler}&gt;Decrement&lt;/button&gt;
      &lt;/div&gt;
      &lt;button onClick={toggleCounterHandler}&gt;Toggle Counter&lt;/button&gt;
    &lt;/main&gt;
  );
};

export default Counter;
</code></pre><ul>
<li>스토어에 액션을 보내기 위해서 -&gt; useDispatch</li>
<li>액션은 유형 속성이 있는 객체이므로 액션을 보내기 위해서 dispatch({ type: &#39;&#39; }) 의 형식으로 보내며 type의 값은 스토어에서 사용하는 식별자 중 하나</li>
</ul>
<hr>
<p>[components &gt; Counter.js]</p>
<pre><code>class Counter extends Component {
  incrementHandler() {
    this.props.increment();
  }
  decrementHandler() {
    this.props.decrement();
  }
  toggleCounterHandler() {}
  render() {
    return (
      &lt;main className={classes.counter}&gt;
        &lt;h1&gt;Redux Counter&lt;/h1&gt;
        &lt;div className={classes.value}&gt;{this.props.counter}&lt;/div&gt;
        &lt;div&gt;
          &lt;button onClick={this.incrementHandler.bind(this)}&gt;Increment&lt;/button&gt;
          &lt;button onClick={this.decrementHandler.bind(this)}&gt;Decrement&lt;/button&gt;
        &lt;/div&gt;
        &lt;button onClick={this.toggleCounterHandler}&gt;Toggle Counter&lt;/button&gt;
      &lt;/main&gt;
    );
  }
}

//useSelector
//리덕스 스테이트를 받음 -&gt; 객체를 리턴함 (키는 프롭으로 받은것, 값은 리덕스 상태에 들어가는 로직 )
const mapStateToProps = (state) =&gt; {
  return {
    counter: state.counter,
  };
};

//usedispatch와 같음, dispatch 함수를 프롭에 저장
const mapDispatchToProps = (dispatch) =&gt; {
  return {
    increment: () =&gt; dispatch({ type: &quot;increment&quot; }),
    decrement: () =&gt; dispatch({ type: &quot;decrement&quot; }),
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Counter);
</code></pre><ul>
<li>커넥트를 export -&gt; 새 함수를 반환함 , 리턴함수에 counter 보냄</li>
<li>커넥트 함수를 실행 -&gt; 새 함수를 리턴 -&gt; 리턴을 실행 (counter을 여기에 보냄)</li>
<li>연결하기 위해서 실행할때 뭔가 보냄 -&gt; 변수가 있어야 한다(2개 함수)</li>
<li>첫번째 = 리덕스 상태를 전달(prop) 받아서 맵한다 -&gt; 컴포넌트에 받아질 것</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL - 12/27]]></title>
            <link>https://velog.io/@beom_pie/TIL-1227-riqbm9a4</link>
            <guid>https://velog.io/@beom_pie/TIL-1227-riqbm9a4</guid>
            <pubDate>Tue, 27 Dec 2022 04:32:01 GMT</pubDate>
            <description><![CDATA[<p>Udemy [리액트 완벽 가이드] 
#244 ~ #246</p>
<hr>
<p><strong>[store &gt; index.js]</strong></p>
<pre><code>import { createStore } from &quot;redux&quot;;

const counterReducer = (state = { counter: 0 }, action) =&gt; {
  if (action.type === &quot;increment&quot;) {
    return {
      counter: state.counter + 1,
    };
  }
  if (action.type === &quot;decrement&quot;) {
    return {
      counter: state.counter - 1,
    };
  }
  return state;
};

const store = createStore(counterReducer);
export default store;</code></pre><ul>
<li>리액트 앱과 리덕스 스토어와 연결 -&gt; 앱의 컴포넌트가 액션 발송하고 들을 수 있도록</li>
<li>하나뿐인 스통러르 제공하면 되는데, 여기서 제공이란 무엇일까?</li>
</ul>
<hr>
<p><strong>[src &gt; index.js]</strong></p>
<pre><code>import { Provider } from &#39;react-redux&#39;;
import store from &#39;./store/index&#39;;

const root = ReactDOM.createRoot(document.getElementById(&#39;root&#39;));
root.render(&lt;Provider store={store}&gt;&lt;App/&gt;&lt;/Provider&gt;);</code></pre><ul>
<li>다양한 컴포넌트 / 앱 전체에서 스토어에 접근해야 한다면 최상위에서 Provider 로 감싸주어야 한다</li>
<li>감싸주기만 한다고 어떤 스토어에 접근할 수 있는지를 알려주는 것이 아니다 -&gt; 하나의 저장소만 있지만 다른 파일에 저장되어 있기 때문에 import 해와야 한다</li>
<li>모든 컴포넌트들이 저장소에 접근할 수 있게 되며 데이터 받기 / 구독 설정 / 액션 발송도 가능하다!</li>
</ul>
<hr>
<p><strong>[components &gt; counter.js]</strong>
counter 값을 출력하기 위해 리덕스 저장소와 그 안에 있는 데이터에 접근해야 한다</p>
<pre><code>import { useSelector } from &#39;react-redux&#39;;

const Counter = () =&gt; {
    const counter = useSelector(state =&gt; state.counter);

    return (
        &lt;div&gt;{counter}&lt;/div&gt;
        );
}</code></pre><p>*useSelector</p>
<ol>
<li>저장소가 관리하는 상태부분을 우리가 자동으로 선택할 수 있다 ( 상태 객체 전체에서 일부분만 쉽게 떼어내기 편함)</li>
<li>사용할 때 react-redux가 해당 컴포넌트를 위해 리덕스 저장소에 자동 구독 설정해준다 (저장소 데이터가 변경될 때마다 업데이트 -&gt; 최신 데이터를 받는다)</li>
</ol>
<p>*클래스 기반 컴포넌트 -&gt; connect 사용</p>
<ul>
<li>useSelector에 함수 넘겨줘야 한다 -&gt; 그 함수는 react-redux 가 실행 -&gt; 실행될 때 리덕스 상태, 관리된 데이터를 함수에 넣고 필요한 상태 부분을 받게 된다</li>
<li>우리가 저장소에서 추출할 어떤 데이터인지를 결정할 것이다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redux]]></title>
            <link>https://velog.io/@beom_pie/TIL-1227</link>
            <guid>https://velog.io/@beom_pie/TIL-1227</guid>
            <pubDate>Tue, 27 Dec 2022 03:43:27 GMT</pubDate>
            <description><![CDATA[<pre><code>const redux = require(&quot;redux&quot;);</code></pre><p>서드파티 패키지를 가져오기 위해서 위처럼 사용</p>
<pre><code> const store = redux.createStore();</code></pre><ul>
<li>스토어를 만들고 상수에 저장</li>
<li>저장소는 데이터를 관리해야 함 -&gt; 리듀서 함수에 의해 결정 (리듀서 함수가 새로운 상태 스냅샷을 생성할 것이기 때문에)</li>
<li>리듀서는 액션이 도착할 때마다 새로운 상태를 내뱉어야 함</li>
<li>초기실행 시 초기 상태를 뱉어냄</li>
</ul>
<hr>
<pre><code>const counterReducer = (state = { counter: 0 }, action) =&gt; {
  return {
    counter: state.counter + 1,

  };
  //기존의 상태를 바꿀 새로운 스테이트를 반환
};</code></pre><ul>
<li>state : 기존상태, counter : 저장된 기존의 값</li>
<li>이후 createStore에 넘겨주자</li>
<li>리듀서는 항상 2개의 파라미터를 받는다 (기존의 상태 / 액션) -&gt; 어떤 출력을 반환해야 한다 (새로운 상태 객체)</li>
<li>그러므로 리듀서 함수는 순수한 함수여야 한다 (함수 안에는 부수적인 효과도 없어야 한다)</li>
</ul>
<hr>
<pre><code>const store = redux.createStore(counterReducer);</code></pre><ul>
<li>어떤 리듀서가 그 저장소를 변경하는지 저장소가 알아야 하기 때문</li>
<li>저장소를 구독할 누군가 필요 + 발송할 수 있는 액션도 필요</li>
</ul>
<hr>
<pre><code>const counterSubscriber = () =&gt; {
  store.getState();
  //getState()는 createStore()로 저장된 저장소에서 사용할 수 있는 메서드
  //구독함수는 상태가 변경될 때마다 트리거 된다
  //트리거 되면 getState() 메소드로 변경돈 후의 최신 상태를 받을 수 있음
  const latestState = store.getState();
  console.log(latestState);
};</code></pre><ul>
<li>이제 리덕스가 이 구독함수를 인식 + 상태가 변경될 때마다 실행하라고 알려줘야함
저장소 -&gt; subscribe 메소드 호출</li>
</ul>
<hr>
<pre><code>store.subscribe(counterSubscriber);</code></pre><p>함수를 실행하지 않고 가르키기만 한다
리듀서와 구독함수를 모두 리덕스가 실행하기 때문</p>
<hr>
<ul>
<li>해당 상태로 실행하게 되면 Undefined가 출력 (counter) -&gt; 기존 상태가 없기 때문에 -&gt; state에 기본값을 주어야함, 안주면 가정된다</li>
<li>state 기본값은 설정 후 다음에 실행될 때 기존 상태가 있게 되므로 기본값은 사용되지 않는다</li>
<li>state = {counter : 0}</li>
<li>변경 후 실행 -&gt; 실행은 되지만 출력된 값이 없다 &lt;- 액션 발송을 안했기 때문이다<pre><code>store.dispatch({ type: &quot;increment&quot; });</code></pre></li>
<li>dispatch() 액션 발송 메소드</li>
<li>액션 = 자바스크립트 객체 -&gt; 식별자 역할을 하는 타입 프로퍼티를 가진
고유한 문자열 사용!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL - 12/16]]></title>
            <link>https://velog.io/@beom_pie/TIL-1216</link>
            <guid>https://velog.io/@beom_pie/TIL-1216</guid>
            <pubDate>Fri, 16 Dec 2022 06:19:23 GMT</pubDate>
            <description><![CDATA[<p>useCallbak -&gt; 함수를 저장
useMemo -&gt; 값을 저장</p>
<hr>
<p>커스텀 훅은 데이터가 아닌 로직을 공유한다
search / Ingredients 두 컴포넌트에서 모두 사용되는 로직을 공유하도록 만듦
하나의 컴포넌트에서 요청을 보낼 때 다른 컴포넌트에서는 아무일도 일어나지 않음 (ex. ingredients 에서 요청을 보낼 때 search 에서는 x)
-&gt; 컴포넌트간에 스테이트 관련 로직을 공유하는 것
<a href="https://github.com/BEOOM/React-UDEMY/pull/17/commits/26762bb9d1f56e35f29c0816d1cbd3f9ccda406a">코드</a></p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL - 12/14]]></title>
            <link>https://velog.io/@beom_pie/TIL</link>
            <guid>https://velog.io/@beom_pie/TIL</guid>
            <pubDate>Fri, 16 Dec 2022 01:47:30 GMT</pubDate>
            <description><![CDATA[<h1 id="react---udemy">React - Udemy</h1>
<p>#443 
선택한 아이템 삭제하기</p>
<pre><code class="language-javascript">const removeIngredientHandler = (ingredientId) =&gt; {
  setUserIngredients((prevIngredients) =&gt; 
       prevIngredients.filter(
           (ingredient) =&gt; ingredient.id !== ingredientId
        )
     );
}</code></pre>
<p>전의 값을 가지고 와 조건에 부합하지 않으면 버린다 -&gt; 해당 값들로 업데이트 해주기</p>
<pre><code class="language-javascript">const query =
      enteredFilter.length === 0
        ? &quot;&quot;
        : `?orderBy=&quot;title&quot;&amp;equalTo=&quot;${enteredFilter}&quot;`;
    fetch(
      &quot;API주소&quot; + query
    )</code></pre>
<p>firbase에서 필터기능을 제공해주기 때문에 위와 같이 쓸 수 있다</p>
<hr>
<p>#447 useCallback</p>
<pre><code class="language-javascript">  const filteredIngredientsHandler = useCallback((filteredIngredients) =&gt; {
    setUserIngredients(filteredIngredients);
  }, []);</code></pre>
<p>캐싱되어 다시 렌더링이 되더라도 값이 남아있도록 해준다</p>
<p><a href="https://github.com/facebook/react/issues/10231#issuecomment-316644950">https://github.com/facebook/react/issues/10231#issuecomment-316644950</a></p>
<p>console.log(name); // prints name state, e.g. &#39;Manu&#39;
setName(&#39;Max&#39;);
console.log(name); // ??? what gets printed? &#39;Max&#39;?
name 상태에 setName(&#39;Max&#39;);  다음에 엑세스하면 새로운 값(예: &#39;Max&#39;) 이 나올것 같지만 사실 그렇지 않습니다. 명심하세요. 새 상태 값은 다음 구성 요소 렌더링 주기에서만 사용할 수 있습니다. (setName() 호출 시 스케줄됨).</p>
<hr>
<p>reducer -&gt; 여러개의 입력을 받아 하나의 결과를 반환하는 함수
useReducer -&gt; 어떤 식으로 상태를 변경할 건지 정의할 수 있게 해준다</p>
]]></description>
        </item>
    </channel>
</rss>