<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>May the code be with you</title>
    <link>https://fe-kwangmin.tistory.com/</link>
    <description>Javascript ,Typescript and React</description>
    <language>ko</language>
    <pubDate>Mon, 6 Apr 2026 08:07:25 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>code walker</managingEditor>
    <image>
      <title>May the code be with you</title>
      <url>https://tistory1.daumcdn.net/tistory/5404465/attach/5827077bbc934e8f8cbcacef1b3ed814</url>
      <link>https://fe-kwangmin.tistory.com</link>
    </image>
    <item>
      <title>[Typescript] Typescript Infer / 조건부 타입(Conditional Types)</title>
      <link>https://fe-kwangmin.tistory.com/61</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;infer keyword 란?&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;infer&amp;nbsp;키워드는&amp;nbsp;TypeScript에서&amp;nbsp;조건부&amp;nbsp;타입(Conditional&amp;nbsp;Types)과&amp;nbsp;함께&amp;nbsp;사용되어&amp;nbsp;특정&amp;nbsp;타입의&amp;nbsp;정보를&amp;nbsp;추론할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;주로 타입의 일부를 추출하거나 변환하는 데 유용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;infer 키워드를 사용하면 타입을 변수처럼 선언하고 조건부 타입 내에서 이를 활용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;infer&amp;nbsp;키워드를&amp;nbsp;사용하는&amp;nbsp;것이&amp;nbsp;유리한&amp;nbsp;상황은&amp;nbsp;주로&amp;nbsp;복잡한&amp;nbsp;타입을&amp;nbsp;다룰&amp;nbsp;때입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;infer는 타입 시스템을 보다 강력하고 유연하게 만들어 주며, 타입 추론을 자동화함으로써 코드의 유지보수성을 높여줍니다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;infer 키워드는 조건부 타입 내부에서만 사용할 수 있습니다.&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;컨디셔널 타입의 참 부분에만 infer된 타입 변수를 사용할 수 있다. 거짓 부분에서 쓰려고 하면 에러가 발생합니다.&lt;br /&gt;왜 그런지는 생각해 보면 당연합니다. &lt;br /&gt;infer를 통해서 추론할 수 있다면 참으로, 없다면 거짓으로 가게 되는데 infer를 통해서 타입을 추론할 수 없다면 해당 타입을 결정할 수 없다. 따라서 infer를 통해서 타입을 결정할 수 있는 참 부분에서만 infer를 통해 만들어진 타입 변수를 사용할 수 있는 것입니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1. 간단한 infer 예시&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1719152585630&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type Unpack&amp;lt;T&amp;gt; = T extends (infer U)[] ? U : T;

// string[] 타입의 요소를 추출
type Test1 = Unpack&amp;lt;string[]&amp;gt;; // string

// 그냥 타입을 반환
type Test2 = Unpack&amp;lt;number&amp;gt;; // number&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;위&amp;nbsp;코드에서&amp;nbsp;Unpack&amp;nbsp;타입은&amp;nbsp;제네릭&amp;nbsp;타입&amp;nbsp;T를&amp;nbsp;인수로&amp;nbsp;받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;nbsp;T가&amp;nbsp;배열&amp;nbsp;타입인지&amp;nbsp;확인하고,&amp;nbsp;배열이라면&amp;nbsp;요소&amp;nbsp;타입(U)을&amp;nbsp;추출합니다.&amp;nbsp;그렇지&amp;nbsp;않다면&amp;nbsp;T&amp;nbsp;자체를&amp;nbsp;반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. Function return Type 추출&lt;/span&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1719152639651&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type ReturnType&amp;lt;T&amp;gt; = T extends (...args: any[]) =&amp;gt; infer R ? R : any;

// 함수 타입에서 반환 타입 추출
type Test3 = ReturnType&amp;lt;() =&amp;gt; string&amp;gt;; // string

type Test4 = ReturnType&amp;lt;(x: number) =&amp;gt; boolean&amp;gt;; // boolean&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이&amp;nbsp;예제에서&amp;nbsp;ReturnType&amp;nbsp;타입은&amp;nbsp;함수&amp;nbsp;타입&amp;nbsp;T의&amp;nbsp;반환&amp;nbsp;타입&amp;nbsp;R을&amp;nbsp;추출합니다.&amp;nbsp;T가&amp;nbsp;함수&amp;nbsp;타입이&amp;nbsp;아닌&amp;nbsp;경우,&amp;nbsp;기본적으로&amp;nbsp;any&amp;nbsp;타입을&amp;nbsp;반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;3. Promise 내부 Type 추출&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1719152768067&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type Awaited&amp;lt;T&amp;gt; = T extends Promise&amp;lt;infer U&amp;gt; ? U : T;

// 프로미스 타입에서 내부 타입 추출
type Test5 = Awaited&amp;lt;Promise&amp;lt;string&amp;gt;&amp;gt;; // string

type Test6 = Awaited&amp;lt;number&amp;gt;; // number&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;여기서는&amp;nbsp;Awaited&amp;nbsp;타입이&amp;nbsp;Promise&amp;nbsp;타입의&amp;nbsp;내부&amp;nbsp;값을&amp;nbsp;추출합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;T가 Promise 타입이라면 내부 타입 U를 반환하고, 그렇지 않다면 T를 그대로 반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4. 외부 라이브러리에 types를 제공 안해주는 경우 (타입 추출 )&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1719153430754&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function getProfileO(person:{
    name:string;
    age:number;
    hobbies:[string, string];
}){
    return `${person.name}은 ${person.age}살이고 ${person.hobbies.join(&quot; 와 &quot;)}가 취미입니다.`
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1719154022689&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const me={
    name:&quot;남광민&quot;,
    age:30,
    hobbies:[&quot;JS&quot;, &quot;TS&quot;],
}
// me.hobbies의 타입이 string[]으로 추론되어 타입 에러 발생
getProfile(me);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 me.hobbies의 타입이 string[]으로 추론되어 타입 에러 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719153986477&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type GetFirstArgumentType&amp;lt;T&amp;gt; = T extends (arg: infer U, ...args:any) =&amp;gt; any ? U : never;

const me:GetFirstArgumentType&amp;lt;typeof getProfile&amp;gt;={
    name:&quot;남광민&quot;,
    age:30,
    hobbies:[&quot;JS&quot;, &quot;TS&quot;],
}

getProfile(me);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그냥 Person 타입을 새로 정의해 주는 방법도 있겠지만 서드파티 라이브러리의 코드를 다 파악해서 타입을 새로 정의하는 것은 쉽지 않습니다. 이런 경우 infer를 사용한 GetFirstArgumentType&amp;lt;T&amp;gt;와 같은 타입으로 쉽게 함수 인자 타입을 추론해 줄 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마치며&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;infer 타입은 사실 TS를 하면서 자주 마주할 일은 없는 타입 입니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;자주 사용한다면 오히려 뭔가 코드가 이상해지고 있다는 이야기일지도 모릅니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;하지만 외부 함수를 사용할 때 함수의 인자나 리턴 타입 추론, 재귀적인 타입 추론 등 다른 타입에서 어떤 일부 타입을 뽑아서 사용해야 할 때 매우 유용하게 사용할 수 있습니다. 이런 활용법을 알아두면 나중에 유용하게 쓸 수 있을 것입니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>front-end/Javascript&amp;amp;Typescript</category>
      <category>infer</category>
      <category>JavaScript</category>
      <category>React</category>
      <category>TS</category>
      <category>TypeScript</category>
      <category>타입스크립트</category>
      <author>code walker</author>
      <guid isPermaLink="true">https://fe-kwangmin.tistory.com/61</guid>
      <comments>https://fe-kwangmin.tistory.com/61#entry61comment</comments>
      <pubDate>Sun, 23 Jun 2024 23:49:53 +0900</pubDate>
    </item>
    <item>
      <title>[React] 이제는 써야한다.Suspense , ErrorBoundary  feat:(Apollo Clients)</title>
      <link>https://fe-kwangmin.tistory.com/60</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;현재 회사에서 맡고있는 프로덕트는 어드민 페이지를 관리 하고있는데, 어드민의 UI/UX가 대부분 filtering 하는 검색박스와, 이를 결과로 보여주는 AgGrid 라는 라이브러리의 table을 사용하고있습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;추가로 GraphQL을 사용하기에 , Apollo-client를 사용하고 , Gql query 통해 error , loading&amp;nbsp; 그리고 data state를 관리하고 있습니다. 위에 말했다시피 data를 &lt;b&gt;AgGrid &lt;/b&gt;table로 그리는 페이지가 대다수였기에, Aggrid table 컴포넌트에서 제공하는 error, loading props를 넘겨주면 각 상황에 맞는 UI가 유저에게 그려지고 있습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;하지만 어느 프로젝트나 시간이 지나면 그렇듯 프로덕트의 범위가 커지고, 어드민의 페이지가 늘어나고 기획 및 디자인 범위가 늘어날수록, 단순히 table만 그리는게 아닌 새로운 컴포넌트도 많이 도입이 되고 있었습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;국내 및 해외 빅테크의 비동기 통신처리를 리액트에서 어떻게 하는지 유튜브나 블로그 포스팅글을 자주 보곤했는데, React 18의 Suspense 그리고 ErrorBoundary를 통해 비동기 통신 하는것을 추천 하는 글을 많이 보고 Suspense의 매력을 알아채고 기회가 되면 회사 프로젝트에 사용을 해봐야지 라는 생각을 갖고 있었습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;자 그럼 우선 Suspense가 비동기 통신에 어떤 이점이 있고 , React 16 , 17 version 의 Suspense과 18 version 의 Suspense의 차이를 알아보고, Apollo에서 제공하는 useSuspenseQuery와 어떻게 사용하는지 작성해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1. Why Suspense ?&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;React의 Suspense는 컴포넌트의 로딩 상태를 React 자체에서 처리할 수 있게 해주는 기능입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이로 인해 데이터를 불러오는 비동기 로직을 쉽게 관리할 수 있으며, 이는 컴포넌트의 로딩 상태나 오류 상태를 처리하는 새로운 패턴을 제공합니다. Suspense는 React 16.6에서 처음 도입되었고, React 18에서는 Suspense 기능이 확장되어 더 많은 유형의 비동기 작업을 처리할 수 있게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Suspense의 장점&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 코드 분할을 쉽게 관리: Suspense를 사용하면 코드 분할(Code-Splitting)과 같은 비동기 작업을 쉽게 처리할 수 있습니다. 이는 애플리케이션의 로딩 시간을 줄이고 성능을 향상시킵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2.일관된 로딩 상태 처리: Suspense는 로딩 인디케이터 같은 UI를 쉽게 통합할 수 있게 해줍니다. 이를 통해 비동기 로딩 상태를 일관되게 관리할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3.컴포넌트 추상화: 데이터 로딩 로직을 컴포넌트 외부로 분리함으로써 컴포넌트를 더 깨끗하고 관리하기 쉽게 만들 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4. 동시성 모드(Concurrent Mode)와의 통합: React 18에서는 Suspense가 Concurrent Mode와 결합하여, 여러 비동기 작업을 동시에 처리하면서도 사용자 인터페이스를 즉시 반응하게 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2. React 16~17 의 Suspense와 React 18 Suspense&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;React 16, 17 의 Suspense&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주로 코드 분할을 위한 것으로 사용되었습니다. 컴포넌트가 로딩 중일 때 다른 컴포넌트로 대체하는 방식으로 작동했습니다. 주로 React.lazy와 import()를 사용하여 동적으로 컴포넌트를 로드하는 데 사용되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Suspense의 핵심은 Promise를 throw 하는 것입니다 . Promise가 resolve(성공) 하거나 reject(실패) 할 때까지 컴포넌트 트리의 실행을 연기 시킵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컴포넌트 트리의 실행이 연기되는 동안 컴포넌트 트리는 UI에서 숨겨집니다. DOM 트리에서 삭제되는 것이 아니라 해당 컴포넌트에 display: none 스타일을 추가하는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;React 16,17 에서의 Suspense 사용 예제&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;code&gt;const OtherComponent = React.lazy(() =&amp;gt; import('./OtherComponent'));

function MyComponent() {
  return (
    // Displays &amp;lt;Spinner&amp;gt; until OtherComponent loads
    &amp;lt;React.Suspense fallback={&amp;lt;Spinner /&amp;gt;}&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;OtherComponent /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/React.Suspense&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;React 18 &lt;b&gt;의 Suspense&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컴포넌트 트리의 실행이 연기되는 동안 해당 컴포넌트는 DOM 트리에 존재하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실행이 완료되지 않는 컴포넌트는 커밋 되지 않아, 따라서 컴포넌트가 완료되고 DOM 트리에 배치되며 브라우저 화면에 업데이트되기 때문에 라이프사이클 이벤트가 불일치하는 일이 발생하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;Suspense는 데이터 로딩을 포함한 더 광범위한 비동기 작업을 지원합니다. 동시성 모드와의 통합을 통해 더 부드러운 사용자 경험을 제공합니다. Suspense는 이제 렌더링을 &quot;중단&quot;할 수 있으며, React는 우선순위에 따라 다른 작업으로 전환할 수 있습니다. 새로운 데이터 가져오기 라이브러리와의 통합을 위한 API가 도입되었습니다. 이를 통해 컴포넌트가 데이터를 필요로 할 때까지 데이터 로딩을 지연시킬 수 있으며, 이는 서버 사이드 렌더링(SSR)에서도 유용하게 사용될 수 있습니다. 더 나은 에러 핸들링을 제공하며, Suspense boundary 내에서 발생하는 오류를 쉽게 관리할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기존&amp;nbsp;SSR&amp;nbsp;방식&amp;nbsp;문제점&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;1.&amp;nbsp;HTML을&amp;nbsp;렌더링&amp;nbsp;하기&amp;nbsp;전에&amp;nbsp;app에&amp;nbsp;필요한&amp;nbsp;모든&amp;nbsp;데이터를&amp;nbsp;가져와야한다.&amp;nbsp;서버에서&amp;nbsp;HTML&amp;nbsp;렌더링을&amp;nbsp;시작하려면&amp;nbsp;모든&amp;nbsp;데이터가&amp;nbsp;준비되어&amp;nbsp;있어야&amp;nbsp;한다.&amp;nbsp;즉,&amp;nbsp;데이터가&amp;nbsp;수집되지&amp;nbsp;않으면&amp;nbsp;HTML&amp;nbsp;렌더링을&amp;nbsp;시작하지&amp;nbsp;못해&amp;nbsp;클라이언트에&amp;nbsp;어떠한&amp;nbsp;HTML로&amp;nbsp;전송할&amp;nbsp;수&amp;nbsp;없다는&amp;nbsp;것을&amp;nbsp;의미한다.&amp;nbsp;만약&amp;nbsp;초기&amp;nbsp;화면&amp;nbsp;일부에&amp;nbsp;필요한&amp;nbsp;데이터가&amp;nbsp;준비되는&amp;nbsp;시간이&amp;nbsp;늦어지면&amp;nbsp;초기&amp;nbsp;화면의&amp;nbsp;나머지&amp;nbsp;HTML&amp;nbsp;렌더링도&amp;nbsp;늦어지며&amp;nbsp;전송도&amp;nbsp;지연된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;&amp;nbsp;2.&amp;nbsp;hydrate를&amp;nbsp;시작하기&amp;nbsp;전에&amp;nbsp;필요한&amp;nbsp;모든&amp;nbsp;JavaScript&amp;nbsp;코드가&amp;nbsp;로드되어야&amp;nbsp;한다.&amp;nbsp;서버에서&amp;nbsp;렌더링된&amp;nbsp;HTML이&amp;nbsp;전달되면&amp;nbsp;정적인&amp;nbsp;HTML을&amp;nbsp;상호작용&amp;nbsp;가능하게&amp;nbsp;하기&amp;nbsp;위해&amp;nbsp;이벤트&amp;nbsp;핸들러를&amp;nbsp;연결해야&amp;nbsp;한다.&amp;nbsp;이때&amp;nbsp;브라우저&amp;nbsp;컴포넌트에&amp;nbsp;의해&amp;nbsp;생성된&amp;nbsp;컴포넌트&amp;nbsp;트리가&amp;nbsp;서버에서&amp;nbsp;생성된&amp;nbsp;트리와&amp;nbsp;일치해야&amp;nbsp;한다.&amp;nbsp;일치하지&amp;nbsp;않는다면&amp;nbsp;React는&amp;nbsp;HTML과&amp;nbsp;JavaScript&amp;nbsp;코드를&amp;nbsp;매치할&amp;nbsp;수&amp;nbsp;없다.&amp;nbsp;이&amp;nbsp;때문에&amp;nbsp;hydrate를&amp;nbsp;진행하기&amp;nbsp;전&amp;nbsp;모든&amp;nbsp;JavaScript를&amp;nbsp;로드해야&amp;nbsp;하는&amp;nbsp;것이다.&amp;nbsp;화면의&amp;nbsp;일부분(컴포넌트)에&amp;nbsp;상호작용할&amp;nbsp;로직이&amp;nbsp;많이&amp;nbsp;존재할&amp;nbsp;때,&amp;nbsp;이에&amp;nbsp;따른&amp;nbsp;JavaScript&amp;nbsp;로직을&amp;nbsp;다운로드하는데&amp;nbsp;시간이&amp;nbsp;많이&amp;nbsp;걸릴&amp;nbsp;경우&amp;nbsp;비교적&amp;nbsp;상호작용&amp;nbsp;로직이&amp;nbsp;적은&amp;nbsp;화면(컴포넌트)&amp;nbsp;HTML에도&amp;nbsp;hydrate를&amp;nbsp;시작할&amp;nbsp;수&amp;nbsp;없다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;3.&amp;nbsp;상호작용을&amp;nbsp;시작하기&amp;nbsp;전,&amp;nbsp;모든&amp;nbsp;HTML에&amp;nbsp;hydrate가&amp;nbsp;완료되어야&amp;nbsp;한다.&amp;nbsp;hydrate가&amp;nbsp;시작되면&amp;nbsp;React는&amp;nbsp;hydrate가&amp;nbsp;완료될&amp;nbsp;때까지&amp;nbsp;멈출&amp;nbsp;수&amp;nbsp;없으며&amp;nbsp;다른&amp;nbsp;작업을&amp;nbsp;할&amp;nbsp;수&amp;nbsp;없다.&amp;nbsp;즉,&amp;nbsp;화면&amp;nbsp;일부에&amp;nbsp;필요한&amp;nbsp;코드&amp;nbsp;다운로드가&amp;nbsp;느리다면&amp;nbsp;navigation&amp;nbsp;바&amp;nbsp;또는&amp;nbsp;사이드&amp;nbsp;바와&amp;nbsp;같은&amp;nbsp;부분도&amp;nbsp;hydrate가&amp;nbsp;되지&amp;nbsp;않아&amp;nbsp;해당&amp;nbsp;페이지에서&amp;nbsp;벗어나거나&amp;nbsp;다른&amp;nbsp;컨텐츠와&amp;nbsp;상호작용할&amp;nbsp;수&amp;nbsp;없다.&amp;nbsp;만약&amp;nbsp;느린&amp;nbsp;네트워크를&amp;nbsp;사용하는&amp;nbsp;사용자가&amp;nbsp;있다면&amp;nbsp;그&amp;nbsp;사용자는&amp;nbsp;HTML만&amp;nbsp;보고&amp;nbsp;있을&amp;nbsp;뿐&amp;nbsp;어떠한&amp;nbsp;작업도&amp;nbsp;할&amp;nbsp;수&amp;nbsp;없다는&amp;nbsp;것을&amp;nbsp;의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;3. Apollo client (useSuspenseQuery)와 함께 쓰는법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 실제프로젝트에서 어떻게 Apollo와 어떻게 사용했는지 작성해보려 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로젝트내 아폴로 버전이 3.7 이였습니다. 공식문서상 리액트의 Suspense 기능을 사용하려면 기존에 자주 사용하던 useQuery , useLazyQuery가 아닌 useSuspenseQuery를 사용해야하는데 , 3.8 버전부터 사용이 가능하여 package 업그레이드를 우선 진행했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우선 Apollo 공식문서 예제 코드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711212570132&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Suspense } from 'react';
import {
  gql,
  TypedDocumentNode,
  useSuspenseQuery
} from '@apollo/client';

interface Data {
  dog: {
    id: string;
    name: string;
  };
}

interface Variables {
  id: string;
}

interface DogProps {
  id: string
}

const GET_DOG_QUERY: TypedDocumentNode&amp;lt;Data, Variables&amp;gt; = gql`
  query GetDog($id: String) {
    dog(id: $id) {
      # By default, an object's cache key is a combination of
      # its __typename and id fields, so we should always make
      # sure the id is in the response so our data can be
      # properly cached.
      id
      name
      breed
    }
  }
`;

function App() {
  return (
    &amp;lt;Suspense fallback={&amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}&amp;gt;
      &amp;lt;Dog id=&quot;3&quot; /&amp;gt;
    &amp;lt;/Suspense&amp;gt;
  );
}

function Dog({ id }: DogProps) {
  const { data } = useSuspenseQuery(GET_DOG_QUERY, {
    variables: { id },
  });

  return &amp;lt;&amp;gt;Name: {data.dog.name}&amp;lt;/&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위 코드예시를 보면 useQuery나 useLazyQuery에서 제공하는 boolean 타입의 loading state는 useSuspenseQuery 에서 반환하지 않습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;useSuspenseQuery를 호출하는 컴포넌트가 데이터를 가져올 때 항상 suspends 상태가 되기 때문입니다. 이에 대한 함의는 렌더링될 때, 데이터가 항상 정의되어 있다는 것입니다! Suspense 패러다임에서는, 기존에 컴포넌트가 스스로 렌더링해야 했던 로딩 상태를 대체하는 fallback 들이 대기 중인 컴포넌트의 바깥에 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;useSuspenseQuery hook 은 네트워크 요청을 시작하고 요청이 진행되는 동안 호출한 컴포넌트를 대기 상태로 만듭니다. 이를 사용하는 동안 렌더링하는 동안 React의 Suspense 기능을 활용할 수 있게 해주는 useQuery의 Suspense 준비된 대체재로 생각할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;ErrorBoundary와 함께 사용하는법&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1711213212896&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback;
    }

    return this.props.children;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711213225791&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function App() {
  const { data } = useSuspenseQuery(GET_DOGS_QUERY);
  const [selectedDog, setSelectedDog] = useState(
    data.dogs[0].id
  );

  return (
    &amp;lt;&amp;gt;
      &amp;lt;select
        onChange={(e) =&amp;gt; setSelectedDog(e.target.value)}
      &amp;gt;
        {data.dogs.map(({ id, name }) =&amp;gt; (
          &amp;lt;option key={id} value={id}&amp;gt;
            {name}
          &amp;lt;/option&amp;gt;
        ))}
      &amp;lt;/select&amp;gt;
      &amp;lt;ErrorBoundary
        fallback={&amp;lt;div&amp;gt;Something went wrong&amp;lt;/div&amp;gt;}
      &amp;gt;
        &amp;lt;Suspense fallback={&amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}&amp;gt;
          &amp;lt;Dog id={selectedDog} /&amp;gt;
        &amp;lt;/Suspense&amp;gt;
      &amp;lt;/ErrorBoundary&amp;gt;
    &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서, 우리는 ErrorBoundary 컴포넌트를 사용하고 Dog 컴포넌트의 바깥에 배치합니다. 이제, Dog 컴포넌트 내부의 useSuspenseQuery 훅이 에러를 던질 때, ErrorBoundary가 이를 잡아내고 우리가 제공한  fallback 요소를 표시합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useSuspenseQuery는 데이터를 가져오는 동안 대기 상태가 되기 때문에, useSuspenseQuery를 사용하는 컴포넌트 트리는 각각의 useSuspenseQuery 호출이 이전 호출이 완료될 때까지 시작할 수 없는 &quot; waterfall&quot;을 일으킬 수 있습니다. 이는 부모 컴포넌트에서 useBackgroundQuery로 데이터를 가져오고, 자식 컴포넌트에서 useReadQuery로 데이터를 읽음으로써 피할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도움 될만한글: Suspense 를 무분별하게 사용하고 있진 않는지?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://happysisyphe.tistory.com/54&quot;&gt;https://happysisyphe.tistory.com/54&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;</description>
      <category>front-end/React</category>
      <author>code walker</author>
      <guid isPermaLink="true">https://fe-kwangmin.tistory.com/60</guid>
      <comments>https://fe-kwangmin.tistory.com/60#entry60comment</comments>
      <pubDate>Wed, 20 Mar 2024 23:32:54 +0900</pubDate>
    </item>
    <item>
      <title>[Typescript] Typescript satisfies</title>
      <link>https://fe-kwangmin.tistory.com/57</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2년전, 타입스크립트를 처음에 접할땐 interface , type 키워드만알아도 거의 개발하는데 무방했지만, 실무에서 타입스크립트와 리액트로&lt;br /&gt;개발하다보면 TS의 Util을 활용을 하면 훨씬 더 편하고, 확장성 좋은 강력한 type safe 기능을 발휘 할 수 있습니다.&lt;br /&gt;그래서 작년에 TS의 Util 관련하여 블로그 포스팅한게 있습니다. 지금도 헷갈리거나 기억이 안날때 가끔 제가 쓴&lt;br /&gt;블로그 보면서 참고하는데요.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이번엔 타입스크립트의 &quot;satisfies&quot; 키워드를 포스팅 해보겠습니다.&lt;br /&gt;TS를 극한으로 쓰시는분들이 아니면 이 키워드는 생소(?) 할것같은데요. (저는 그랬습니다.)&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;satisfies 키워드가 무엇이고 언제 쓰이면 유용할까요?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 개인적으로 저는 타입스크립트의 Type safe역할도 그렇지만, 미리 Interface 나 type을 작성하고 타입 지정을 해주면 제가 작성해놓은 type에 맞게끔 자동완성 기능을 정말 애용하는 편입니다.&lt;br /&gt;그리고 또한 그 타입의 맞는 method 또한 자동으로 완성되죠. 아래의 예시를 보면서 satisfies를 적용하고나서와 하기전을 비교해보겠습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;TypeScript의 satisfies 키워드는 TypeScript 4.9에서 도입된 새로운 기능으로, 주로 타입 체크를 강화하고 코드의 의도를 명확히 하기 위해 사용됩니다. 이 키워드는 특정 변수가 특정 타입을 '만족(satisfy)'하는지를 확인하는 데 사용됩니다. 기본개념 variable satisfies Type 구문을 사용하면, variable이 Type의 모든 요구 사항을 충족하는지 확인할 수 있습니다. 이는 주로 다음 두 가지 상황에서 유용합니다:&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;1. 타입 가드: 변수가 특정 타입을 만족하는지를 런타임에 확인합니다.&lt;br /&gt;2. 타입 정제: 특정 조건에서 변수의 타입을 더 구체적인 서브타입으로 좁혀 나갑니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Example.1 &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;atisfies 적용전&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;type ProfileType = {
&amp;nbsp;&amp;nbsp;name:string;
&amp;nbsp;&amp;nbsp;age:string | number;
}

const profile:ProfileType = {
&amp;nbsp;&amp;nbsp;name:'kwangmin',
&amp;nbsp;&amp;nbsp;age:30
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;위 예시는 전혀 문제가없습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;age 쪽을 보면 string과 number 유니온 타입을 받는데요. 아래의 이미지를 보면 profile의 name은 string의 하나의 타입을 가집니다.&lt;br /&gt;그래서 profile 객체의 name의 키값에 접근할때는 string method를 자동완성으로 보여주고있습니다.&lt;br /&gt;하지만 유니온 타입은 age의 접근할때는 number의 method를 제대로 불러오질 못하고있습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;반대로 age를 string의 값인 &quot;30&quot;으로 바꾼다고 해도 똑같이 method 자동완성을 제대로 못하고있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1166&quot; data-origin-height=&quot;946&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbS6Ca/btsDrG4qTE6/kzkUVV14DINUlcVaNyCvQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbS6Ca/btsDrG4qTE6/kzkUVV14DINUlcVaNyCvQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbS6Ca/btsDrG4qTE6/kzkUVV14DINUlcVaNyCvQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbS6Ca%2FbtsDrG4qTE6%2FkzkUVV14DINUlcVaNyCvQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;617&quot; height=&quot;501&quot; data-origin-width=&quot;1166&quot; data-origin-height=&quot;946&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Or4DS/btsDxkswCsg/rrScsdY4IKktgqWSFLTfU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Or4DS/btsDxkswCsg/rrScsdY4IKktgqWSFLTfU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Or4DS/btsDxkswCsg/rrScsdY4IKktgqWSFLTfU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOr4DS%2FbtsDxkswCsg%2FrrScsdY4IKktgqWSFLTfU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;614&quot; height=&quot;356&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Example.1&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;satisfies 적용후&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;type ProfileType = {
&amp;nbsp;&amp;nbsp;name:string;
&amp;nbsp;&amp;nbsp;age:string | number;
}

const profile = {
&amp;nbsp;&amp;nbsp;name:'kwangmin',
&amp;nbsp;&amp;nbsp;age:30
} satisfies ProfileType&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;798&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFkn1T/btsDrIaaRtK/vzoIuEkzRIdowwmGmszB00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFkn1T/btsDrIaaRtK/vzoIuEkzRIdowwmGmszB00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFkn1T/btsDrIaaRtK/vzoIuEkzRIdowwmGmszB00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFkn1T%2FbtsDrIaaRtK%2FvzoIuEkzRIdowwmGmszB00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;641&quot; height=&quot;451&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;798&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;satisfies 키워드를 선언하면 사용하는 타입의 따라 모든 메소드를 자동완성 해주고있습니다. 간단하죠?&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Example 2.&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const profile:Record&amp;lt;string,number&amp;gt; = {};

profile.any = 10;
profile.any2 = 20;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;scores의 객체의 키값이 string인 와이드한 타입이기때문에 선언이 되어있지도 않는 any, any2의 접근을 해도 타입에러를 내뱉지 않습니다. 만약 객체의 키값도 자동완성 기능과 타입 체크를 원한다면 여기서도 satisfies를 사용 할 수 있습니다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;사실 satisfies 를 사용 하지않고도 아래처럼 키값을 정해줄 수 도있습니다. 이런식으로 해도 타입가드 역할을 할 수있습니다.&lt;br /&gt;오히려 아래는 키 name값을 직접 미리 타입으로 선언해줄수있어서 아래의 방법도 괜찮습니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;type Key = 'name' | 'age'

const profile:Record&amp;lt;Key,number&amp;gt; = {};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;profile2의 키값 자동완성은 완성될수없습니다. 왜냐하면 키값을 그저 string의 타입을 갖고오기때문이죠.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1748&quot; data-origin-height=&quot;730&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbyZGR/btsDuwtxmMV/jyI6ZXNu5RTTzK7RSdfO7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbyZGR/btsDuwtxmMV/jyI6ZXNu5RTTzK7RSdfO7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbyZGR/btsDuwtxmMV/jyI6ZXNu5RTTzK7RSdfO7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbyZGR%2FbtsDuwtxmMV%2FjyI6ZXNu5RTTzK7RSdfO7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1748&quot; height=&quot;730&quot; data-origin-width=&quot;1748&quot; data-origin-height=&quot;730&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;as 와 satisfies 차이&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;as&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;as 키워드 as 키워드는 타입 단언(type assertion)에 사용됩니다. 이는 개발자가 TypeScript 컴파일러에게 &quot;이 변수를 내가 지정한 타입으로 처리해 달라&quot;고 요청하는 것과 같습니다. 컴파일러는 이 단언을 신뢰하고 해당 타입에 맞게 코드를 처리합니다. 하지만 실제 런타임에서 변수의 타입이 단언한 타입과 다를 경우에도 TypeScript는 이를 감지하지 못하고, 오류가 발생할 수 있습니다. 즉, as 키워드는 컴파일 시간에만 영향을 미치며 런타임 타입 검사는 하지 않습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;satisfies&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;반면,&amp;nbsp;satisfies&amp;nbsp;키워드는&amp;nbsp;주로&amp;nbsp;개발&amp;nbsp;중&amp;nbsp;타입의&amp;nbsp;호환성을&amp;nbsp;검사하기&amp;nbsp;위해&amp;nbsp;사용됩니다.&amp;nbsp;satisfies는&amp;nbsp;변수가&amp;nbsp;특정&amp;nbsp;타입을&amp;nbsp;&quot;만족하는지(satisfies)&quot;&amp;nbsp;검사하고,&amp;nbsp;만족하지&amp;nbsp;않으면&amp;nbsp;컴파일&amp;nbsp;시점에&amp;nbsp;오류를&amp;nbsp;발생시킵니다.&amp;nbsp;이는&amp;nbsp;타입&amp;nbsp;안정성을&amp;nbsp;강화하고,&amp;nbsp;코드가&amp;nbsp;명시된&amp;nbsp;타입&amp;nbsp;계약을&amp;nbsp;정확히&amp;nbsp;준수하도록&amp;nbsp;보장합니다.&amp;nbsp;satisfies는&amp;nbsp;타입&amp;nbsp;단언과&amp;nbsp;달리&amp;nbsp;런타임에&amp;nbsp;영향을&amp;nbsp;미치지&amp;nbsp;않으며,&amp;nbsp;주로&amp;nbsp;타입&amp;nbsp;검사와&amp;nbsp;문서화에&amp;nbsp;유용합니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;타입&amp;nbsp;검증&amp;nbsp;vs.&amp;nbsp;타입&amp;nbsp;단언&lt;/b&gt;:&amp;nbsp;as는&amp;nbsp;타입&amp;nbsp;단언으로,&amp;nbsp;개발자가&amp;nbsp;컴파일러에게&amp;nbsp;타입을&amp;nbsp;강제로&amp;nbsp;지정하게&amp;nbsp;합니다.&amp;nbsp;반면,&amp;nbsp;satisfies는&amp;nbsp;타입이&amp;nbsp;특정&amp;nbsp;조건을&amp;nbsp;만족하는지&amp;nbsp;검증합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;안전성&lt;/b&gt;: satisfies는 타입 불일치 시 컴파일 오류를 발생시켜, 코드의 타입 안전성을 높입니다. as는 런타임 오류를 유발할 수 있는 위험을 갖고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;용도&lt;/b&gt;: as는 주로 타입 정보가 부족한 상황에서 사용되며, satisfies는 타입 계약을 확인하고 문서화하는 데 유용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;satisfies를 사용함으로서 더욱 강력한 타입세이프 기능을 활용하고 더 편한 개발을 할 수 있을것같습니다!&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=r1L35zxZQPE&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;&lt;b&gt;https://www.youtube.com/watch?v=r1L35zxZQPE&lt;/b&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=r1L35zxZQPE&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/c6mJza/hyU5JuQlM7/vkBOWK6Kt5Pn0gZxyz8bK1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/r1L35zxZQPE&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>front-end/Javascript&amp;amp;Typescript</category>
      <author>code walker</author>
      <guid isPermaLink="true">https://fe-kwangmin.tistory.com/57</guid>
      <comments>https://fe-kwangmin.tistory.com/57#entry57comment</comments>
      <pubDate>Mon, 15 Jan 2024 22:45:07 +0900</pubDate>
    </item>
    <item>
      <title>코드 가독성에 대해 (feat: KISS, Boy scout rule)</title>
      <link>https://fe-kwangmin.tistory.com/56</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;코딩을할때 어떤 방법이 100% 옳다라는 정답은 없지만 코드의 가독성에 대해 생각하고 작성 한다면 추후에 같은 코드를 보면서 개발을할때 훨씬 수월하게 할 수 있다는 생각은 100% 맞는 말 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 포스팅은 사내 그룹스터디 할때 토픽이 되었던 주제인데, 좋은 글인거같아 정리삼아 포스팅을 하려고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;아래의 포스팅 전체의 내용을 다루는것보다, 사내 스터디를 할때 기억에 가장 남은것들만 우선 정리한 포스팅 입니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1. 코드의 가독성은 왜 높아야할까?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어떤 feautre을 개발한다고 칩시다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;저는 프론트엔드 개발자이니까 보통 기획과 디자인 그리고 백엔드 개발자에게 디자인 리뷰 , API interface등 리뷰를 받고 개발을 진행 한적이 많은데, 리뷰를 받고 feature 개발 하기까지의 2주라는 시간이 소요된다고 가정하에, 이 2주동안은 feature의 대한 이해, 왜 개발을 하는지? 어떤 기획의 의도가 있는지를 파악을 한 상태에서 개발을 할것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예를들어 변수명 및 함수명을 마감기한이란 압박때문에 5분 조차 고민 안하고 생각나는 대로 지었고, 어떻게 개발 완료를 해서 배포까지 완로 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 한달 후 , 다른 feature 개발 후 전에 개발하던것에서 에러가 터지거가, 추각개발건이 있다고 가정하에 변수명과 함수명을 대충 지었다는 이유로 전체적인 로직을 한번 쭉 훑어봐야하는 불상사가 생길 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또 다른 이슈는 제가 휴가를 가거나 Day off인날은 다른 개발자가 제 코드를 무슨 생각으로 짰는지 파악할때 변수명과 함수명을 잘 지었으면 코드 파악하는것이 훨씬 수월 했겠죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #616161; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;5분 생각해서 변수 명을 고민하거나 적절한 주석을 다는 것으로 다른 개발자(미래의 자기 자신도 포함)가 1시간 고민하는 일을 막을 수 있을지 모릅니다. 중요한 것은 단기적이고 개인적인 생산성이 아니라 상품의 라이프 사이클 기간에 걸친 팀 전체의 생산성입니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #616161; text-align: start;&quot;&gt;코드의 가독성을 높게 코드를 작성하는 방법론은 매우 많지만 아래의 간단한 예제를 통해서 변수명이 왜 중요한지 파악해보겠습니다.&lt;/span&gt;&lt;span style=&quot;color: #616161; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705236583039&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  function checkLegalDrinkingAge(age:number):boolean{
    if(age &amp;gt; 19){
      return true;
    }else {
      return false;
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사실 위의 코드예시는 함수명과 age라는 파라미터를 보고 &quot;19&quot; 라고 되어있는 부분이 어떤 값인지 유추 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 19를 변수로 따로 관리 해서 예를들어 &lt;b&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;const LEGAL_DRINKING_AGE = 19 &lt;/span&gt;&lt;/b&gt;라는 constant 로 따로 관리하면 어떤 의도로 19를 작성했는지, 또는 19가 어떤 의미인지 더 잘 파악 할 수 있겠네요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;코드의 가독성을 중시해야 할지 결정하는 기준은 코드를 읽고 해석하는 데 드는 시간과 코드를 작성하는 데 드는 시간을 비교하는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2. 프로그래밍 원칙&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;견고하고 가독성 높은 코드를 작성하기 위해서는 프로그래밍 원칙에 따르는 것이 유용한 경우가 많습니다. 본 장에서는 코드의 가독성을 고려할 때 특별히 중요한 것뿐만 아니라, 혹시 과도하게 적용해도 부작용이 별로 없는 프로그래밍 원칙 5개가 참고 포스팅에 있지만 저는 2개정도만 정리하려고합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2-1. The boy scout rule&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;The&amp;nbsp;Boy&amp;nbsp;Scout&amp;nbsp;Rule&amp;nbsp;이&amp;nbsp;원칙은&amp;nbsp;&quot;코드를&amp;nbsp;변경할&amp;nbsp;때마다&amp;nbsp;더&amp;nbsp;깔끔하게&amp;nbsp;만들어라&quot;라는&amp;nbsp;생각을&amp;nbsp;기반으로&amp;nbsp;합니다.&amp;nbsp;보이스카우트&amp;nbsp;운동의&amp;nbsp;창시자&amp;nbsp;Robert&amp;nbsp;Baden-Powell의&amp;nbsp;격언에서&amp;nbsp;영감을&amp;nbsp;받아&amp;nbsp;Robert&amp;nbsp;C.&amp;nbsp;Martin이&amp;nbsp;소프트웨어&amp;nbsp;개발에&amp;nbsp;적용한&amp;nbsp;원칙입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;구체적인&amp;nbsp;예시로,&amp;nbsp;코드를&amp;nbsp;수정하는&amp;nbsp;과정에서&amp;nbsp;변수명을&amp;nbsp;더&amp;nbsp;명확하게&amp;nbsp;변경하거나,&amp;nbsp;필요한&amp;nbsp;주석을&amp;nbsp;추가하고,&amp;nbsp;불필요한&amp;nbsp;코드를&amp;nbsp;제거하는&amp;nbsp;것이&amp;nbsp;포함됩니다.&amp;nbsp;이&amp;nbsp;원칙의&amp;nbsp;핵심은&amp;nbsp;코드를&amp;nbsp;만질&amp;nbsp;때마다&amp;nbsp;전반적인&amp;nbsp;코드베이스의&amp;nbsp;질을&amp;nbsp;향상시키려는&amp;nbsp;노력입니다.&amp;nbsp;예를&amp;nbsp;들어,&amp;nbsp;복잡한&amp;nbsp;switch&amp;nbsp;문에&amp;nbsp;새로운&amp;nbsp;케이스를&amp;nbsp;추가하는&amp;nbsp;대신,&amp;nbsp;전략&amp;nbsp;패턴(strategy&amp;nbsp;pattern)을&amp;nbsp;사용하여&amp;nbsp;리팩터링하는&amp;nbsp;것이&amp;nbsp;이&amp;nbsp;원칙을&amp;nbsp;따르는&amp;nbsp;좋은&amp;nbsp;예시가&amp;nbsp;될&amp;nbsp;수&amp;nbsp;있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2-2. KISS&amp;nbsp;(Keep&amp;nbsp;It&amp;nbsp;Simple&amp;nbsp;Stupid)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 원칙은 &quot;항상 간단하게 유지해라&quot;는 의미로, 복잡성을 최소화하고 단순성을 유지하는 것을 강조합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;원래는 군사 장비의 설계 원칙으로 사용되었으나, 소프트웨어 개발에도 적용됩니다. KISS 원칙은 특히 기능과 구현 방식을 단순하게 유지하는 것을 지향합니다. 복잡하고 고도로 추상화된 코드보다는 이해하기 쉽고, 유지 관리가 용이한 코드를 선호합니다. 이 원칙의 핵심은 목적과 수단의 구분입니다. 프로그래밍 기법과 패러다임, 설계 방법은 코드의 가독성과 견고함을 향상시키기 위한 수단이어야 하며, 그 자체가 목적이 되어서는 안 됩니다. 예를 들어, 리액티브 프로그래밍이나 다른 고급 기법을 단지 그것이 &quot;아름답다&quot;거나 &quot;일관성이 있다&quot;는 이유로 사용하는 것은 KISS 원칙에 어긋납니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 두 원칙은 모두 코드의 가독성과 유지 보수성을 높이는 데 중점을 두고 있으며, 좋은 소프트웨어 개발 관행의 일부로 널리 인정받고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;KISS의 간단한 예로 자바스크립트 삼항연산자로 예를 들겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705237495095&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const age = name === 'john' ? 20 : name === 'tom' ? 19 : name === 'zed' ? 30 : null;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이러한 삼항 연산자가 있다고 가정해보면, 이 정도 deps의 조건이면 그냥 if else문을 적나라하게 쓰는게 훨씬 가독성이 좋습니다..&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Simple Stupid 처럼요.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다른 개발자가 저 코드를 파악하려면 예를들어 10분 걸릴것을, 간단한 if else문으로 작성하면 3분도 안되는 시간에 파악 할테니까요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래 처럼 말이죠.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705237598827&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (name === 'john') {
    return 20;
} else if (name === 'tom') {
    return 19;
} else if (name === 'zed') {
    return 30;
} else {
	return null;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;저는 2년차때쯤엔 코딩테스트를 보다가 구현사항을 10줄이 넘게 코드 작성을 했었는데, 다른 분은 2줄이면 구현을 해버리는것을 본 뒤로&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2줄로 구현하는게 가독성이 좋고, 간결해서 구현사항에 더 유리할 줄 알았었습니다. 하지만 지금은 그게 좋지만은 아닌것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;특히 코딩테스트는 개인이보는거지만 실무에선 협업, 즉 다른 사람들과 항상 함께 같이 일을 하니까요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사내 컨벤션이 있다면 컨벤션에 최대한 따라주면서, 컨벤션이 잘못된거같거나,개선사항이 있으면 좋을것 같은것들은 항상 팀원들과 얘기하면서 코드 가독성을 개선하면서 개발을 해야 할것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;KISS reference&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://medium.com/@ksekwamote/keep-it-simple-stupid-how-it-applies-in-javascript-113b1c4e77a8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@ksekwamote/keep-it-simple-stupid-how-it-applies-in-javascript-113b1c4e77a8&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/best-practices-writing-javascript-code-dry-kiss-yagni-emmanuel/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.linkedin.com/pulse/best-practices-writing-javascript-code-dry-kiss-yagni-emmanuel/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt; 참고한 포스팅: &lt;a href=&quot;https://engineering.linecorp.com/ko/blog/code-readability-vol1&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://engineering.linecorp.com/ko/blog/code-readability-vol1&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>good tips for dev</category>
      <author>code walker</author>
      <guid isPermaLink="true">https://fe-kwangmin.tistory.com/56</guid>
      <comments>https://fe-kwangmin.tistory.com/56#entry56comment</comments>
      <pubDate>Sun, 14 Jan 2024 22:17:55 +0900</pubDate>
    </item>
    <item>
      <title>[React] useDebounce custom hook 으로 성능향상 해보기 (feat: Debounce)</title>
      <link>https://fe-kwangmin.tistory.com/55</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;Debounce 란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;짧은 시간내에 연속 된 함수 및 event 호출시, 호출 되는 모든 함수를 바로 처리하지않고 정해진 딜레이 이후에 한번만 처리 하는 패턴 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;Debounce는 왜 필요할까?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start; --darkreader-inline-color: #c8c3bc; font-family: 'Nanum Gothic';&quot; data-darkreader-inline-color=&quot;&quot;&gt;1. 네트워크 요청의 함수나 전반적인 성능을 향상 시키기 위해서 가장 많이 쓰입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start; --darkreader-inline-color: #c8c3bc; font-family: 'Nanum Gothic';&quot; data-darkreader-inline-color=&quot;&quot;&gt;2. 비용절약 측면에서도 &lt;span style=&quot;text-align: start;&quot;&gt;Debounce가 필요한데요, 예를들어&amp;nbsp; 어떠한 서비스앱이 유료 API가 사용되고있는데 , API의 호출 횟수의 따라 비용이 나간다면 debounce 를 사용하여 네트워크 요청의 횟수를 줄일 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;Use case&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;1. input의 입력과 동시에 네트워크 요청을 통해 검색 결과를 가져올때&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start; --darkreader-inline-color: #c8c3bc; font-family: 'Nanum Gothic';&quot; data-darkreader-inline-color=&quot;&quot;&gt;(유튜브에서 React와 Debounce 관련 설명 영상의 예시가 거의 위의 사용사례로 강의를 합니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;2. 스크롤 / 리사이즈 바탕으로 작업을 할때&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;3. 문서 편집 자동저장&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;간단한 예시를 통해 debounce의 필요성과 재사용성이 높게끔 &lt;span style=&quot;text-align: start;&quot;&gt;리액트 커스텀 훅으로 예제를 만들어보겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; --darkreader-inline-color: #c8c3bc; font-family: 'Nanum Gothic';&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;코드 예제&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1694528599414&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Main.jsx

import React, { useEffect, useState } from 'react';

export default function Main() {

  const [countries, setCountries] = useState([]);
  const [input, setInput] = useState(&quot;&quot;);

  const getCountries = async () =&amp;gt; {
    try {
      const countriesData = await fetch(`https://restcountries.com/v3.1/name/${input}`);
      const json = await countriesData.json();
      setCountries(json);
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() =&amp;gt; {
    if(input) getCountries();
  }, [input]);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input
        type=&quot;text&quot;
        value={input}
        onChange={(e) =&amp;gt; setInput(e.target.value)}
        placeholder='나라를 검색해보세요.'
      /&amp;gt;
      {countries?.length === 0
      	? &amp;lt;strong&amp;gt;나라가 없습니다.&amp;lt;/strong&amp;gt;
        : countries?.map((item)=&amp;gt;(
          &amp;lt;div key={item.common}&amp;gt;
          	{item.name.common}
          &amp;lt;/div&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; --darkreader-inline-color: #c8c3bc; font-family: 'Nanum Gothic';&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;코드 관련해서 간단하게 설명하자면,&amp;nbsp;&lt;a style=&quot;color: #333333; --darkreader-inline-color: #c8c3bc;&quot; href=&quot;https://restcountries.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;restcountries&lt;/span&gt;&lt;/a&gt; 에서 국가의 정보 관련된 API를 가져옵니다. 그리고 input의 value로 국가를 검색합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; --darkreader-inline-color: #c8c3bc; font-family: 'Nanum Gothic';&quot; data-darkreader-inline-color=&quot;&quot;&gt;더 쉽게 말해, input에 입력과 동시에 결과를 input의 입력값에 따라 검색 결과를 가져온다고 보면 될것같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;&lt;b&gt;Debounce 를 적용하기전의 모습&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;debounce를 적용하기전, 아래의 gif를 통해 검색창에 'korea'를 검색하는것과 'korea'를 검색했을때 네트워크 통신이 몇번이나 이뤄지는지 한번 보겠습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면-기록-2023-09-12-오후-11.42.31.gif&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;2234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzcMEO/btstRJhBcFA/36aOiN1jrByh8FxLJzFI80/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzcMEO/btstRJhBcFA/36aOiN1jrByh8FxLJzFI80/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzcMEO/btstRJhBcFA/36aOiN1jrByh8FxLJzFI80/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bzcMEO/btstRJhBcFA/36aOiN1jrByh8FxLJzFI80/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3456&quot; height=&quot;2234&quot; data-filename=&quot;화면-기록-2023-09-12-오후-11.42.31.gif&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;2234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; --darkreader-inline-color: #c8c3bc; font-family: 'Nanum Gothic';&quot; data-darkreader-inline-color=&quot;&quot;&gt;위 예제를 통해 확인해보면 'korea'의 한글자 마다 네트워크 요청을 보내고있는데요, 이런식으로 input의 값이 바뀔때마다 fetcher 함수를 호출 하고있습니다. 예제의 방법보다는, 유저가 검색창의 입력이 일어나고 fetcher 함수를 호출 하기 전까지 텀(딜레이)가 있다면 효율적인 함수 호출이 가능해집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; --darkreader-inline-color: #c8c3bc; font-family: 'Nanum Gothic';&quot; data-darkreader-inline-color=&quot;&quot;&gt;그래서 이런 부분을 보다 효율적으로 바꾸기 위해 debounce를 적용 하면 성능이 개선 될 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;&lt;b&gt;useDebounce Custom Hook 만들어보기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1694530772289&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// useDebounce.js

import { useEffect, useState } from &quot;react&quot;;

//delay 같은경우 보통 500ms 을 사용한다고 합니다.
function useDebounce(value, delay = 2000) {
  const [debounceVal , setDebounceVal] = useState(value);

  useEffect(()=&amp;gt;{
    const handler = setTimeout(()=&amp;gt;{
      setDebounceVal(value);
    },delay);
    return () =&amp;gt; {
      clearTimeout(handler);
    }
  },[value,delay])
  return debounceVal;
}

export default useDebounce;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;우선 리액트 네이밍 컨벤션&amp;nbsp; , hook 같은 경우 앞에 'use..~' 가 붙으니 useDebounce 라는 커스텀 훅 파일을 하나 생성을 해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;위의 코드를 간단하게 설명하자면, 두가지의 인자를 custom hook에 받습니다. 첫번째 인자는 value를 받는데 , 이전 Main.jsx 에서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;input state 값을 인자로 받습니다. 그리고 두번째는 setTimeOut의 delay의 값을 넣어주는데 , 기본값을 보통은 500ms로 지정하지만&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;저는 확실하게 debounce가 되는지를 위해 2000ms 으로 지정 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;useDebonce hook에 또 다른 state를 생성 하는데 전달받은 value의 인자값을 debounceVal의 state에 초기값 설정을 해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;그리고 마지막으로 useEffect로 전달받은 인자 value의 값이 업데이트 될때마다 setTimeOut의 함수가 호출이 되어, setDebounce를 통해 &lt;span style=&quot;text-align: start; --darkreader-inline-color: #c1bcb4;&quot; data-darkreader-inline-color=&quot;&quot;&gt;최신 &lt;b&gt;value(debounceVal)&lt;/b&gt;를 &lt;/span&gt;리턴 해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #e8e6e3; text-align: start; --darkreader-inline-color: #d8d4cf;&quot; data-ke-size=&quot;size23&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;&lt;b&gt;Debounce 를 적용하고나서의 모습&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면-기록-2023-09-13-오전-12.10.55.gif&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;2234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lf03s/btstH0rzWkO/M8qlSKYkQNcxqswq3GJJNK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lf03s/btstH0rzWkO/M8qlSKYkQNcxqswq3GJJNK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lf03s/btstH0rzWkO/M8qlSKYkQNcxqswq3GJJNK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/lf03s/btstH0rzWkO/M8qlSKYkQNcxqswq3GJJNK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3456&quot; height=&quot;2234&quot; data-filename=&quot;화면-기록-2023-09-13-오전-12.10.55.gif&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;2234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #e8e6e3; text-align: start; --darkreader-inline-color: #d8d4cf;&quot; data-ke-size=&quot;size16&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;useDebounce의 delay 인자의 초기값을 2000ms로 해서 꽤 시간이 걸리네요ㅎㅎ..&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #e8e6e3; text-align: start; --darkreader-inline-color: #d8d4cf;&quot; data-ke-size=&quot;size16&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;그래도 debounce를 적용하기전에는 한글자 한글자 마다 네트워크 요청이 이뤄졌었는데 , useDebounce 커스텀 훅으로 유저의 이벤트가 끝나고 2000ms이 지난 후 한번만 'korea' 네트워크 요청을 하는것을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #e8e6e3; text-align: start; --darkreader-inline-color: #d8d4cf;&quot; data-ke-size=&quot;size16&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #e8e6e3; text-align: start; --darkreader-inline-color: #d8d4cf;&quot; data-ke-size=&quot;size16&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #e8e6e3; text-align: start; --darkreader-inline-color: #d8d4cf;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;Reference&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=gwIkg1acujU&amp;amp;t=97s&quot;&gt;https://www.youtube.com/watch?v=gwIkg1acujU&amp;amp;t=97s&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=gwIkg1acujU&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/Krnu0/hyTSumlbM6/BgrGxg2qsA32tvqzp8uoF0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=798_174_1116_522&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;React Custom Hooks: useDebounce - Simply Explained!&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/gwIkg1acujU&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333;&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=d8CTMD2aang&quot;&gt;https://www.youtube.com/watch?v=d8CTMD2aang&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=d8CTMD2aang&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/ptzvL/hyTVS0bnQY/Ctbx7BVZwhFFKfM1nOMkCk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;검색창에 디바운스 적용하는 방법 [React]&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/d8CTMD2aang&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p style=&quot;color: #e8e6e3; text-align: start; --darkreader-inline-color: #d8d4cf;&quot; data-ke-size=&quot;size16&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #e8e6e3; text-align: start; --darkreader-inline-color: #d8d4cf;&quot; data-ke-size=&quot;size16&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #e8e6e3; text-align: start; --darkreader-inline-color: #d8d4cf;&quot; data-ke-size=&quot;size16&quot; data-darkreader-inline-color=&quot;&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>front-end/React</category>
      <category>custom hook</category>
      <category>debounce</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>React</category>
      <category>useDebounce</category>
      <category>디바운스</category>
      <category>커스텀훅</category>
      <author>code walker</author>
      <guid isPermaLink="true">https://fe-kwangmin.tistory.com/55</guid>
      <comments>https://fe-kwangmin.tistory.com/55#entry55comment</comments>
      <pubDate>Wed, 13 Sep 2023 00:19:27 +0900</pubDate>
    </item>
    <item>
      <title>[Monorepo] 모노레포는 멀티레포로부터 어떻게 구원을 해줄까?feat:Turborepo</title>
      <link>https://fe-kwangmin.tistory.com/54</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;모노레포를 알아보기전에 우선 모놀리식 , 멀티레포를 알아야 합니다.&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;모노레포의 등장배경과 모노레포의 장점을 파악하려면 기존의 프로젝트 구성에 어떤 단점이 있는지 알아봐야합니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;모놀리식이란?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt; 모놀리식 애플리케이션은 모듈화 없이 모든 구성 요소가 한 프로젝트 안에 통합된 소프트웨어 애플리케이션을 이야기합니다. DB 커넥션을 맺고, 데이터를 요청하며, 화면을 그리는 로직이 한 프로젝트 안에 구현된 초기 웹 서비스를 모놀리식 애플리션으로 볼 수 있습니다.&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #e8e6e3; text-align: start;&quot; data-ke-size=&quot;size20&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;모놀리식의 장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;소수의 개발자가 빠르게 개발할 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #e8e6e3; text-align: start;&quot; data-ke-size=&quot;size20&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;모놀리식의 단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;1. 관심사 분리가 어려워서 설계, 리팩토링 어려움&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;2. 매번 거대한 프로젝트를 배포 해야함.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;3. 일부분의 에러가 전체 서비스에 영향을 줄 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;멀티레포란 ?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;폴리레포(Poly repo) 라고도 부릅니다. 멀티레포란, 만약 모노레포가 지금 어떤것인지 모른다면 현재 사용되고있는 프로젝트는 멀티레포로 되어있을 가능성이 큽니다. 프로젝트별로 레파지토리를 생성하여 만든 프로젝트를 멀티레포라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;각각의 프로젝트가 자신만의 고유의 저장소를 가지게 되고 , 다른 프로젝트와 의존성을 전혀 갖고 있지 않아, 독립적으로 빠르게 개발이 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;그리고 독립적으로 관리가 되기 때문에 크기가 가벼우므로 프로젝트 관리 또한 쉬운 편 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;멀티레포의 장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;1.독립성과 격리: &lt;/b&gt;각&amp;nbsp;리포지토리는&amp;nbsp;독립적으로&amp;nbsp;관리되므로&amp;nbsp;하나의&amp;nbsp;리포에서&amp;nbsp;발생한&amp;nbsp;문제가&amp;nbsp;다른&amp;nbsp;리포에&amp;nbsp;영향을&amp;nbsp;미치지&amp;nbsp;않습니다.&amp;nbsp;이는&amp;nbsp;다수의&amp;nbsp;독립적인&amp;nbsp;프로젝트나&amp;nbsp;서비스를&amp;nbsp;관리해야&amp;nbsp;하는&amp;nbsp;경우&amp;nbsp;유용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;2. CI/CD 파이프라인 분리&lt;/b&gt;: 멀티 리포에서는 각 리포의 CI/CD 파이프라인을 분리하여 관리할 수 있으므로, 특정 프로젝트에 대한 배포 및 테스트 프로세스를 개별적으로 조정할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;멀티레포의 단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;1.코드 중복성:&lt;/b&gt; 공통 코드나 라이브러리가 여러 리포지토리에 중복해서 들어갈 수 있습니다. 이로 인해 코드 변경 사항을 유지하거나 버그를 수정할 때 중복된 작업이 필요할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;2.관리 오버헤드:&lt;/b&gt; 멀티 리포에서는 각각의 리포지토리를 별도로 관리해야 하므로, 리포지토리 생성, 업데이트, 보안 관리 등에 추가적인 관리 오버헤드가 발생할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;3.한가지 feature을 개발을 위해 여러 레파지토리에 merge를 해야합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://turbo.build/repo/docs/handbook/what-is-a-monorepo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;멀티레포의 단점에 대해 Turborepo에서 든 예시를 보면 멀티레포의 단점의 대해서 더욱 이해가 잘 되었습니다.&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;예를 들어, App, Doc 및 &lt;span style=&quot;text-align: start; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;shared-utils&lt;/span&gt; 세 개의 별도 저장소가 있다고 가정해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;App 과&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;text-align: start; --darkreader-inline-color: #c8c3bc;&quot; data-darkreader-inline-color=&quot;&quot;&gt;Doc&lt;/span&gt; 모두 npm 패키지로 게시되는 shared-utils에 의존합니다. shared-utils에서 버그가 발생하여 앱과 문서에 중요한 이슈가 발생한다고 가정해봅시다. 이러한 경우 다음과 같은 과정이 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;1. shared-utils에서 오류를 수정하는 커밋 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;2. shared-utils 내에서 npm에 게시하기 위한 게시 작업 실행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;3. App 내에서 shared-utils 종속성의 버전을 올리는 커밋 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;4. Doc 내에서 shared-utils 종속성의 버전을 올리는 커밋 생성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;5. 위 4단계를 거쳐야 App , Doc이 버그가 수정된 버전으로 배포를 완료 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start; --darkreader-inline-color: #c1bcb4;&quot; data-darkreader-inline-color=&quot;&quot;&gt;App 이나 Doc이&lt;/span&gt;&amp;nbsp;shared-utils에 의존하는 수가 늘어날수록 이 프로세스가 더 오래 걸릴 수 있으며 매우 번거로울 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;모노레포의 등장&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우선 간단하게 모노레포의 정의를 설명하자면 두 개 이상의 프로젝트 코드를 하나의 버전 관리 저장소(repository)에서 관리하는 방법을 말합니다. 멀티레포처럼 독립적으로 관리 되는것이 아닌, 멀티레포의 반대로 모두 하나의 레파지토리에서 모든것이 관리가 됩니다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;(최상위&amp;nbsp;폴더부터&amp;nbsp;트리구조로&amp;nbsp;서비스&amp;nbsp;폴더가&amp;nbsp;구성된다고&amp;nbsp;합니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;Google, Facebook, Microsoft, Uber, Airbnb 그리고 Twitter 등 여러 글로벌 기업들은 자신들의 운영 전략 아래 대규모 모노레포를 이미 운영하고 있다고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;프로젝트를 진행할때 규모가 작으면 굳이 모노레포 구성의 프로젝트 세팅을 할 필요는없곘지만, 서비스가 거대해지면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;코드내에서 공유되는 코드 그리고 의존성 패키지들이 분명히 점차 많이 생겨날것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;모노레포의 장점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;1. 코드 공유와 재사용:&lt;/b&gt;&amp;nbsp;모노리포에서는&amp;nbsp;모든&amp;nbsp;애플리케이션&amp;nbsp;및&amp;nbsp;모듈이&amp;nbsp;하나의&amp;nbsp;코드베이스에서&amp;nbsp;관리됩니다.&amp;nbsp;이로&amp;nbsp;인해&amp;nbsp;코드&amp;nbsp;공유와&amp;nbsp;재사용이&amp;nbsp;용이해집니다.&amp;nbsp;공통&amp;nbsp;라이브러리,&amp;nbsp;유틸리티&amp;nbsp;함수&amp;nbsp;및&amp;nbsp;컴포넌트를&amp;nbsp;쉽게&amp;nbsp;다른&amp;nbsp;프로젝트에서&amp;nbsp;공유하고&amp;nbsp;활용할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;2. 테스트 및 통합 용이성&lt;/b&gt;: 모노리포에서는 모든 코드가 함께 있으므로 서로 다른 애플리케이션 간의 테스트 및 통합이 용이합니다. 코드 변경 사항이 다른 애플리케이션에 어떤 영향을 미치는지 빠르게 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;3.배포&amp;nbsp;및&amp;nbsp;릴리스&amp;nbsp;관리&amp;nbsp;단순화:&amp;nbsp;&lt;/b&gt;모노리포에서는&amp;nbsp;하나의&amp;nbsp;릴리스&amp;nbsp;프로세스를&amp;nbsp;사용하여&amp;nbsp;모든&amp;nbsp;프로젝트를&amp;nbsp;동시에&amp;nbsp;배포할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이로&amp;nbsp;인해&amp;nbsp;배포&amp;nbsp;및&amp;nbsp;버전&amp;nbsp;관리가&amp;nbsp;단순화되며,&amp;nbsp;다수의&amp;nbsp;애플리케이션&amp;nbsp;간의&amp;nbsp;버전&amp;nbsp;호환성을&amp;nbsp;보다&amp;nbsp;쉽게&amp;nbsp;유지할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;4.NPM에 배포할 필요가없어서 의존성관리가 쉬움&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이 외에도 의존성 관리가 쉽고 , 여러 프로젝트팀 간의 협업이 수월 해집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #e8e6e3; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;모노레포의 단점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;1. CI 속도 저하 가능성이 있음.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;2. 무분별한 리팩토링의 가능성이 있음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;모노레포를 사용해야 할때는 언제?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;1. 기존에 있는 서비스와 새로 개발 될 서비스가 비슷해서 로직관련한 코드의 중복성이 생길 수 있을때 모노레포를 사용하면 좋습니다. 예를들어 PC 페이지 모바일 페이지로 나뉘어지고 기능은 같을때 모노레포로 구성 하는것이 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;2. 멀티레포처럼 여러 레파지토리를 확인하면서 코드를 파악하지 않고 한눈에 하나의 저장소에서 여러 프로젝트를 파악 해야할때도 모노레포로 구성 하는것이 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;3. NPM과같은 디펜던시뿐만 아니라 전체적인 개발자의 코드 configuration 파일들도 모노레포에서 설정을 할 수 있기때문에&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;eslint, prettier 과 같은 세팅을 동일하게 줄 수 있어서 통일감 있는 코드를 작성할 수 있을때 , 또한 &lt;span style=&quot;text-align: start; --darkreader-inline-color: #c1bcb4;&quot; data-darkreader-inline-color=&quot;&quot;&gt;모노레포로 구성 하는것이 좋습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;&lt;b&gt;FYI , 마치며&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #000000;&quot;&gt;이런 모노레포를 구성해주는 도구도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Yarn , Turborepo ,, Nx , npm , pnmp 등 여러가지가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;개인적으로 저는 최근에 사이드프로젝트를 Next.js13으로 구성했었던적이 있어서 앞으로 Next.js 13을 멀티레포로 구성할때는&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;Vercel에서 관리 되는 Turborepo를 사용해서 사이드프로젝트를 진행 해볼 예정입니다 :)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;각각의 프레임워크, 라이브러리에 맞는 모노레포의 구성을 도와주는 도구가 있으니 참고하시면 될것같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://turbo.build/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://turbo.build&lt;/a&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1693928798486&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Turbo&quot; data-og-description=&quot;Turbo is an incremental bundler and build system optimized for JavaScript and TypeScript, written in Rust.&quot; data-og-host=&quot;turbo.build&quot; data-og-source-url=&quot;https://turbo.build/&quot; data-og-url=&quot;https://turbo.build&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/uLbPp/hyTPHeLLoR/1E7kPs6lYjkcz6vUDEION1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/JPVk9/hyTPzueQpf/kQM66TLzZfcq3u6XD47VK0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://turbo.build/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://turbo.build/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/uLbPp/hyTPHeLLoR/1E7kPs6lYjkcz6vUDEION1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/JPVk9/hyTPzueQpf/kQM66TLzZfcq3u6XD47VK0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Turbo&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Turbo is an incremental bundler and build system optimized for JavaScript and TypeScript, written in Rust.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;turbo.build&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://www.youtube.com/watch?v=mxLLIwZ93nY&quot;&gt;https://www.youtube.com/watch?v=mxLLIwZ93nY&lt;/a&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=mxLLIwZ93nY&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/BsyuB/hyTPJwROjX/5Zfk9zB3RgdQribGAbRAk1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=898_130_1058_304&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/mxLLIwZ93nY&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://www.youtube.com/watch?v=Ix9gxqKOatY&amp;amp;t=408s&quot;&gt;https://www.youtube.com/watch?v=Ix9gxqKOatY&amp;amp;t=408s&lt;/a&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=Ix9gxqKOatY&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/SmfHH/hyTStsnclt/4gG24ugnKZlx3QJdlyhEuK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=1026_440_1080_500&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/Ix9gxqKOatY&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>good tips for dev</category>
      <category>Monorepo</category>
      <category>turborepo</category>
      <category>멀티레포</category>
      <category>모노레포</category>
      <category>터보레포</category>
      <category>프로젝트구성</category>
      <category>프론트엔드</category>
      <category>프론트엔드세팅</category>
      <author>code walker</author>
      <guid isPermaLink="true">https://fe-kwangmin.tistory.com/54</guid>
      <comments>https://fe-kwangmin.tistory.com/54#entry54comment</comments>
      <pubDate>Wed, 6 Sep 2023 00:48:37 +0900</pubDate>
    </item>
    <item>
      <title>[Yarn Berry] Yarn Berry가 node_modules의 문제를 어떻게 해결할까?</title>
      <link>https://fe-kwangmin.tistory.com/53</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2년차 주니어 프론트엔드 개발자로 일하면서 , 요즘 드는 생각이 리액트, 뷰, 앵귤러 같은 프레임워크의 변화를 지켜보고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어떤 부분이 더 좋고, 어떤 부분이 더 편리하게 변했는지 공부하는거도 중요하지만 이런 프레임워크 및 라이브러리를 설치해주는 의존성 및 관리하는것은 node_modules 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제는 리액트 , 자바스크립트 등의 기술도 물론 중요하지만 이런 의존성 패키지의 Background에 대해서도 deep하게 공부 해야할것 같다는 생각이 들었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 node_modules의 단점을 극복해줄 Yarn berry를 알아보면서 node_modules의 단점을 공부하기위해 포스팅을 하려고합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Package 란?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우선 패키지란 무엇인지 간단한게 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;모듈(Module)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모듈은 Node.js 애플리케이션을 작은 조각으로 분할하는 방법입니다. 모듈은 코드를 논리적으로 그룹화하고 해당 모듈에서 정의된 변수, 함수, 클래스 등을 내보내거나 가져와서 재사용할 수 있게 해줍니다. Node.js는 CommonJS 스펙을 따르므로, require 함수를 사용하여 모듈을 불러올 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;패키지(Package)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt; 패키지는 Node.js 애플리케이션에서 사용되는 외부 라이브러리나 모듈의 집합입니다. 패키지는 package.json 파일에 정의되며, 이 파일은 프로젝트의 의존성 및 설정 정보를 포함합니다. 패키지 관리자인 npm(Node Package Manager) 또는 yarn을 사용하여 패키지를 설치하고 관리할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;node_modules 의 문제점&lt;/b&gt;&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;간단하게 node_modules의 대표적인 단점들을 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;의존성 버전 충돌&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로젝트의 여러 의존성 패키지가 서로 다른 버전의 라이브러리를 요구할 때, node_modules는 버전 충돌 문제가 발생할 수 있습니다. 이로 인해 프로젝트의 안정성과 유지 보수가 어려워질 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;패키지&amp;nbsp;설치&amp;nbsp;시간&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;의존성 패키지를 설치할 때 node_mo&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;dules 폴더는 상당한 용량을 차지하고 설치 시간이 오래 걸릴 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-05 오전 1.17.14.png&quot; data-origin-width=&quot;1389&quot; data-origin-height=&quot;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BPfQi/btssZg2n4as/sMIk3PvKAeIbtOOdX2l5y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BPfQi/btssZg2n4as/sMIk3PvKAeIbtOOdX2l5y1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BPfQi/btssZg2n4as/sMIk3PvKAeIbtOOdX2l5y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBPfQi%2FbtssZg2n4as%2FsMIk3PvKAeIbtOOdX2l5y1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1389&quot; height=&quot;491&quot; data-filename=&quot;스크린샷 2023-09-05 오전 1.17.14.png&quot; data-origin-width=&quot;1389&quot; data-origin-height=&quot;491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;프로젝트 폴더 가독성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;node_modules 폴더는 프로젝트의 루트 디렉토리에 생성되며, 프로젝트 코드와 함께 저장되어 프로젝트 구조를 복잡하게 만들 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 외에도 &lt;a href=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;비효율적 의존성 검색, 유령 의존성&lt;/a&gt; 등이 있습니다. 토스팀 에서 잘 설명해놓은게 있으니 링크 참고해서 꼭 확인해보시는걸 추천 드립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;참고로 Yarn과 Npm은 다운로드를 받았는지만 검사하고 , 의존성 모듈들이 &quot;잘&quot; 다운로드가 됐는지는 확인을 안한다고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Yarn berry의 등장&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우선 Yarn berry는 node_modules와 node에 내장된 의존성 관리 없이 의존성을 관리하는게 주요한 기능 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt; Yarn berry는 Yarn version2 입니다. 이전&amp;nbsp;버전의&amp;nbsp;Yarn과&amp;nbsp;비교하여&amp;nbsp;다음과&amp;nbsp;같은&amp;nbsp;주요&amp;nbsp;변경&amp;nbsp;사항이&amp;nbsp;있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;PnP (Plug'n'Play) 모드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Yarn Berry의 가장 큰 변경 사항 중 하나는 Plug'n'Play(PnP) 모드의 도입입니다. PnP 모드는 Node.js 프로젝트에서 의존성을 관리하는 새로운 방식입니다. 이전에는 node_modules 폴더에 의존성 패키지를 설치하고 사용했지만 PnP 모드에서는 이러한 패키지를 별도의 폴더에 설치하고 가상 파일 시스템을 통해 Node.js에 제공합니다. 이로써 의존성 충돌과 패키지 버전 관리가 향상되며, 더 빠른 설치와 실행이 가능해집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;PnP (Plug'n'Play)&amp;nbsp; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;사용법&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;NPM에서 최신버전의 Yarn을 내려받고, 버전을 Berry로 설정하면 Yarn Berry를 사용 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1693845118832&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install -g yarn
$ cd ../path/to/some-package
$ yarn set version berry&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러고 PnP 모드에서 yarn install을 이용하여 의존성을 다운로드 했을때 기존의 node_modules랑은 다른 모습울 볼 수 있습니다,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Yarn berry를 이용하면 node_modulues가 디렉토리에 없는걸 확인 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대신 .yarn/cahce 폴더에 의존성의 정보가 저장이 되고&amp;nbsp; pnp.cjs 라는 생소한 파일이 하나 있을건데요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;pnp.cjs 파일에 의존성을 찾을 수 있는 정보가 기록 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brFE5i/btss91iAhUo/PtznRylHkkaoHVklkmKGPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brFE5i/btss91iAhUo/PtznRylHkkaoHVklkmKGPk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;412&quot; data-filename=&quot;스크린샷 2023-09-05 오전 1.30.05.png&quot; style=&quot;width: 28.7642%; margin-right: 10px;&quot; data-widthpercent=&quot;29.1&quot; id=&quot;kEditorPhotosEditingImage-1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brFE5i/btss91iAhUo/PtznRylHkkaoHVklkmKGPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrFE5i%2Fbtss91iAhUo%2FPtznRylHkkaoHVklkmKGPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;418&quot; height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LG5Oo/btssVTGlT93/Gf6UDyOKPxSGMIv0aEniJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LG5Oo/btssVTGlT93/Gf6UDyOKPxSGMIv0aEniJ0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1305&quot; data-origin-height=&quot;528&quot; data-filename=&quot;스크린샷 2023-09-05 오전 1.38.46.png&quot; width=&quot;50&quot; height=&quot;20&quot; style=&quot;width: 70.073%;&quot; data-widthpercent=&quot;70.9&quot; id=&quot;kEditorPhotosEditingImage-2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LG5Oo/btssVTGlT93/Gf6UDyOKPxSGMIv0aEniJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLG5Oo%2FbtssVTGlT93%2FGf6UDyOKPxSGMIv0aEniJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1305&quot; height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;출처:우아한 테크 유튜브&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Zero Install (feat: zipfile)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-05 오전 1.34.02.png&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4huKF/btssUKpopzp/3AqVcZrfH0h4YldkiYni10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4huKF/btssUKpopzp/3AqVcZrfH0h4YldkiYni10/img.png&quot; data-alt=&quot;출처: 우아한 테크 유튜브&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4huKF/btssUKpopzp/3AqVcZrfH0h4YldkiYni10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4huKF%2FbtssUKpopzp%2F3AqVcZrfH0h4YldkiYni10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;632&quot; height=&quot;349&quot; data-filename=&quot;스크린샷 2023-09-05 오전 1.34.02.png&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 우아한 테크 유튜브&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위 디렉토리 구조를 보면 zip으로 묶인 라이브러리가 저장된 .yarn/cache 폴더를 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Yarn PnP 시스템에서 각 의존성은 Zip으로 관리됩니다. 이후 .pnp.cjs 파일이 지정하는 바에 따라 동적으로 Zip 아카이브 내용이 참조 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Zip 아카이브의 의존성의 장점은 &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 더 이상 node_modules의 구조를 생성할 필요가 없기때문에 설치가 빨리 완료됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 각 패키지는 버전마다 하나의 Zip 아카이브를 가지기 떄문에 중복해서 설치 되지 않습니다. 또한 Zip이 압축되어있음을 고려할때 스토리지 용량을 크게 아낄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;속도비교&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-09-05 오전 1.41.30.png&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c16IvG/btss3WvKMaC/S5tPx9lP6tWITvkoGwwwW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c16IvG/btss3WvKMaC/S5tPx9lP6tWITvkoGwwwW1/img.png&quot; data-alt=&quot;출처:우아한테크 유튜브&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c16IvG/btss3WvKMaC/S5tPx9lP6tWITvkoGwwwW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc16IvG%2Fbtss3WvKMaC%2FS5tPx9lP6tWITvkoGwwwW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1424&quot; height=&quot;544&quot; data-filename=&quot;스크린샷 2023-09-05 오전 1.41.30.png&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;544&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:우아한테크 유튜브&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;NPM&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;npm은 아무래도 가장 오래 사용되고 있기도 하고 그만큼 reference가 많아서 trouble shooting 하기도 좋은 패키지 매니지먼트&amp;nbsp; 입니다. reference가 많고 안정된걸 지향 한다면 추천 드립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;PNPM&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;pnpm은 npm보다는 성능이 좋지만 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;reference npm보다는 없기 때문에 npm 만큼의 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;trouble shooting을 기대하긴 어려울것같습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Yarn (Classic)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Yarn version 1 같은 경우에는 2.0 버전이 나오면서 2020년도 부터 더 이상 ver1은 개발하지않고 유지보수 모드로 들어갔다고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;장기적인 프로젝트를 진행한다면 Yarn ver 1 사용은 지양 하는게 좋을것같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Yarn Berry&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;npm 만큼의 reference는 없지만  CI / CD 및 배포속도 패키지의 용량 고려 등의 이유로 충분히 도입 해볼만 하다고 생각합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=LUykz1etOo0&quot;&gt;https://www.youtube.com/watch?v=LUykz1etOo0&lt;/a&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=LUykz1etOo0&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/XytNj/hyTPx3Ujq9/8zM8CpVyFzFDkrJHE607i0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/LUykz1etOo0&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://toss.tech/article/node-modules-and-yarn-berry&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1693846158832&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;node_modules로부터 우리를 구원해 줄 Yarn Berry&quot; data-og-description=&quot;토스 프론트엔드 레포지토리 대부분에서 사용하고 있는 패키지 매니저 Yarn Berry. 채택하게 된 배경과 사용하면서 좋았던 점을 공유합니다.&quot; data-og-host=&quot;toss.tech&quot; data-og-source-url=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot; data-og-url=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cwPEWP/hyTPuTEXuX/A4SM6jwSnPIXPBMzpWquQ0/img.png?width=4802&amp;amp;height=2514&amp;amp;face=0_0_4802_2514,https://scrap.kakaocdn.net/dn/dCHlz7/hyTPBSML0B/EmiNJYTtGsxrkGO3XpvyN0/img.png?width=1500&amp;amp;height=1500&amp;amp;face=0_0_1500_1500&quot;&gt;&lt;a href=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cwPEWP/hyTPuTEXuX/A4SM6jwSnPIXPBMzpWquQ0/img.png?width=4802&amp;amp;height=2514&amp;amp;face=0_0_4802_2514,https://scrap.kakaocdn.net/dn/dCHlz7/hyTPBSML0B/EmiNJYTtGsxrkGO3XpvyN0/img.png?width=1500&amp;amp;height=1500&amp;amp;face=0_0_1500_1500');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;node_modules로부터 우리를 구원해 줄 Yarn Berry&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;토스 프론트엔드 레포지토리 대부분에서 사용하고 있는 패키지 매니저 Yarn Berry. 채택하게 된 배경과 사용하면서 좋았던 점을 공유합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;toss.tech&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Ds7EjE8Rhjs&amp;amp;t=77s&quot;&gt;https://www.youtube.com/watch?v=Ds7EjE8Rhjs&amp;amp;t=77s&lt;/a&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=Ds7EjE8Rhjs&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/lYBmj/hyTPusBANr/kQXxOlEQrGZxoKn8pF4k0K/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=816_184_918_294&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/Ds7EjE8Rhjs&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>good tips for dev</category>
      <category>Front-End</category>
      <category>node_modules</category>
      <category>npm</category>
      <category>PnP</category>
      <category>Yarn</category>
      <category>yarn berry</category>
      <category>yarn v2</category>
      <author>code walker</author>
      <guid isPermaLink="true">https://fe-kwangmin.tistory.com/53</guid>
      <comments>https://fe-kwangmin.tistory.com/53#entry53comment</comments>
      <pubDate>Tue, 5 Sep 2023 01:56:54 +0900</pubDate>
    </item>
    <item>
      <title>[React] 왜 Create React App 대신에 Vite를 사용할까?</title>
      <link>https://fe-kwangmin.tistory.com/51</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2년전쯤 리액트를 처음 배울때는 CRA 를 통해 React app을 만들어서 공부를 했었는데요 , 요새는 vite를 더 추구하는것같습니다. 그래서 Vite를 사용한지도 약 1년정도 된거같은데, 체감상으로도 확실히 &lt;b&gt;빌드속도&lt;/b&gt; ,&lt;b&gt;세팅속도&lt;/b&gt; 그리고 가장 매력적이였던건 개발 중 &lt;b&gt;코드를 수정하고 브라우저에 반영하기까지의 속도가 CRA에 비해 굉장히 빨랐습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어떤 점이 Vite가 CRA보다 궁금해서 검색을 하다가 설명이 너무 길지도 않고 Vite의 핵심만 담겨있는 포스트를 발견해서 번역 및 참고 해서 포스트를 하려고합니다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;:&lt;a href=&quot;https://makimo.com/blog/why-we-use-vite-instead-of-create-react-app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://makimo.com/blog/why-we-use-vite-instead-of-create-react-app/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1692754713050&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Why we use Vite instead of Create React App &amp;mdash; Makimo &amp;ndash; Consultancy &amp;amp; Software Development Services&quot; data-og-description=&quot;Create React App is for many developers the default option since they have never checked out other JavaScript build tools. But there are better alternatives.&quot; data-og-host=&quot;makimo.com&quot; data-og-source-url=&quot;https://makimo.com/blog/why-we-use-vite-instead-of-create-react-app/&quot; data-og-url=&quot;https://makimo.com/blog/why-we-use-vite-instead-of-create-react-app/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ccD2bb/hyTIDP36pq/gjbZmTTP27jJKqFIsqK4OK/img.png?width=1160&amp;amp;height=606&amp;amp;face=0_0_1160_606,https://scrap.kakaocdn.net/dn/bHWWQc/hyTIEBqeqS/2nEn83ft0S6zXaeoT45dFK/img.png?width=1160&amp;amp;height=606&amp;amp;face=0_0_1160_606&quot;&gt;&lt;a href=&quot;https://makimo.com/blog/why-we-use-vite-instead-of-create-react-app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://makimo.com/blog/why-we-use-vite-instead-of-create-react-app/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ccD2bb/hyTIDP36pq/gjbZmTTP27jJKqFIsqK4OK/img.png?width=1160&amp;amp;height=606&amp;amp;face=0_0_1160_606,https://scrap.kakaocdn.net/dn/bHWWQc/hyTIEBqeqS/2nEn83ft0S6zXaeoT45dFK/img.png?width=1160&amp;amp;height=606&amp;amp;face=0_0_1160_606');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Why we use Vite instead of Create React App &amp;mdash; Makimo &amp;ndash; Consultancy &amp;amp; Software Development Services&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Create React App is for many developers the default option since they have never checked out other JavaScript build tools. But there are better alternatives.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;makimo.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;CRA가&amp;nbsp;느린&amp;nbsp;이유는&amp;nbsp;무엇인가요?&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CRA는 내부적으로 &lt;b&gt;웹팩(Webpack)&lt;/b&gt;을 사용합니다. 웹팩은 애플리케이션 코드 전체를 번들로 묶은 후 서버에서 제공합니다. 큰 코드베이스의 경우 개발 서버를 실행하는 데 더 많은 시간이 걸리며 변경 사항이 반영되는 시간도 오래 걸립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대다수의 프로젝트는 대표적인 프론트엔드 애플리케이션 개발 라이브러리인 React의 창시자들이 주도하는 Create React App (CRA)에 의존하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CRA는 React 문서에서 기본 선택지이며, 많은 개발자들에게는 다른 JavaScript 앱 빌드 도구를 확인해보지 않아서 기본 선택으로 남게 되었습니다. 그러나 더 나은 대안들이 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Makimo에서는&amp;nbsp;많은&amp;nbsp;애플리케이션을&amp;nbsp;Vite로&amp;nbsp;전환하고&amp;nbsp;있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래에서는 이 작업을 진행한 이유를 설명하겠습니다. 또한 Create React App의 한계에 대해서도 논의하겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CRA는 JavaScript 프로젝트를 구성하기 위한 매우 간단한 도구이며, 단일 명령으로 작동하는 작업을 생성할 수 있습니다. 그러나 구성 및 번들러 사용에 대한 제약으로 인해 Vite가 더 나은 선택임이 입증되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Vite&amp;nbsp;대비&amp;nbsp;Create&amp;nbsp;React&amp;nbsp;App의&amp;nbsp;장점&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Create&amp;nbsp;React&amp;nbsp;App&amp;nbsp;(CRA)은&amp;nbsp;가장&amp;nbsp;인기&amp;nbsp;있는&amp;nbsp;번들러&amp;nbsp;중&amp;nbsp;하나인&amp;nbsp;Webpack을&amp;nbsp;구성할&amp;nbsp;필요&amp;nbsp;없이&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;해주는&amp;nbsp;확장&amp;nbsp;프로그램입니다.&amp;nbsp;CRA는&amp;nbsp;Webpack에&amp;nbsp;새로운&amp;nbsp;기능을&amp;nbsp;추가하지&amp;nbsp;않습니다.&amp;nbsp;오히려&amp;nbsp;가능한&amp;nbsp;선택지의&amp;nbsp;수를&amp;nbsp;제한하여&amp;nbsp;초보&amp;nbsp;개발자들을&amp;nbsp;위한&amp;nbsp;확실한&amp;nbsp;솔루션으로&amp;nbsp;만들어&amp;nbsp;줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;빌드 속도&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CRA를&amp;nbsp;Vite로&amp;nbsp;변경한&amp;nbsp;주된&amp;nbsp;이유는&amp;nbsp;속도입니다.&amp;nbsp;Vite는&amp;nbsp;esbuild&amp;nbsp;번들러를&amp;nbsp;사용하며,&amp;nbsp;CRA에서&amp;nbsp;사용되는&amp;nbsp;Webpack보다&amp;nbsp;훨씬&amp;nbsp;빠릅니다.&amp;nbsp;Vite의&amp;nbsp;속도는&amp;nbsp;&lt;b&gt;Go&lt;/b&gt;&amp;nbsp;언어로&amp;nbsp;작성되어&amp;nbsp;&lt;b&gt;빠른&amp;nbsp;멀티스레드&amp;nbsp;언어&lt;/b&gt;로&amp;nbsp;기계&amp;nbsp;코드로&amp;nbsp;컴파일되기&amp;nbsp;때문에&amp;nbsp;생겨난&amp;nbsp;것입니다.&amp;nbsp;이에&amp;nbsp;반해&amp;nbsp;Webpack은&amp;nbsp;JavaScript로&amp;nbsp;작성되었고&amp;nbsp;해석되며&amp;nbsp;단일&amp;nbsp;스레드로&amp;nbsp;작동되어&amp;nbsp;더&amp;nbsp;느립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;보다 유연한 설정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;많은&amp;nbsp;사람들은&amp;nbsp;CRA를&amp;nbsp;선택한&amp;nbsp;이유가&amp;nbsp;구성이&amp;nbsp;필요하지&amp;nbsp;않기&amp;nbsp;때문입니다.&amp;nbsp;CRA의&amp;nbsp;주요&amp;nbsp;장점은&amp;nbsp;단일&amp;nbsp;명령으로&amp;nbsp;React&amp;nbsp;애플리케이션을&amp;nbsp;실행할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;능력입니다.&amp;nbsp;그러나&amp;nbsp;이는&amp;nbsp;유연성의&amp;nbsp;부족이라는&amp;nbsp;대가를&amp;nbsp;지닙니다.&amp;nbsp;큰&amp;nbsp;프로젝트에서는&amp;nbsp;분명히&amp;nbsp;CRA에&amp;nbsp;새로운&amp;nbsp;기능을&amp;nbsp;추가해야&amp;nbsp;할&amp;nbsp;필요성을&amp;nbsp;느낄&amp;nbsp;것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CRA가&amp;nbsp;기능을&amp;nbsp;지원하지&amp;nbsp;않을&amp;nbsp;때,&amp;nbsp;그&amp;nbsp;한계를&amp;nbsp;해결하기&amp;nbsp;위해&amp;nbsp;다양한&amp;nbsp;조치들이&amp;nbsp;필요합니다.&amp;nbsp;예를&amp;nbsp;들어&amp;nbsp;Webpack의&amp;nbsp;구성&amp;nbsp;파일을&amp;nbsp;복원하려면&amp;nbsp;CRA&amp;nbsp;자체&amp;nbsp;대신&amp;nbsp;CRACO를&amp;nbsp;설치해야&amp;nbsp;하며,&amp;nbsp;이로&amp;nbsp;인해&amp;nbsp;CRA&amp;nbsp;버전&amp;nbsp;4를&amp;nbsp;사용하는&amp;nbsp;것으로&amp;nbsp;제한됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;반면&amp;nbsp;&lt;b&gt;Vite&lt;/b&gt;는&amp;nbsp;&lt;b&gt;rollup.js&lt;/b&gt;를&amp;nbsp;고려하여&amp;nbsp;개발된&amp;nbsp;플러그인&amp;nbsp;지원을&amp;nbsp;가지고&amp;nbsp;있습니다.&amp;nbsp;이는&amp;nbsp;빠르게&amp;nbsp;Rollup&amp;nbsp;플러그인을&amp;nbsp;작성할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;인기&amp;nbsp;있는&amp;nbsp;솔루션으로,&amp;nbsp;누락된&amp;nbsp;기능을&amp;nbsp;추가할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;도와줍니다.&amp;nbsp;Rollup은&amp;nbsp;훨씬&amp;nbsp;더&amp;nbsp;다양한&amp;nbsp;플러그인&amp;nbsp;생태계를&amp;nbsp;가지고&amp;nbsp;있어&amp;nbsp;필요에&amp;nbsp;맞는&amp;nbsp;환경을&amp;nbsp;생성할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;프레임워크 지원&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Vite는 React, Vue, Svelte와 같은 다양한 프레임워크를 사용합니다. CRA는 능력을 React에만 한정합니다. 다른 프레임워크에서 애플리케이션을 개발할 때마다 처음부터 새로운 도구를 학습해야 할 필요가 있습니다. Vite는 Vue의 창시자들이 만들었음에도 불구하고 React, Vue 및 SolidJS, Svelte 또는 Lit과 같은 덜 인기 있는 프레임워크를 구성할 수 있게 해줍니다. 모든 프로젝트에서 Vite를 사용함으로써 많은 학습 시간을 절약하고 새로운 개발자들이 쉽게 프로젝트에 참여할 수 있도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개발&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전에는&amp;nbsp;&lt;b&gt;Snowpack&lt;/b&gt;라는&amp;nbsp;솔루션을&amp;nbsp;사용했으나,&amp;nbsp;불행히도&amp;nbsp;해당&amp;nbsp;프로젝트는&amp;nbsp;더&amp;nbsp;이상&amp;nbsp;유지되지&amp;nbsp;않아&amp;nbsp;계속해서&amp;nbsp;도구를&amp;nbsp;바꾸는&amp;nbsp;악순환에&amp;nbsp;빠지지&amp;nbsp;않도록&amp;nbsp;잘&amp;nbsp;개발된&amp;nbsp;대안을&amp;nbsp;찾기&amp;nbsp;시작했습니다.&amp;nbsp;그와&amp;nbsp;반대로&amp;nbsp;Vite는&amp;nbsp;상당히&amp;nbsp;안정적이며&amp;nbsp;포괄적인&amp;nbsp;생태계를&amp;nbsp;가지고&amp;nbsp;있습니다.&amp;nbsp;npm에서&amp;nbsp;평균&amp;nbsp;주당&amp;nbsp;2.5백만&amp;nbsp;다운로드를&amp;nbsp;기록하고&amp;nbsp;있으며,&amp;nbsp;업데이트는&amp;nbsp;평균&amp;nbsp;한&amp;nbsp;달에&amp;nbsp;한&amp;nbsp;번씩&amp;nbsp;출시되며&amp;nbsp;커뮤니티는&amp;nbsp;계속해서&amp;nbsp;수정&amp;nbsp;작업을&amp;nbsp;진행하고&amp;nbsp;있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;핵심기능&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가장&amp;nbsp;중요한&amp;nbsp;이득은&amp;nbsp;응용&amp;nbsp;프로그램&amp;nbsp;개발&amp;nbsp;중의&amp;nbsp;속도입니다.&amp;nbsp;브라우저에서&amp;nbsp;응용&amp;nbsp;프로그램이&amp;nbsp;새로&amp;nbsp;고침되기까지&amp;nbsp;몇&amp;nbsp;초를&amp;nbsp;기다려야만&amp;nbsp;하는&amp;nbsp;경우&amp;nbsp;집중력을&amp;nbsp;잃고&amp;nbsp;주의가&amp;nbsp;흐트러질&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이는&amp;nbsp;하루에&amp;nbsp;수백&amp;nbsp;번&amp;nbsp;이상&amp;nbsp;발생할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;Vite를&amp;nbsp;사용하면&amp;nbsp;이러한&amp;nbsp;문제를&amp;nbsp;겪지&amp;nbsp;않게&amp;nbsp;됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;실제 사례&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span&gt;더&amp;nbsp;작은&amp;nbsp;프로젝트에서&amp;nbsp;CRA를&amp;nbsp;Vite로&amp;nbsp;교체한&amp;nbsp;결과,&amp;nbsp;애플리케이션&amp;nbsp;빌드&amp;nbsp;시간이&amp;nbsp;거의&amp;nbsp;절반으로&amp;nbsp;줄었습니다.&amp;nbsp;28.4초에서&amp;nbsp;16.1초로&amp;nbsp;개선되었습니다.&amp;nbsp;이&amp;nbsp;시간&amp;nbsp;절약은&amp;nbsp;Github&amp;nbsp;Actions와&amp;nbsp;같은&amp;nbsp;자동화에서&amp;nbsp;가장&amp;nbsp;두드러집니다.&amp;nbsp;로컬&amp;nbsp;서버도&amp;nbsp;훨씬&amp;nbsp;빨리&amp;nbsp;시작됩니다.&amp;nbsp;CRA는&amp;nbsp;동일한&amp;nbsp;프로젝트를&amp;nbsp;4.5초에&amp;nbsp;시작하지만,&amp;nbsp;Vite는&amp;nbsp;390ms에&amp;nbsp;작업을&amp;nbsp;수행합니다.&amp;nbsp;이는&amp;nbsp;상당한&amp;nbsp;시간을&amp;nbsp;절약해줍니다.&amp;nbsp;개발자가&amp;nbsp;프로젝트에서&amp;nbsp;작업하는&amp;nbsp;경우&amp;nbsp;차이가&amp;nbsp;눈에&amp;nbsp;띄지&amp;nbsp;않을&amp;nbsp;수&amp;nbsp;있지만,&amp;nbsp;더&amp;nbsp;큰&amp;nbsp;규모에서는&amp;nbsp;이미&amp;nbsp;절약이&amp;nbsp;크게&amp;nbsp;나타납니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음&amp;nbsp;빌드&amp;nbsp;및&amp;nbsp;배포에서의&amp;nbsp;시간&amp;nbsp;절약은&amp;nbsp;좋은&amp;nbsp;점일&amp;nbsp;수&amp;nbsp;있지만,&amp;nbsp;더&amp;nbsp;좋은&amp;nbsp;것이&amp;nbsp;있습니다.&amp;nbsp;개발&amp;nbsp;중에는&amp;nbsp;변경&amp;nbsp;사항을&amp;nbsp;빠르게&amp;nbsp;반영하기&amp;nbsp;위해&amp;nbsp;각&amp;nbsp;변경&amp;nbsp;후&amp;nbsp;애플리케이션을&amp;nbsp;다시&amp;nbsp;로드하는&amp;nbsp;핫&amp;nbsp;리로드&amp;nbsp;기능을&amp;nbsp;자주&amp;nbsp;사용합니다.&amp;nbsp;CRA에서는&amp;nbsp;저장&amp;nbsp;후&amp;nbsp;뷰가&amp;nbsp;업데이트되기까지&amp;nbsp;약&amp;nbsp;5초를&amp;nbsp;기다려야&amp;nbsp;했습니다.&amp;nbsp;그러나&amp;nbsp;Vite에서는&amp;nbsp;이것이&amp;nbsp;거의&amp;nbsp;즉시&amp;nbsp;발생하여&amp;nbsp;개발을&amp;nbsp;더&amp;nbsp;즐겁고&amp;nbsp;효율적으로&amp;nbsp;만들어주며,&amp;nbsp;애플리케이션을&amp;nbsp;빌드하기를&amp;nbsp;기다리는&amp;nbsp;동안&amp;nbsp;기다리는&amp;nbsp;시간으로&amp;nbsp;인한&amp;nbsp;주의산만을&amp;nbsp;방지합니다.&amp;nbsp;이는&amp;nbsp;작업의&amp;nbsp;품질을&amp;nbsp;완전히&amp;nbsp;변화시킵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;매번&amp;nbsp;약간의&amp;nbsp;시간을&amp;nbsp;절약한다고&amp;nbsp;해서&amp;nbsp;별로&amp;nbsp;중요하지&amp;nbsp;않아&amp;nbsp;보일&amp;nbsp;수&amp;nbsp;있지만,&amp;nbsp;여러&amp;nbsp;분을&amp;nbsp;걸리는&amp;nbsp;큰&amp;nbsp;애플리케이션을&amp;nbsp;생각해보면&amp;nbsp;몇&amp;nbsp;분이&amp;nbsp;걸릴&amp;nbsp;수도&amp;nbsp;있는데,&amp;nbsp;그럴&amp;nbsp;때&amp;nbsp;차이는&amp;nbsp;분명히&amp;nbsp;더&amp;nbsp;눈에&amp;nbsp;띄게&amp;nbsp;됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 테이블은 CRA 에서 Vite 로 전환한 몇 가지 프로젝트의 예시입니다:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-23 오전 10.28.13.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vru65/btsrZwREvLR/lPnaxLY9zkSuU038Ztp67k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vru65/btsrZwREvLR/lPnaxLY9zkSuU038Ztp67k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vru65/btsrZwREvLR/lPnaxLY9zkSuU038Ztp67k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvru65%2FbtsrZwREvLR%2FlPnaxLY9zkSuU038Ztp67k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;728&quot; height=&quot;207&quot; data-filename=&quot;스크린샷 2023-08-23 오전 10.28.13.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;요약&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Create React App는 React로 간단한 첫 번째 앱을 구축하는 데 적합합니다. 그러나 빠르게 제한 사항을 인식하게 되며, 앱을 생성할 때 더 유연한 도구를 선택하는 것이 의미가 있습니다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 리액트 말고도 다양한 프레임워크를 사용할경우 Vite는 더욱 좋은 선택이 될것같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;속도와 구성의 간편함으로 인해 Vite로 전환하는 데 투자한 시간은 빠르게 보답받습니다. 거대한 기능을 가지고 있음에도 불구하고, 이 도구는 사용하기 쉬우며 개발자들을 제한하지 않습니다. 무엇보다도 Vite의 사용은 시간을 절약해주며 어떤 JS 프로젝트에도 유연하게 적용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>front-end/React</category>
      <category>CRA</category>
      <category>frontend</category>
      <category>React</category>
      <category>Vite</category>
      <category>webpack</category>
      <category>리액트</category>
      <author>code walker</author>
      <guid isPermaLink="true">https://fe-kwangmin.tistory.com/51</guid>
      <comments>https://fe-kwangmin.tistory.com/51#entry51comment</comments>
      <pubDate>Wed, 23 Aug 2023 10:39:39 +0900</pubDate>
    </item>
    <item>
      <title>[React]  HOC (고차 컴포넌트, Higher-Order Component)</title>
      <link>https://fe-kwangmin.tistory.com/50</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;maxresdefault.jpeg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdZUzE/btsrr3wLBEB/COUddAEieEDHyKC6WFr0z0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdZUzE/btsrr3wLBEB/COUddAEieEDHyKC6WFr0z0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdZUzE/btsrr3wLBEB/COUddAEieEDHyKC6WFr0z0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdZUzE%2Fbtsrr3wLBEB%2FCOUddAEieEDHyKC6WFr0z0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-filename=&quot;maxresdefault.jpeg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;HOC 란?&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;리액트의&amp;nbsp;&lt;b&gt;HOC(고차&amp;nbsp;컴포넌트,&amp;nbsp;Higher-Order&amp;nbsp;Component)&lt;/b&gt;는&amp;nbsp;컴포넌트&amp;nbsp;간의&amp;nbsp;로직을&amp;nbsp;재사용하기&amp;nbsp;위한&amp;nbsp;패턴입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;HOC는&amp;nbsp;함수이며,&amp;nbsp;&lt;b&gt;인자&lt;/b&gt;로&amp;nbsp;&lt;b&gt;컴포넌트를&lt;/b&gt;&amp;nbsp;받아들이고,&amp;nbsp;&lt;b&gt;새로운&amp;nbsp;컴포넌트를&amp;nbsp;반환&lt;/b&gt;합니다.&amp;nbsp;이렇게&amp;nbsp;반환된&amp;nbsp;컴포넌트는&amp;nbsp;원본&amp;nbsp;컴포넌트의&amp;nbsp;기능을&amp;nbsp;감싸거나&amp;nbsp;수정하는&amp;nbsp;데&amp;nbsp;사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 리액트 공식문서에서 설명이 잘 나와있어서 아래의 이미지를 스크랩 해왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-18 오전 11.28.05.png&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ugcNi/btsrrUNrgsP/rTNqUUEBcMGHhZdsAcj3c0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ugcNi/btsrrUNrgsP/rTNqUUEBcMGHhZdsAcj3c0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ugcNi/btsrrUNrgsP/rTNqUUEBcMGHhZdsAcj3c0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FugcNi%2FbtsrrUNrgsP%2FrTNqUUEBcMGHhZdsAcj3c0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1022&quot; height=&quot;430&quot; data-filename=&quot;스크린샷 2023-08-18 오전 11.28.05.png&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;HOC 활용 및 활용 이유&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;함수&amp;nbsp;반환:&amp;nbsp;&lt;/b&gt;HOC는&amp;nbsp;함수입니다.&amp;nbsp;이&amp;nbsp;함수는&amp;nbsp;인자로&amp;nbsp;컴포넌트를&amp;nbsp;받아들이고,&amp;nbsp;새로운&amp;nbsp;컴포넌트를&amp;nbsp;반환합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;로직&amp;nbsp;분리:&amp;nbsp;&lt;/b&gt;HOC를&amp;nbsp;사용하여&amp;nbsp;여러&amp;nbsp;컴포넌트에서&amp;nbsp;중복되는&amp;nbsp;로직을&amp;nbsp;분리하여&amp;nbsp;재사용할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;예를&amp;nbsp;들어,&amp;nbsp;인증,&amp;nbsp;권한&amp;nbsp;관리,&amp;nbsp;로깅&amp;nbsp;등과&amp;nbsp;같은&amp;nbsp;기능을&amp;nbsp;여러&amp;nbsp;컴포넌트에서&amp;nbsp;공통으로&amp;nbsp;사용하려고&amp;nbsp;할&amp;nbsp;때&amp;nbsp;HOC를&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;컴포넌트&amp;nbsp;감싸기:&lt;/b&gt; HOC는 원본 컴포넌트를 감싸는 형태로 동작합니다. 이로 인해 기존 컴포넌트의 기능을 확장하거나 수정할 수 있습니다. 인자 전달: HOC는 인자를 전달하여 컴포넌트에 추가 데이터나 기능을 제공할 수 있습니다. 이를 통해 컴포넌트 간의 상호작용을 구현할 수 있습니다. 명명 규칙: 보통 HOC는 이름 앞에 &quot;with&quot;를 붙여 명명됩니다. 예를 들어, withDoSomething 와 같은 이름을 가질 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;컴포지션:&lt;/b&gt;&amp;nbsp;여러&amp;nbsp;HOC를&amp;nbsp;함께&amp;nbsp;사용하여&amp;nbsp;여러&amp;nbsp;개의&amp;nbsp;기능을&amp;nbsp;한&amp;nbsp;컴포넌트에&amp;nbsp;적용할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이러한&amp;nbsp;컴포지션은&amp;nbsp;컴포넌트&amp;nbsp;간의&amp;nbsp;강력한&amp;nbsp;로직&amp;nbsp;재사용을&amp;nbsp;가능케&amp;nbsp;합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;HOC를 사용하면 여러 컴포넌트 간에 공통으로 사용되는 코드를 중앙에서 관리할 수 있어 유지보수성이 향상되고, 코드 중복을 줄일 수 있습니다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한&amp;nbsp;HOC는&amp;nbsp;상속을&amp;nbsp;사용하지&amp;nbsp;않고도&amp;nbsp;컴포넌트의&amp;nbsp;기능을&amp;nbsp;확장하거나&amp;nbsp;수정할&amp;nbsp;수&amp;nbsp;있어&amp;nbsp;유연한&amp;nbsp;코드를&amp;nbsp;작성하는&amp;nbsp;데&amp;nbsp;도움이&amp;nbsp;됩니다.&amp;nbsp;리액트&amp;nbsp;훅의&amp;nbsp;도입으로&amp;nbsp;함수형&amp;nbsp;컴포넌트에서도&amp;nbsp;상태&amp;nbsp;관리와&amp;nbsp;사이드&amp;nbsp;이펙트&amp;nbsp;처리가&amp;nbsp;용이해져서&amp;nbsp;클래스&amp;nbsp;컴포넌트를&amp;nbsp;대체하는&amp;nbsp;경우가&amp;nbsp;많아졌지만,&amp;nbsp;HOC는&amp;nbsp;여전히&amp;nbsp;유용한&amp;nbsp;상황이&amp;nbsp;있을&amp;nbsp;수&amp;nbsp;있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;규모가 큰 애플리케이션에서 state와&amp;nbsp; setState 를 호출하는 동일한 패턴이 반복적으로 발생한다고 가정해봅시다. 그렇게 된다면 이 로직을 한 곳에서 정의하고 많은 컴포넌트에서 로직을 공유할 수 있게 하는 추상화가 필요하게 됩니다.&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;&lt;i&gt;이러한 경우에 고차 컴포넌트를 사용하면 좋습니다.&lt;/i&gt; &lt;a href=&quot;https://ko.legacy.reactjs.org/docs/higher-order-components.html#dont-mutate-the-original-component-use-composition&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;from React 공식문서&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예시&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;HOC 패턴의 이해를 돕기 위해 직접 코드로 간단한 예시를 만들어봤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;HOC 패턴은 클래스형 컴포넌트와 함수형 컴포넌트 둘다 가능하지만 , hooks의 사용을 편하게 하기위해 함수형으로 예제로 준비해봤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래의 두가지 코드는 간단히 num state를 increseNum 이란 함수를 통해서 +1 씩 증가시키는 간단한 예제입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제목이 First, Second 라는 것만 다르고 , 로직과 UI는 똑같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Before applying HOC&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1692328131144&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//Frist.tsx


import { useState } from &quot;react&quot;

export default function Frist() {

  const [num, setNum] = useState&amp;lt;number&amp;gt;(0);

  const increaseNum = () =&amp;gt; {
    setNum(prev =&amp;gt; prev + 1)
  }

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;First / {num}&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={increaseNum}&amp;gt;Increase First Number&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692328155570&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Second.tsx

import { useState } from &quot;react&quot;;

export default function Second() {

  const [num, setNum] = useState&amp;lt;number&amp;gt;(0);

  const increaseNum = () =&amp;gt; {
    setNum(prev =&amp;gt; prev + 1)
  }

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;SECOND / {num}&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={increaseNum}&amp;gt;Increase Second Number&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이렇게 비슷한 로직을 추가로 컴포넌트를 통해 구현을 해야할때, 지금은 두개라서 useState와 setState의 로직을 하나씩 작성해줬지만 만약에 10개,100개가 넘어가면 중복성이 너무 심할것같다는 생각이 들건데요.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 &lt;b&gt;인자&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;로&amp;nbsp;&lt;/span&gt;&lt;b&gt;컴포넌트를&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;받아들이고,&amp;nbsp;&lt;/span&gt;&lt;b&gt;새로운 컴포넌트를 반환해서,&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt; 컴포넌트 재사용성이 높은 HOC 패턴을 이용해 중복로직을&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;줄여보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;아래와 같이 HOC.tsx 파일을 하나 만들고 위의 num 을 증가시키는 로직 (num state 와 increase 함수)를 작성해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;여기서 중요한것은 HigherOrderComponent의 인자로는 나중에 Wrapping할 컴포넌트를 전달 해준다는 것 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1692328424666&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// HOC.tsx

import React, { useState } from 'react'

interface CounterProps {
  num: number;
  increaseNum: () =&amp;gt; void;
}

const WithHihgerOrderComponent = (Counter: React.ComponentType&amp;lt;CounterProps&amp;gt;) =&amp;gt; {
  const HigherOrderComInner = () =&amp;gt; {
    const [num, setNum] = useState(0);
    const increaseNum = () =&amp;gt; {
      setNum(prev =&amp;gt; prev + 1)
    }
    return (
      &amp;lt;Counter num={num} increaseNum={increaseNum}/&amp;gt;
    )
  }
  return HigherOrderComInner;
}

export default WithHihgerOrderComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 Frist , Second 컴포넌트에서 HigherOrderComponent로 감싸주기만 한다면 기능은 똑같이 작동합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그전에 , 기존에 First, Second 컴포넌트에서 중복되었는 useState 와 increaseNum의 함수를 HOC에서 컨트롤 하고 있으니&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저 지워준뒤 , HOC에서 전달받은 props로 num의 state 와 increaseNum 으로 기능 구현을 해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;After applying HOC&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1692328886780&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// After wrapping HOC First.tsx

import WithHihgerOrderComponent from &quot;./HOC&quot;;

interface CounterProps {
  num: number;
  increaseNum: () =&amp;gt; void;
}

function First({num,increaseNum}:CounterProps) {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;SECOND / {num}&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={increaseNum}&amp;gt;Increase Second Number&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default WithHihgerOrderComponent(First);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692329024525&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// After wrapping HOC Second.tsx

import WithHihgerOrderComponent from &quot;./HOC&quot;;

interface CounterProps {
  num: number;
  increaseNum: () =&amp;gt; void;
}

function Second({num,increaseNum}:CounterProps) {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;SECOND / {num}&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={increaseNum}&amp;gt;Increase Second Number&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default WithHihgerOrderComponent(Second);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예시2&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 예시는 jsonplaceholder dummy api 를 이용해 user 리스트와 todo 리스트를 갖고오는 컴포넌트를 하나씩 생성해서 데이터를 불러와보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 예제 역시 불러오는 api 엔드포인트만 다르고 모든 로직 및 UI 는 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Before applying HOC&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1692329768731&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// User.tsx

import { useEffect, useState } from &quot;react&quot;

interface UserItem {
  id:number;
  name:string;
  username:string;
  email:string;
}

export default function User() {

  const [user, setUser] = useState&amp;lt;UserItem[]&amp;gt;([]);

  useEffect(() =&amp;gt; {
    const getData = async () =&amp;gt; {
      const data = await fetch('https://jsonplaceholder.typicode.com/users');
      const json = await data.json();
      setUser(json);

    };
    getData();
  }, []);

  console.log(user);
  
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Users&amp;lt;/h1&amp;gt;
      &amp;lt;ul&amp;gt;
        {user?.slice(0, 10).map((user) =&amp;gt; (
          &amp;lt;li key={user.id}&amp;gt;{user.name}&amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692329809129&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Todo.tsx

import { useEffect, useState } from &quot;react&quot;

interface TodoItem {
  userId: number;
  id: number;
  title: string;
  completed: boolean;
}

export default function Todo() {

  const [todo, setTodo] = useState&amp;lt;TodoItem[]&amp;gt;([]);

  useEffect(() =&amp;gt; {
    const getData = async () =&amp;gt; {
      const data = await fetch('https://jsonplaceholder.typicode.com/todos');
      const json = await data.json();
      setTodo(json);

    };
    getData();
  }, [])
  
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;To do&amp;lt;/h1&amp;gt;
      &amp;lt;ul&amp;gt;
        {todo?.slice(0, 10).map((todo) =&amp;gt; (
          &amp;lt;li key={todo.id}&amp;gt;{todo.title}&amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위와 코드는 api 엔드포인트만 다르죠? User 컴포넌트는 users , Todo 컴포넌트는 todos 를 통해 각 데이터를 호출 하고있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;useEffect를 통해 데이터를 빈 state에 setState를 통해 데이터를 채워주는 로직이 똑같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위의 코드를 HOC 패턴을 이용해 코드의 중복성을 줄이고 재사용성을 높여 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-18 오후 12.58.32.png&quot; data-origin-width=&quot;1313&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Ng2T/btsrAQ3TuE7/yBdAq8Hio0n2lomBKb01Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Ng2T/btsrAQ3TuE7/yBdAq8Hio0n2lomBKb01Fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Ng2T/btsrAQ3TuE7/yBdAq8Hio0n2lomBKb01Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Ng2T%2FbtsrAQ3TuE7%2FyBdAq8Hio0n2lomBKb01Fk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1313&quot; height=&quot;439&quot; data-filename=&quot;스크린샷 2023-08-18 오후 12.58.32.png&quot; data-origin-width=&quot;1313&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위의 예제와 완전 똑같지만 , API 의 endpoint를 동적으로 받아와야하기 때문에 인자에 endpoint를 하나 더 생성 해줬습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;HOC 컴포넌트의 list의 api 호출한 결과값을 데이터에 담고 props로 전달해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1692330221856&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// HOC.tsx

import React, { useEffect, useState } from 'react';

export interface UserItem {
  id: number;
  name: string;
}

export interface TodoItem {
  id:number;
  title:string;
}

export interface ListProps&amp;lt;T&amp;gt; {
  list: T[];
}

const WithHihgerOrderComponent = &amp;lt;T extends UserItem | TodoItem&amp;gt;(
  DataList: React.ComponentType&amp;lt;ListProps&amp;lt;T&amp;gt;&amp;gt;,
  endpoint: string
) =&amp;gt; {
  const HigherOrderComponentInner = () =&amp;gt; {
    const [list, setList] = useState&amp;lt;T[]&amp;gt;([]);

    useEffect(() =&amp;gt; {
      const getData = async () =&amp;gt; {
        const data = await fetch(`https://jsonplaceholder.typicode.com/${endpoint}`);
        const json = await data.json();
        setList(json);
      };
      getData();
    }, []);

    return &amp;lt;DataList list={list} /&amp;gt;;
  };
  return HigherOrderComponentInner;
};

export default WithHihgerOrderComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;After applying HOC&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1692330319351&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Todo.tsx

import WithHihgerOrderComponent, { ListProps, TodoItem } from &quot;./HOC&quot;

function Todo({list}:ListProps&amp;lt;TodoItem&amp;gt;) {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;To do&amp;lt;/h1&amp;gt;
      &amp;lt;ul&amp;gt;
        {list.slice(0, 10).map((todo) =&amp;gt; (
          &amp;lt;li key={todo.id}&amp;gt;{todo.title}&amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default WithHihgerOrderComponent(Todo,'todos')&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692330385849&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// User.tsx

import WithHihgerOrderComponent, { ListProps, UserItem } from &quot;./HOC&quot;

function User({ list }:ListProps&amp;lt;UserItem&amp;gt;) {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;User&amp;lt;/h1&amp;gt;
      &amp;lt;ul&amp;gt;
        {list.slice(0, 10).map((user) =&amp;gt; (
          &amp;lt;li key={user.id}&amp;gt;{user.name}&amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export default WithHihgerOrderComponent(User, 'users')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;HOC를 적용하고나서의 화면&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-08-18 오후 12.58.32.png&quot; data-origin-width=&quot;1313&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Ng2T/btsrAQ3TuE7/yBdAq8Hio0n2lomBKb01Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Ng2T/btsrAQ3TuE7/yBdAq8Hio0n2lomBKb01Fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Ng2T/btsrAQ3TuE7/yBdAq8Hio0n2lomBKb01Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Ng2T%2FbtsrAQ3TuE7%2FyBdAq8Hio0n2lomBKb01Fk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1313&quot; height=&quot;439&quot; data-filename=&quot;스크린샷 2023-08-18 오후 12.58.32.png&quot; data-origin-width=&quot;1313&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;같은 로직과 같은 UI가 중복된점이 있으면 HOC를통해 보다 나은 (유지보수성) 을 고려하면서 코드를 짤 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;HigherOrderComponent의 두번째 인자로 API endpoint를 넣어서 하나의 컴포넌트에서 동적으로 데이터를 받아옴으로서 재사용성이 높은, 중복을 줄일 수 있는 코드를 작성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;HOC&amp;nbsp;패턴을&amp;nbsp;사용하면&amp;nbsp;코드의&amp;nbsp;재사용성,&amp;nbsp;모듈화,&amp;nbsp;분리된&amp;nbsp;관심사,&amp;nbsp;컴포지션&amp;nbsp;등&amp;nbsp;여러&amp;nbsp;가지&amp;nbsp;장점을&amp;nbsp;얻을&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이로&amp;nbsp;인해&amp;nbsp;코드의&amp;nbsp;유지보수성과&amp;nbsp;가독성이&amp;nbsp;향상되며,&amp;nbsp;확장&amp;nbsp;가능한&amp;nbsp;애플리케이션을&amp;nbsp;개발할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;잘못된 부분이 있으면 언제든지 알려주시길 바랍니다. :)&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;</description>
      <category>front-end/React</category>
      <category>hoc</category>
      <category>React</category>
      <category>고차컴포넌트</category>
      <category>리액트</category>
      <category>리액트 디자인패턴</category>
      <category>유지보수</category>
      <category>프론트엔드</category>
      <author>code walker</author>
      <guid isPermaLink="true">https://fe-kwangmin.tistory.com/50</guid>
      <comments>https://fe-kwangmin.tistory.com/50#entry50comment</comments>
      <pubDate>Fri, 18 Aug 2023 12:49:32 +0900</pubDate>
    </item>
    <item>
      <title>[React]When to use UseMemo and useCallback (feat:memo) / useCallback 편</title>
      <link>https://fe-kwangmin.tistory.com/48</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;리액트로 프론트 개발을 하다면 useMemo , useCallback 과 같은 컴포넌트 렌더링 최적화 훅을 한번쯤은 들어봤을텐데요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저는 솔직히 지금까지 제일 헷갈리는것 같습니다. 왜냐하면 렌더링 최적화 훅이라고 해도 그냥 막 사용하면 오히려 최적화가 아니라&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;성능에 안좋을 수 있어서, 상황에 맞게 잘 써야합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;메모이제이션&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우선 useCallback 과 useMemo를 사용하기 위해선 &quot;&lt;span style=&quot;color: #8e8b87; text-align: start; --darkreader-inline-color: #76726b;&quot; data-darkreader-inline-color=&quot;&quot;&gt;메모제이션&quot;&lt;/span&gt; 이란 단어를 필수로 짚고 넘어가야합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; --darkreader-inline-color: #9f9e9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot; data-darkreader-inline-color=&quot;&quot;&gt;메모제이션(memoziaiton)은 expensive 한 함수 호출 결과를 캐싱하고 같은 입력이 재발생 될때 캐싱된 결과를 그대로 반환하는&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; --darkreader-inline-color: #9f9e9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot; data-darkreader-inline-color=&quot;&quot;&gt;프로그래밍 기술 입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; --darkreader-inline-color: #9f9e9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot; data-darkreader-inline-color=&quot;&quot;&gt;리액트 함수형 컴포넌트에서 동일한 입력으로 여러번 호출 되는 상황이 꽤 많습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; --darkreader-inline-color: #9f9e9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot; data-darkreader-inline-color=&quot;&quot;&gt;이때 리액트에서 메모이제이션을 사용할때 useMemo , useCallback 훅을 사용해서 렌더링 최적화 및 성능 상향을 시킬 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;useMemo 와 useCallback을 배우기전에 알아야 하는것&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 우선 리액트 함수형 컴포넌트는 단지 jsx 를 반환하는 함수 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 컴포넌트가 렌더링 된다는것은 컴포넌트(함수)를 호출이 되서 실행이 되고 , 자바스크립트의 함수는 실행 될때마다 내부에 선언되어있던 변수가 매번 다시 선언 되어 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 함수형 컴포넌트는 자신의 state가 변경되고, 자식컴포넌트 경우 부모컴포넌트의 state가 변경 되어도 리렌더링(재호출)이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;useMemo :&lt;b&gt;메모이제이션 된 값을 반환합니다.&lt;/b&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;useCallback :&lt;b&gt;메모이제이션 된 함수를 반환합니다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 자바스크립트의 기초가 있다면 참조타입의 함수나 객체 배열은 아래와 같이 작동합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691566679669&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let dog1 = func(){console.log('14/10')}; // has a unique object reference
let dog2 = func(){console.log('14/10')}; // has a unique object reference

dog1 === dog2; // false

let arr = [1,2,3]
let arr2 = [1,2,3]

arr === arr2 // false;

const obj = {name:'kwangmin'}
const obj2 = {name:'kwangmin'}

obj === obj2 // false;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;헷갈리지 말아야할게 변수에 할당된 객체가 직접 다른 변수에 할당된 경우 참조가 일치할 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691566789413&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let dog1 = func(){console.log('14/10')}; // has a unique object reference
let dog2 = dog1;  // assign the unique object reference of dog1 to a variable named dog2

// dog1 and dog2 point to same object reference
dog1 === dog2; // true

let arr = [1,2,3,4];
let arr2 = arr;

arr === arr2 // true

const obj = {name:'kwangmin'};
const obj2 = obj;

obj === obj2 // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start; --darkreader-inline-color: #78736d;&quot; data-darkreader-inline-color=&quot;&quot;&gt;UseCallback&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #76726b; text-align: start; --darkreader-inline-color: #78736d;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start; --darkreader-inline-color: #78736d;&quot; data-darkreader-inline-color=&quot;&quot;&gt;그럼 useCallback 언제 어떻게 사용하는지 알아보겠습니다.&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start; --darkreader-inline-color: #78736d;&quot; data-darkreader-inline-color=&quot;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start; --darkreader-inline-color: #78736d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot; data-darkreader-inline-color=&quot;&quot;&gt;ParentComponent라는 컴포넌트를 생성해 보겠습니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;이 컴포넌트에는 age와 salary라는 상태(state) 그리고 다음과 같은 함수들이 있습니다&lt;/b&gt;&lt;br /&gt;1. incrementAge(): &quot;나이 증가&quot; 버튼을 클릭하면 나이를 1 증가시킵니다.&lt;br /&gt;2. incrementSalary(): &quot;급여 증가&quot; 버튼을 클릭하면 급여를 1000 Rs 증가시킵니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ParentComponent는 다음과 같이 3개의 자식 컴포넌트를 가지고 있습니다.&lt;/b&gt;&lt;br /&gt;1. &amp;lt;Title&amp;gt;: 페이지 제목을 렌더링합니다.&lt;br /&gt;2. &amp;lt;Count&amp;gt;: 페이지에 나이나 급여를 표시합니다. &lt;br /&gt;3. &amp;lt;Button&amp;gt;: 나이와 급여를 증가시키기 위한 버튼입니다. 이 세가지 컴포넌트 모두 컴포넌트가 재렌더링될 때마다 로그 문장을 추가하여 결과를 확인할 수 있도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #231f20; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Code Snippet&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1691567754936&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// App.tsx
import ParentComponent from &quot;./components/ParentComponet&quot;;

export default function App() {
  return (
    &amp;lt;ParentComponent/&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1691567786255&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ParentComponet.tsx

import React, { useState } from 'react';
import Button from './Button';
import Title from './title';
import Count from './Count';
function ParentComponent() {
  const [age, setAge] = useState(25);
  const [salary, setSalary] = useState(25000)
  const incrementAge = () =&amp;gt; {
    setAge((prev =&amp;gt; prev +1));
  }
  const incrementSalary = () =&amp;gt; {
    setSalary(prev =&amp;gt; prev + 10000);
  }
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Title /&amp;gt;
      &amp;lt;Count text=&quot;age&quot; count={age} /&amp;gt;
      &amp;lt;Button handleClick={incrementAge}&amp;gt;Increment my age&amp;lt;/Button&amp;gt;
      &amp;lt;Count text=&quot;salary&quot; count={salary} /&amp;gt;
      &amp;lt;Button handleClick={incrementSalary}&amp;gt;Increment my salary&amp;lt;/Button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
export default ParentComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1691567810161&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Button.tsx
import React from 'react';

function Button(props:any) {
  console.log(`Button clicked ${props.children}`);
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={props.handleClick}&amp;gt; {props.children} &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
export default Button;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1691567827509&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Count.tsx
import React from 'react';

function Count(props:any) {
  console.log(&quot;Count rendering&quot;);
  return (
    &amp;lt;div&amp;gt;
      {props.text} is {props.count}
    &amp;lt;/div&amp;gt;
  );
}
export default Count;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1691567851931&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Title.tsx

export default function Title() {
console.log(&quot;Title is rendering.&quot;)
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;useCallBack hook&amp;lt;/h2&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; text-align: start;&quot;&gt;incrementAge &lt;/span&gt;&amp;nbsp;버튼을 클릭하면 나이가 25에서 26으로 증가합니다. 그러나 콘솔에서 확인해보면 모든 컴포넌트가 다시 호출되었습니다나이가 성공적으로 증가되었음을 볼 수 있지만, 다른 모든 컴포넌트도 매번 재렌더링되었고, 그렇게 되면 안되겠죠?&lt;br /&gt;App에서 변경된 것은 나이 상태 뿐입니다. 그럼에도 불구하고 모든 리액트 컴포넌트가 변경 여부와 관계없이 재렌더링됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제에서 나이를 증가시킬 때는 두 가지만 다시 렌더링되어야 합니다. 나이와 관련된 Count 컴포넌트. 나이를 증가시키는 Button 컴포넌트. 다른 세 가지 로그 문장은 다시 렌더링될 필요가 없습니다. 급여 역시 마찬가지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;급여를 증가시키면 제목과 나이 컴포넌트가 다시 렌더링되지 않아야 합니다. 그렇다면 어떻게 이를 최적화할 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 답은 React.memo() 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;React.memo란?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React.memo는 함수형 컴포넌트의 부모 컴포넌트로부터 전달받은 props나 상태state 변경되지 않는 한 해당 컴포넌트의 재렌더링을 방지하는 고차 컴포넌트(HOC)입니다. React.memo()는 훅과 아무 관련이 없다는 것을 염두에 두시기 바랍니다. 이 기능은 리액트 버전 16.6부터 제공되었으며, 클래스 컴포넌트에서는 이미 PureComponent 또는 shouldComponentUpdate를 사용하여 재렌더링을 제어할 수 있었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;아래와 같이 예제에서 React.memo()를 활용해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;memo로 래핑을 해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1691569930027&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default React.memo(Button); 
export default React.memo(Count); //Count.js
export default React.memo(Title); //Title.js&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제&amp;nbsp;해당&amp;nbsp;컴포넌트는&amp;nbsp;상태(state)나&amp;nbsp;프롭스(props)에&amp;nbsp;변경이&amp;nbsp;있을&amp;nbsp;때만&amp;nbsp;재렌더링됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 잘 작동하는지 테스트해보죠. 그러나 여전히 안됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저에서 페이지를 로드하면 처음에는 5개의 로그가 모두 나타납니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이제 incrementAge() 를 클릭한 후, 로그가 적어진 것을 볼 수 있습니다. 그럼에도 불구하고 아직 완벽하지 않습니다. 나이를 증가시키면 급여 증가 버튼이 여전히 재렌더링되고, 급여를 증가시키면 나이 증가 버튼이 재렌더링됩니다. &lt;br /&gt;이런 일이 일어나는 이유를 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Title 컴포넌트는 자체 state나 props가 없으므로 리렌더링되지 않습니다. Count는 나이를 props로 받고, 버튼은 incrementAge()를 props로 받으며 이것은 나이에 의존적입니다. 그래서 둘 다 재렌더링됩니다. 그런데 우리가 볼 수 있는 것은 incrementSalary 버튼도 재렌더링됩니다. 왜일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;급여에 대한 count 컴포넌트는 재렌더링되지 않습니다. 이는 부모 컴포넌트가 재렌더링될 때마다 새로운 incrementSalary 함수가 생성되기 때문입니다. 함수를 다룰 때는 항상 참조 동등성을 고려해야 합니다. 두 함수가 완전히 동일한 동작을 하더라도 서로 같다는 것을 의미하지 않습니다. 그래서 리렌더링 전의 함수와 리렌더링 후의 함수는 다릅니다. 그리고 함수인 handleClick이 props이기 때문에, React.memo는 프롭스가 변경되었다고 판단하고 재렌더링을 막지 않습니다. 그래서 3개의 로그가 남게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서&amp;nbsp;이제&amp;nbsp;React에게&amp;nbsp;매번&amp;nbsp;incrementSalary&amp;nbsp;함수를&amp;nbsp;생성할&amp;nbsp;필요가&amp;nbsp;없다는&amp;nbsp;것을&amp;nbsp;알려야&amp;nbsp;합니다.&amp;nbsp;그&amp;nbsp;답은&amp;nbsp;useCallback&amp;nbsp;훅입니다.&amp;nbsp;useCallback&amp;nbsp;훅은&amp;nbsp;incrementSalary&amp;nbsp;함수를&amp;nbsp;캐시하고,&amp;nbsp;급여가&amp;nbsp;증가되지&amp;nbsp;않는&amp;nbsp;경우&amp;nbsp;해당&amp;nbsp;함수를&amp;nbsp;반환합니다.&amp;nbsp;급여가&amp;nbsp;변경될&amp;nbsp;경우에만&amp;nbsp;새로운&amp;nbsp;함수가&amp;nbsp;반환됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691570360604&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const incrementAge = useCallback(() =&amp;gt; {
    setAge(prev =&amp;gt; prev + 1);
  }, [age]);

  const incrementSalary = useCallback(() =&amp;gt; {
    setSalary(prev =&amp;gt; prev + 10000);
  }, [salary]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 자식 컴포넌트가 React.memo() 같은 것으로 최적화 되어 있고 그 자식 컴포넌트에게 callback 함수를 props로 넘길 때, 상위 컴포넌트에서 useCallback 으로 함수를 선언하는 것이 유용하다라는 의미이다. 함수가 매번 재선언되면 자식 컴포넌트는 넘겨 받은 함수가 달라졌다고 인식하기 때문이다. React.memo()로 함수형 컴포넌트 자체를 감싸면 넘겨 받는 props가 변경되지 않았을 때는 상위 컴포넌트가 메모리제이션된 함수형 컴포넌트(이전에 렌더링된 결과)를 사용하게 된다. 함수는 오로지 자기 자신만이 동일하기 때문에 상위 컴포넌트에서 callback 함수를 (같은 함수이더라도) 재선언한다면 props로 callback 함수를 넘겨 받는 하위 컴포넌트 입장에서는 props가 변경 되었다고 인식한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;when-should-you-not-use-the-usecallback-hook&quot; style=&quot;background-color: #ffffff; color: #070e27; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;When should you not use the useCallback hook&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useCallback&amp;nbsp;훅을&amp;nbsp;모든&amp;nbsp;참조&amp;nbsp;동등성&amp;nbsp;문제를&amp;nbsp;해결하기&amp;nbsp;위해&amp;nbsp;사용해서는&amp;nbsp;안&amp;nbsp;됩니다.&amp;nbsp;매번&amp;nbsp;재선언을&amp;nbsp;피하는&amp;nbsp;좋은&amp;nbsp;해결책처럼&amp;nbsp;보일&amp;nbsp;수&amp;nbsp;있지만,&amp;nbsp;여기서&amp;nbsp;주의할&amp;nbsp;점은&amp;nbsp;메모이제이션이&amp;nbsp;일부&amp;nbsp;데이터를&amp;nbsp;메모리에&amp;nbsp;저장하는&amp;nbsp;기술임을&amp;nbsp;염두에&amp;nbsp;두어야&amp;nbsp;합니다.&amp;nbsp;애플리케이션의&amp;nbsp;모든&amp;nbsp;부분을&amp;nbsp;메모이제이션하는&amp;nbsp;것은&amp;nbsp;더&amp;nbsp;많은&amp;nbsp;메모리&amp;nbsp;리소스를&amp;nbsp;사용하며,&amp;nbsp;이로&amp;nbsp;인해&amp;nbsp;애플리케이션의&amp;nbsp;성능에&amp;nbsp;부정적인&amp;nbsp;영향을&amp;nbsp;미칠&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.memberstack.com/blog/using-usecallback&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.memberstack.com/blog/using-usecallback&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691571419961&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Using useCallback Hook in React &amp;mdash; A Developer's Guide | Memberstack Blog&quot; data-og-description=&quot; &quot; data-og-host=&quot;www.memberstack.com&quot; data-og-source-url=&quot;https://www.memberstack.com/blog/using-usecallback&quot; data-og-url=&quot;https://www.memberstack.com/blog/using-usecallback&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.memberstack.com/blog/using-usecallback&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.memberstack.com/blog/using-usecallback&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Using useCallback Hook in React &amp;mdash; A Developer's Guide | Memberstack Blog&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.memberstack.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kentcdodds.com/blog/usememo-and-usecallback&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kentcdodds.com/blog/usememo-and-usecallback&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691571431141&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;When to useMemo and useCallback&quot; data-og-description=&quot;Stay up to date Subscribe to the newsletter to stay up to date with articles, courses and much more! Learn more Stay up to date Subscribe to the newsletter to stay up to date with articles, courses and much more! Learn more All rights reserved &amp;copy; Kent C. D&quot; data-og-host=&quot;kentcdodds.com&quot; data-og-source-url=&quot;https://kentcdodds.com/blog/usememo-and-usecallback&quot; data-og-url=&quot;https://kentcdodds.com/blog/usememo-and-usecallback&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bQGoDZ/hyTBD3VF55/Kf1ND4AOcPrxR2Xzyn31C0/img.jpg?width=1517&amp;amp;height=1011&amp;amp;face=730_621_817_715,https://scrap.kakaocdn.net/dn/bQZGm5/hyTBD3VF9q/tnPqT6qkWyWiNbakE1qvQ1/img.png?width=1331&amp;amp;height=1054&amp;amp;face=0_0_1331_1054&quot;&gt;&lt;a href=&quot;https://kentcdodds.com/blog/usememo-and-usecallback&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kentcdodds.com/blog/usememo-and-usecallback&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bQGoDZ/hyTBD3VF55/Kf1ND4AOcPrxR2Xzyn31C0/img.jpg?width=1517&amp;amp;height=1011&amp;amp;face=730_621_817_715,https://scrap.kakaocdn.net/dn/bQZGm5/hyTBD3VF9q/tnPqT6qkWyWiNbakE1qvQ1/img.png?width=1331&amp;amp;height=1054&amp;amp;face=0_0_1331_1054');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;When to useMemo and useCallback&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Stay up to date Subscribe to the newsletter to stay up to date with articles, courses and much more! Learn more Stay up to date Subscribe to the newsletter to stay up to date with articles, courses and much more! Learn more All rights reserved &amp;copy; Kent C. D&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kentcdodds.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>front-end/React</category>
      <category>frontend</category>
      <category>React</category>
      <category>react-hook</category>
      <category>useCallback</category>
      <category>useMemo</category>
      <author>code walker</author>
      <guid isPermaLink="true">https://fe-kwangmin.tistory.com/48</guid>
      <comments>https://fe-kwangmin.tistory.com/48#entry48comment</comments>
      <pubDate>Wed, 9 Aug 2023 17:57:24 +0900</pubDate>
    </item>
  </channel>
</rss>