<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>이안의 평일코딩</title>
    <link>https://iancoding.tistory.com/</link>
    <description>I'm Ian here, a junior Front-end developer using React. ✨
I think both learning and playing are important. ✨</description>
    <language>ko</language>
    <pubDate>Wed, 12 Aug 2026 14:55:11 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>이안92</managingEditor>
    <image>
      <title>이안의 평일코딩</title>
      <url>https://tistory1.daumcdn.net/tistory/3997533/attach/2be464e7466c4ff7b13761777b1a3c5c</url>
      <link>https://iancoding.tistory.com</link>
    </image>
    <item>
      <title>리액트 19: 새로운 프론트엔드 시대를 여는 기능 정리</title>
      <link>https://iancoding.tistory.com/363</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beieP9/btsNX23jVih/VCt6I4iaXpFDzRVvr94ZY1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beieP9/btsNX23jVih/VCt6I4iaXpFDzRVvr94ZY1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beieP9/btsNX23jVih/VCt6I4iaXpFDzRVvr94ZY1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeieP9%2FbtsNX23jVih%2FVCt6I4iaXpFDzRVvr94ZY1%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;200&quot; height=&quot;216&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  React v19&lt;/blockquote&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 19는 단순한 기능 추가를 넘어, React 개발 방식에 큰 변화를 가져올 여러 실험적 기능들을 공식화했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서버 중심의 렌더링 철학&lt;/b&gt;, &lt;b&gt;자동화된 성능 최적화&lt;/b&gt;, &lt;b&gt;간결한 API 설계&lt;/b&gt;로 한 단계 도약한 모습을 보여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 저는 커스텀 훅을 사내에서 자주 만들어 사용하는 편이라 익숙하게 Migration 가능할 것 같은데요.&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;blockquote data-ke-style=&quot;style2&quot;&gt;  React Compiler&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 컴파일러는 &lt;b&gt;자동으로 useMemo, useCallback 최적화를 수행&lt;/b&gt;해주는 새로운 도구입니다.&lt;br /&gt;더 이상 불필요한 메모이제이션에 신경 쓰지 않아도 되는 시대가 왔습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747265373243&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function ProductPage({ productId }) {
  const product = useProduct(productId); // 내부적으로 캐시 최적화됨
  return &amp;lt;Product {...product} /&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  use() Hooks&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;use()는 비동기 데이터를 &lt;b&gt;컴포넌트 안에서 직접 await&lt;/b&gt;할 수 있도록 도와주는 새로운 hook입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Server Component에서만 사용 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747265429541&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function ProductPage() {
  const product = use(fetchProduct());
  return &amp;lt;Product {...product} /&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;⚡ Actions&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React의 새로운 &lt;b&gt;폼 액션 핸들링 방식&lt;/b&gt;입니다. 서버 함수와 클라이언트가 자연스럽게 연결됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747265459767&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use server';

export async function createTodo(data) {
  await db.insert(data);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1747265474971&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;form action={createTodo}&amp;gt;
  &amp;lt;input name=&quot;task&quot; /&amp;gt;
  &amp;lt;button type=&quot;submit&quot;&amp;gt;Create&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  use client &amp;amp; use server&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 19에서는 컴포넌트 파일 최상단에 'use client' 또는 'use server'를 선언하여 &lt;b&gt;렌더링 위치를 명시&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 &lt;b&gt;서버 컴포넌트와 클라이언트 컴포넌트 간 역할을 명확히 구분&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  useFormStatus &amp;amp; useActionState&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React의 새로운 form 관련 Hook들입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1624&quot; data-start=&quot;1544&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1585&quot; data-start=&quot;1544&quot;&gt;useFormStatus &amp;rarr; submit 중인지 여부를 알려줍니다.&lt;/li&gt;
&lt;li data-end=&quot;1624&quot; data-start=&quot;1586&quot;&gt;useActionState &amp;rarr; 서버 액션의 상태를 관리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1747265558327&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [state, formAction] = useActionState(createTodo, initialState);

&amp;lt;form action={formAction}&amp;gt;
  &amp;lt;SubmitButton /&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  useOptimistic&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;낙관적 UI 업데이트&lt;/b&gt;를 위한 Hook입니다. 사용자 인터랙션에 대해 빠른 피드백을 줄 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747265628566&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [todos, addTodo] = useOptimistic([], (state, newTodo) =&amp;gt; [...state, newTodo]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  Document Metadata&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에서 &lt;b&gt;title, meta, viewport&lt;/b&gt; 등을 구성하는 새로운 API가 도입됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747265690799&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'My Page',
  description: 'Awesome page',
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;⛓️ ForwardRef&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 19에서는 forwardRef 없이도 &lt;b&gt;자동 ref 전달&lt;/b&gt;이 가능해질 예정입니다.&lt;br /&gt;보다 간단한 컴포넌트 작성이 가능해집니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747265857439&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Button(props, ref) {
  return &amp;lt;button ref={ref} {...props} /&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  React.Lazy&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React.lazy()는 여전히 존재하지만, React 19에서는 Server Component 기반으로 더 나은 lazy-loading 전략이 가능해졌습니다.&lt;br /&gt;대부분의 경우 &lt;b&gt;서버 렌더링이 더 나은 UX&lt;/b&gt;를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  &amp;lt;Context.Provider&amp;gt; =&amp;gt; &amp;lt;Context&amp;gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context API도 더욱 간단하게 사용할 수 있게 되었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747265884838&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 기존
&amp;lt;MyContext.Provider value={value}&amp;gt;
  &amp;lt;App /&amp;gt;
&amp;lt;/MyContext.Provider&amp;gt;

// React 19
&amp;lt;Context value={value}&amp;gt;
  &amp;lt;App /&amp;gt;
&amp;lt;/Context&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Front-end/React</category>
      <category>actions</category>
      <category>react compiler</category>
      <category>react19</category>
      <category>use client</category>
      <category>use server</category>
      <category>use()</category>
      <category>useactionstate</category>
      <category>useformstatus</category>
      <category>useoptimistic</category>
      <category>리액트19</category>
      <author>이안92</author>
      <guid isPermaLink="true">https://iancoding.tistory.com/363</guid>
      <comments>https://iancoding.tistory.com/363#entry363comment</comments>
      <pubDate>Thu, 15 May 2025 08:24:36 +0900</pubDate>
    </item>
    <item>
      <title>리액트 18: 무엇이 달라졌나? 요약 및 간략 후기</title>
      <link>https://iancoding.tistory.com/362</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vw51W/btsNCvFc4Ju/hTjBrLoW7a1g5BNZfXLHNk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vw51W/btsNCvFc4Ju/hTjBrLoW7a1g5BNZfXLHNk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vw51W/btsNCvFc4Ju/hTjBrLoW7a1g5BNZfXLHNk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvw51W%2FbtsNCvFc4Ju%2FhTjBrLoW7a1g5BNZfXLHNk%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;200&quot; height=&quot;216&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&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;blockquote data-ke-style=&quot;style2&quot;&gt;React v18 후기&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2022년 3월 출시된 리액트 18의 기존 버전과의 가장 큰 차이점은 바로 동시성(Councurrency) 지원이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에 여러 작업을 효율적으로 처리하여 앱의 응답성을 개선한 점이 눈여겨볼만 하다.&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;blockquote data-ke-style=&quot;style2&quot;&gt;Automatic Batching&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Batching은 업데이트 대상이 되는 상태값들을 하나의 그룹으로 묶어 한번의 리렌더링에 업데이트가 모두 진행될 수 있게 해주는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 함수 안에서 setState를 아무리 많이 호출시키더라도 리렌더링은 단 한번만 발생하고 여러번 리렌더링 하는것을 막아 성능이 향상된다.&lt;/p&gt;
&lt;pre id=&quot;code_1745845290390&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// React 17에서는 각각 렌더링 됨
setTimeout(() =&amp;gt; {
  setCount(count =&amp;gt; count + 1);
  setFlag(flag =&amp;gt; !flag);
}, 1000);

// React 18에서는 한 번에 렌더링됨&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;batch 처리하기 싫은 경우의 경우에는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;ReactDOM.flushSync()&lt;/span&gt;를 사용하여 동기적으로 즉시 렌더링시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, UI가 지금 당장 반영돼야 하는 중요 이벤트 처리나 애니메이션 프레임 맞출 때 등등 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;useTransition, startTransition&lt;/blockquote&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;특정 업데이트를 Transition으로 표시하여 사용자 상호 작용을 크게 개선했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태 전환 중에 시각적 피드백을 제공하고 전환이 발생하는 동안 브라우저의 응답성을 유지하고,&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;예를 들어, 검색창과 결과창 두 부분으로 나눠 유저가 타이핑하는 것에 따라 즉각 반영되기를 기대하는 검색창과&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;검색창보다는 UI 업데이트가 느린 것에 자연스럽게 받아들여질 수 있는 결과창으로 나누면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색창은 Urgent Update, 결과창은 Transition Update로 나눌 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1745845807721&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [isPending, startTransition] = useTransition();

const handleChange = (e) =&amp;gt; {
  startTransition(() =&amp;gt; {
    setInputValue(e.target.value);
  });
};&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;위 코드에서 isPending을 이용해 로딩 스피너를 띄우거나 하면 편하게 UI를 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Suspense&lt;/blockquote&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 16.6 때 나온 초기 버전은 코드스플리팅 (lazy-loading)을 위해 사용했었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 Suspense는 컴포넌트 단위에서만 쓸 수 있었고 데이터 페칭에는 쓰지 못했다.&lt;/p&gt;
&lt;pre id=&quot;code_1745846832800&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Profile = React.lazy(() =&amp;gt; import('./Profile'));

&amp;lt;Suspense fallback={&amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}&amp;gt;
  &amp;lt;Profile /&amp;gt;
&amp;lt;/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;React 18에서 확장된 Suspense는 데이터 페칭도 다룰 수 있게 됐고 서버 사이드 렌더링에서도 지원하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Query, SWR 등의 라이브러리에서도 Suspense를 지원하기 시작했다.&lt;/p&gt;
&lt;pre id=&quot;code_1745846898639&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Suspense fallback={&amp;lt;Loading /&amp;gt;}&amp;gt;
  &amp;lt;UserProfile /&amp;gt;
&amp;lt;/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;UserProfile 컴포넌트 내부에서 데이터를 비동기로 불러오고 있다면 데이터가 준비될 때까지 fallback UI를 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;useId&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSR(서버 사이드 렌더링)에서도 고유 ID를 안정적으로 생성할 수 있고 접근성(ARIA) 작업할 때 필수다.&lt;/p&gt;
&lt;pre id=&quot;code_1745847558334&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const id = useId();

return &amp;lt;input id={id} /&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;useDefferedValue&lt;/blockquote&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_1745847632053&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const deferredValue = useDeferredValue(value);&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;기타 변경사항&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReactDOM.render는 Deprecated되어 ReactDOM.createRoot를 사용해야 한다.&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;a href=&quot;https://ko.react.dev/blog/2022/03/29/react-v18&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.react.dev/blog/2022/03/29/react-v18&lt;/a&gt;&lt;/p&gt;</description>
      <category>Front-end/React</category>
      <category>automatic batching</category>
      <category>reactdom.createroot</category>
      <category>starttransition</category>
      <category>Suspense</category>
      <category>usedefferedvalue</category>
      <category>useid</category>
      <category>usetransition</category>
      <category>리액트18</category>
      <author>이안92</author>
      <guid isPermaLink="true">https://iancoding.tistory.com/362</guid>
      <comments>https://iancoding.tistory.com/362#entry362comment</comments>
      <pubDate>Mon, 28 Apr 2025 22:44:19 +0900</pubDate>
    </item>
    <item>
      <title>[SOLID] React에 개방폐쇄원칙 적용하기</title>
      <link>https://iancoding.tistory.com/359</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBGyYs/btsEHHUkhKd/p4AikPEDL8NS2K4m0Loo3k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBGyYs/btsEHHUkhKd/p4AikPEDL8NS2K4m0Loo3k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBGyYs/btsEHHUkhKd/p4AikPEDL8NS2K4m0Loo3k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBGyYs%2FbtsEHHUkhKd%2Fp4AikPEDL8NS2K4m0Loo3k%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;200&quot; height=&quot;216&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-02-11 오후 6.03.48.png&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJ6v0x/btsEFhoOS5V/dqaW5EQoyEEXGKf4GjbGr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJ6v0x/btsEFhoOS5V/dqaW5EQoyEEXGKf4GjbGr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJ6v0x/btsEFhoOS5V/dqaW5EQoyEEXGKf4GjbGr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJ6v0x%2FbtsEFhoOS5V%2FdqaW5EQoyEEXGKf4GjbGr1%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;1408&quot; height=&quot;804&quot; data-filename=&quot;스크린샷 2024-02-11 오후 6.03.48.png&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;804&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;b&gt;SOLID&lt;/b&gt;란 로버트 마틴이 2000년대 초반에 명명한&amp;nbsp;&lt;b&gt;객체 지향 프로그래밍 및 설계의 다섯 가지 기본 원칙&lt;/b&gt;을 마이클 페더스가 두문자어 기억술로 소개한 것이다.&amp;nbsp;SOLID 원칙들은 소프트웨어 작업에서 프로그래머가&amp;nbsp;&lt;b&gt;소스 코드가 읽기 쉽고 확장하기 쉽게&lt;/b&gt;될 때까지 소프트웨어 소스 코드를 리팩터링하여 코드 냄새를 제거하기 위해 적용할 수 있는&amp;nbsp;&lt;b&gt;지침&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 책임 원칙 (SRP: Single Responsibility Principle)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-02-11 오후 6.04.13.png&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cX2dgP/btsEEH2HCeV/7RImDpMQNyakmBD1LHnA20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cX2dgP/btsEEH2HCeV/7RImDpMQNyakmBD1LHnA20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cX2dgP/btsEEH2HCeV/7RImDpMQNyakmBD1LHnA20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcX2dgP%2FbtsEEH2HCeV%2F7RImDpMQNyakmBD1LHnA20%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;1446&quot; height=&quot;804&quot; data-filename=&quot;스크린샷 2024-02-11 오후 6.04.13.png&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;804&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;&quot;모든 함수/모듈/컴포넌트는 정확히 &lt;b&gt;한 가지 작업&lt;/b&gt;을 수행해야 한다&quot;라는 정의라고 해석할 수 있는 원칙.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;✍  개방 폐쇄 원칙 (OCP: Open Close Principle)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCP는 &quot;소프트웨어의 구성요소(컴포넌트, 클래스, 모듈, 함수)는 &lt;b&gt;확장&lt;/b&gt;에는 &lt;b&gt;열려있고&lt;/b&gt;, &lt;b&gt;수정&lt;/b&gt;은 &lt;b&gt;닫혀 있어야&lt;/b&gt; 한다&quot;라고 말합니다. 새로운 기능의 추가가 일어 났을때에는 기존코드의 수정 없이 추가가 되어야 하고,&amp;nbsp;내부 매커니즘이 변경이 되어야 할때에는 외부의 코드 변화가 없어야 한다&amp;nbsp;라는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-02-11 오후 6.04.52.png&quot; data-origin-width=&quot;1452&quot; data-origin-height=&quot;870&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qN02E/btsEF34HmWQ/sWqVpT3ZPH7kqGwk1yLECk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qN02E/btsEF34HmWQ/sWqVpT3ZPH7kqGwk1yLECk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qN02E/btsEF34HmWQ/sWqVpT3ZPH7kqGwk1yLECk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqN02E%2FbtsEF34HmWQ%2FsWqVpT3ZPH7kqGwk1yLECk%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;1452&quot; height=&quot;870&quot; data-filename=&quot;스크린샷 2024-02-11 오후 6.04.52.png&quot; data-origin-width=&quot;1452&quot; data-origin-height=&quot;870&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;트럭이라는 운송수단과 뒤에 달리는 기구를 분리/결합 할 수 있는 구조&lt;/b&gt;를 만들어 두면 새로운 목적이 필요한 도구를 만들어야 할때&amp;nbsp;&lt;b&gt;트럭 전체를 다시 만들지 않고서&lt;/b&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;b&gt;OCP&lt;/b&gt;를 가장 잘 느낄 수 있는 것은 바로 map, filter, reduce와 같은 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;Higher order Function(고차함수)&lt;/span&gt;와 webpack loader와 같은 &lt;b&gt;플러그인 또는 middleware&lt;/b&gt;&amp;nbsp;개념입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;span style=&quot;background-color: #ffc1c8;&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;b&gt;Bad:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;nimrod&quot;&gt;&lt;code&gt;function getMutipledArray(array, option) {
  const result = []
  for (let i = 0; i &amp;lt; array.length; i++) {
    if (option === &quot;doubled&quot;) {
      result[i] = array[i] * 2 // 새로운 방식으로 만들기 위해서는 수정이 필요하다.
    }
    if (option === &quot;tripled&quot;) {
      result[i] = array[i] * 3 // 옵션으로 분기는 가능하나
    }
    if (option === &quot;half&quot;) {
      result[i] = array[i] / 2 // 새로운 기능을 추가하려면 함수 내에서 변경이 되어야 한다.
    }
  }
  return result
}
&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;b&gt;Good:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;zephir&quot;&gt;&lt;code&gt;// option을 받는게 아니라 fn을 받아보자.
// 이제 새로운 array를 만든다는 매커니즘은 닫혀있으나 방식에 대해서는 열려있다.
function map(array, fn) {
  const result = []
  for (let i = 0; i &amp;lt; array.length; i++) {
    result[i] = fn(array[i], i, array) // 내부 값을 외부로 전달하고 결과를 받아서 사용한다.
  }
  return result
}

// 얼마든지 새로운 기능을 만들어도 map코드에는 영향이 없다.
const getDoubledArray = (array) =&amp;gt; map(array, (x) =&amp;gt; x * 2)
const getTripledArray = (array) =&amp;gt; map(array, (x) =&amp;gt; x * 3)
const getHalfArray = (array) =&amp;gt; map(array, (x) =&amp;gt; x / 2)
&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;하나의 함수의 기능이 여러가지 옵션들로 인해 내부에서 분기가 많이 발생하고 있다면 OCP와 SRP의 원칙에 맞게&amp;nbsp;&lt;b&gt;함수를 매개 변수&lt;/b&gt;로 받는 방법을 통해서&amp;nbsp;&lt;b&gt;공통 매커니즘의 코드와 새로운 기능에 대한 코드를 분리&lt;/b&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;본인이 작성한 덩치가 큰 함수가 params에 option이나 flag가 많은 코드가 있다면 한번 SRP와 OCP 원칙을 기반으로 함수를 한번 점검 해보시기 바랍니다. 버그 수정이 아닌 새로운 기능을 개발할때 기존에 개발된 함수를 수정하면서 코드를 개발하고 있다면 OCP 원칙을 위배한 코드를 작성하고 있을 확률이 엄청 높습니다!  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt; &amp;zwj;  React에 적용해보자!&lt;/blockquote&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;b&gt;컴포넌트 합성&lt;/b&gt;을 활용해서 OCP 원칙을 적용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 작동하는 모습을 보기 위해 다음 시나리오를 살펴보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const Header = () =&amp;gt; {
  const { pathname } = useRouter();

  return (
    &amp;lt;header&amp;gt;
      &amp;lt;Logo /&amp;gt;
      &amp;lt;Actions&amp;gt;
        {pathname === &quot;/dashboard&quot; &amp;amp;&amp;amp; (
          &amp;lt;Link to=&quot;/events/new&quot;&amp;gt;Create event&amp;lt;/Link&amp;gt;
        )}
        {pathname === &quot;/&quot; &amp;amp;&amp;amp; &amp;lt;Link to=&quot;/dashboard&quot;&amp;gt;Go to dashboard&amp;lt;/Link&amp;gt;}
      &amp;lt;/Actions&amp;gt;
    &amp;lt;/header&amp;gt;
  );
};

const HomePage = () =&amp;gt; (
  &amp;lt;&amp;gt;
    &amp;lt;Header /&amp;gt;
    &amp;lt;OtherHomeStuff /&amp;gt;
  &amp;lt;/&amp;gt;
);

const DashboardPage = () =&amp;gt; (
  &amp;lt;&amp;gt;
    &amp;lt;Header /&amp;gt;
    &amp;lt;OtherDashboardStuff /&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;여기에서 현재 페이지에 따라 다른 페이지 컴포넌트를 위한 링크를 렌더링합니다. 더 많은 페이지를 추가하기 시작할 때 어떤 일이 일어날지 생각하면 이 구현이 나쁘다는 것을 쉽게 알 수 있습니다. 새 페이지가 생성될 때마다&amp;nbsp;Header&amp;nbsp;컴포넌트로 돌아가서 렌더링할 작업 링크를 알 수 있도록 구현을 조정해야 합니다. 이러한 접근 방식은&amp;nbsp;Header&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;background-color: #ffc1c8;&quot;&gt;컴포넌트 합성(component composition)&lt;/span&gt;을 사용할 수 있습니다. Header 컴포넌트는 내부에서 무엇을 렌더링할지 신경 쓸 필요가 없으며 대신 children prop을 사용해서 Header를 사용할 컴포넌트에게 이 책임을 위임할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const Header = ({ children }) =&amp;gt; (
  &amp;lt;header&amp;gt;
    &amp;lt;Logo /&amp;gt;
    &amp;lt;Actions&amp;gt;{children}&amp;lt;/Actions&amp;gt;
  &amp;lt;/header&amp;gt;
);

const HomePage = () =&amp;gt; (
  &amp;lt;&amp;gt;
    &amp;lt;Header&amp;gt;
      &amp;lt;Link to=&quot;/dashboard&quot;&amp;gt;Go to dashboard&amp;lt;/Link&amp;gt;
    &amp;lt;/Header&amp;gt;
    &amp;lt;OtherHomeStuff /&amp;gt;
  &amp;lt;/&amp;gt;
);

const DashboardPage = () =&amp;gt; (
  &amp;lt;&amp;gt;
    &amp;lt;Header&amp;gt;
      &amp;lt;Link to=&quot;/events/new&quot;&amp;gt;Create event&amp;lt;/Link&amp;gt;
    &amp;lt;/Header&amp;gt;
    &amp;lt;OtherDashboardStuff /&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;이 접근 방식을 사용하면&amp;nbsp;Header&amp;nbsp;내부에 있던 변수 로직을 완전히 제거하고 이제 컴포넌트 자체를 수정하지 않고도 문자 그대로 원하는 모든 것을 입력할 수 있도록 합성(composition)을 사용할 수 있습니다.&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;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;nbsp;  참고한 사이트 링크&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/dailyjs/applying-solid-principles-in-react-14905d9c5377&quot;&gt;Applying SOLID principles in React&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@teo/Javascript%EC%97%90%EC%84%9C%EB%8F%84-SOLID-%EC%9B%90%EC%B9%99%EC%9D%B4-%ED%86%B5%ED%95%A0%EA%B9%8C&quot;&gt;Javascript에서도 SOLID 원칙이 통할까?&lt;/a&gt;&lt;/p&gt;</description>
      <category>Front-end/React</category>
      <category>OCP</category>
      <category>SOLID</category>
      <category>개방폐쇄원칙</category>
      <author>이안92</author>
      <guid isPermaLink="true">https://iancoding.tistory.com/359</guid>
      <comments>https://iancoding.tistory.com/359#entry359comment</comments>
      <pubDate>Sun, 11 Feb 2024 18:06:54 +0900</pubDate>
    </item>
    <item>
      <title>[SOLID] React에 단일책임원칙 적용하기</title>
      <link>https://iancoding.tistory.com/358</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKjpd4/btsELsh2wgS/xGFrc9CrkmSK9SoLoEtHcK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKjpd4/btsELsh2wgS/xGFrc9CrkmSK9SoLoEtHcK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKjpd4/btsELsh2wgS/xGFrc9CrkmSK9SoLoEtHcK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKjpd4%2FbtsELsh2wgS%2FxGFrc9CrkmSK9SoLoEtHcK%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;200&quot; height=&quot;216&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;nbsp;✍  단일 책임 원칙 (SRP)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 정의는 &quot;모든 클래스는 &lt;b&gt;단 하나의 책임&lt;/b&gt;만 가져야 한다&quot;라고 명시되어 있습니다. 이 원칙은 해석하기 가장 쉽습니다. &quot;모든 함수/모듈/컴포넌트는 정확히 &lt;b&gt;한 가지 작업&lt;/b&gt;을 수행해야 한다&quot;라는 정의라고 해석할 수 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5가지 원칙 중 SRP는 가장 따르기 쉽지만 코드 품질이 크게 향상하기 때문에 가장 영향력 있는 원칙이기도 합니다. 컴포넌트가 한 가지 작업을 수행하도록 하기 위해 다음을 수행할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;너무 많은 작업을 수행하는 큰 컴포넌트를 더 작은 컴포넌트로 나눔&lt;/li&gt;
&lt;li&gt;주요 컴포넌트 기능과 관련 없는 코드를 별도의 유틸리티 함수로 추출&lt;/li&gt;
&lt;li&gt;관련 있는 기능들을 커스텀 hook으로 캡슐화&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt; &amp;zwj;  React에 적용해보자!&lt;/blockquote&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 class=&quot;javascript&quot;&gt;&lt;code&gt;const ActiveUsersList = () =&amp;gt; {
  const [users, setUsers] = useState([]);

  useEffect(() =&amp;gt; {
    const loadUsers = async () =&amp;gt; {
      const response = await fetch(&quot;/some-api&quot;);
      const data = await response.json();
      setUsers(data);
    };

    loadUsers();
  }, []);

  const weekAgo = new Date();
  weekAgo.setDate(weekAgo.getDate() - 7);

  return (
    &amp;lt;ul&amp;gt;
      {users
        .filter((user) =&amp;gt; !user.isBanned &amp;amp;&amp;amp; user.lastActivityAt &amp;gt;= weekAgo)
        .map((user) =&amp;gt; (
          &amp;lt;li key={user.id}&amp;gt;
            &amp;lt;img src={user.avatarUrl} /&amp;gt;
            &amp;lt;p&amp;gt;{user.fullName}&amp;lt;/p&amp;gt;
            &amp;lt;small&amp;gt;{user.role}&amp;lt;/small&amp;gt;
          &amp;lt;/li&amp;gt;
        ))}
    &amp;lt;/ul&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 서로 연관된&amp;nbsp;useState와&amp;nbsp;useEffect가 있을 때는 언제든지 커스텀 hook으로 추출할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const useUsers = () =&amp;gt; {
  const [users, setUsers] = useState([]);

  useEffect(() =&amp;gt; {
    const loadUsers = async () =&amp;gt; {
      const response = await fetch(&quot;/some-api&quot;);
      const data = await response.json();
      setUsers(data);
    };

    loadUsers();
  }, []);

  return { users };
};

const ActiveUsersList = () =&amp;gt; {
  const { users } = useUsers();

  const weekAgo = new Date();
  weekAgo.setDate(weekAgo.getDate() - 7);

  return (
    &amp;lt;ul&amp;gt;
      {users
        .filter((user) =&amp;gt; !user.isBanned &amp;amp;&amp;amp; user.lastActivityAt &amp;gt;= weekAgo)
        .map((user) =&amp;gt; (
          &amp;lt;li key={user.id}&amp;gt;
            &amp;lt;img src={user.avatarUrl} /&amp;gt;
            &amp;lt;p&amp;gt;{user.fullName}&amp;lt;/p&amp;gt;
            &amp;lt;small&amp;gt;{user.role}&amp;lt;/small&amp;gt;
          &amp;lt;/li&amp;gt;
        ))}
    &amp;lt;/ul&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;useUsers&amp;nbsp;hook은 오직 API에서 사용자를 가져오는 것 하나에만 관련되어 있습니다. 또한 메인 컴포넌트 코드가 더 짧아졌을 뿐만 아니라 용도를 파악해야 하는 구조적인 hook을 이름에서 용도를 바로 알 수 있는 도메인 hook으로 대체했기 때문에 보다 읽기 쉬워졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 컴포넌트가 렌더링하는 JSX를 살펴보겠습니다. 객체 배열을 순회하며 매핑하는 경우 배열의 각 항목에 대해 생성하는 JSX의 복잡성에 주의를 기울여야 합니다. 이벤트 핸들러가 연결되지 않은 한 줄짜리 마크업인 경우 인라인으로 유지하는 것이 좋지만 더 복잡한 마크업의 경우 별도의 컴포넌트로 추출하는 것이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;const UserItem = ({ user }) =&amp;gt; {
  return (
    &amp;lt;li&amp;gt;
      &amp;lt;img src={user.avatarUrl} /&amp;gt;
      &amp;lt;p&amp;gt;{user.fullName}&amp;lt;/p&amp;gt;
      &amp;lt;small&amp;gt;{user.role}&amp;lt;/small&amp;gt;
    &amp;lt;/li&amp;gt;
  );
};

const ActiveUsersList = () =&amp;gt; {
  const { users } = useUsers();

  const weekAgo = new Date();
  weekAgo.setDate(weekAgo.getDate() - 7);

  return (
    &amp;lt;ul&amp;gt;
      {users
        .filter((user) =&amp;gt; !user.isBanned &amp;amp;&amp;amp; user.lastActivityAt &amp;gt;= weekAgo)
        .map((user) =&amp;gt; (
          &amp;lt;UserItem key={user.id} user={user} /&amp;gt;
        ))}
    &amp;lt;/ul&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 API로부터 얻은 전체 사용자 목록에서 비활성 사용자를 필터링하는 로직이 있습니다. 이 로직은 비교적 독립되어 있고 애플리케이션의 다른 부분에서 재사용될 수 있으므로 유틸리티 함수로 쉽게 추출할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const getOnlyActive = (users) =&amp;gt; {
  const weekAgo = new Date();
  weekAgo.setDate(weekAgo.getDate() - 7);

  return users.filter(
    (user) =&amp;gt; !user.isBanned &amp;amp;&amp;amp; user.lastActivityAt &amp;gt;= weekAgo
  );
};

const ActiveUsersList = () =&amp;gt; {
  const { users } = useUsers();

  return (
    &amp;lt;ul&amp;gt;
      {getOnlyActive(users).map((user) =&amp;gt; (
        &amp;lt;UserItem key={user.id} user={user} /&amp;gt;
      ))}
    &amp;lt;/ul&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;이 시점에서 메인 컴포넌트는 더 이상 나누지 않아도 될 만큼 짧고 간단합니다. 그러나 조금 더 자세히 살펴보면 여전히 해야 할 것보다 더 많은 일을 하고 있음을 알 수 있습니다. 현재 컴포넌트는 데이터를 페칭한 다음 필터링을 적용하고 있지만 추가 조작 없이 데이터를 가져와 렌더링하기만 하는 것이 이상적입니다. 따라서 마지막 개선 사항으로 이 로직을 새로운 커스텀 hook으로 캡슐화할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const useActiveUsers = () =&amp;gt; {
  const { users } = useUsers();

  const activeUsers = useMemo(() =&amp;gt; {
    return getOnlyActive(users);
  }, [users]);

  return { activeUsers };
};

const ActiveUsersList = () =&amp;gt; {
  const { activeUsers } = useActiveUsers();

  return (
    &amp;lt;ul&amp;gt;
      {activeUsers.map((user) =&amp;gt; (
        &amp;lt;UserItem key={user.id} user={user} /&amp;gt;
      ))}
    &amp;lt;/ul&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;useActiveUsers&amp;nbsp;hook을 만들어 메인 컴포넌트에는 hook에서 가져온 데이터를 렌더링하는 최소한의 작업만 남겨둡니다. (좋은 성능을 위해 필터링된 데이터를 메모이제이션했습니다)&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;background-color: #ffc1c8;&quot;&gt;&quot;한 가지&quot;&lt;/span&gt;를 어떻게 해석하는지에 따라 컴포넌트가 여전히 먼저 데이터를 얻은 다음 렌더링하기 때문에 &quot;한 가지&quot;가 아니라고 주장할 수 있습니다. 한 컴포넌트에서 hook을 호출한 다음 그 결과를 다른 컴포넌트에 props로 전달해서 더 나눌 수 있지만 실제 애플리케이션에서 이것이 실제로 이로운 경우는 거의 없었습니다. 때문에 정의를 &quot;컴포넌트가 얻은 렌더링 데이터&quot;를 &quot;한 가지&quot;로 너그럽게 받아들이도록 합시다.&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;b&gt;모듈화하면 코드를 파악하기 쉬워지고, 의도치 않은 중복 코드를 작성할 가능성이 줄어듭니다. 또한 작은 모듈은 테스트 및 수정하기 더 쉽기 때문에 결과적으로 코드를 보다 쉽게 유지 관리할 수 있어 좋습니다.&lt;/b&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;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;nbsp;  출처 링크&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/dailyjs/applying-solid-principles-in-react-14905d9c5377&quot;&gt;Applying SOLID principles in React&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-React%EC%97%90-SOLID-%EC%9B%90%EC%B9%99-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0&quot;&gt;[번역] React에 SOLID 원칙 적용하기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/React</category>
      <category>SOLID</category>
      <category>SRP</category>
      <category>단일책임원칙</category>
      <author>이안92</author>
      <guid isPermaLink="true">https://iancoding.tistory.com/358</guid>
      <comments>https://iancoding.tistory.com/358#entry358comment</comments>
      <pubDate>Sun, 11 Feb 2024 18:02:19 +0900</pubDate>
    </item>
    <item>
      <title>any와 unknown</title>
      <link>https://iancoding.tistory.com/357</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;879&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUIHY9/btsEFQqUZAZ/9j6uCwIT5KI3ckk0cYVwt1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUIHY9/btsEFQqUZAZ/9j6uCwIT5KI3ckk0cYVwt1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUIHY9/btsEFQqUZAZ/9j6uCwIT5KI3ckk0cYVwt1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUIHY9%2FbtsEFQqUZAZ%2F9j6uCwIT5KI3ckk0cYVwt1%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;200&quot; height=&quot;212&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;879&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  anyscript&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트 프로젝트의 tsconfig에서 strict를 true로 설정하거나, noImplicitAny를 true로 설정하면, 각종 변수에 타입을 지정하지 않았을 때 에러가 발생합니다. 타입스크립트에서 기본적으로 타입 추론이라는 것을 하는데, 추론한 근거가 없으면 암시적으로 any로 할당됩니다. 이러한 것을 못하게 하는 옵션이 noImplicitAny(말 그대로, no implicit any &amp;ndash; 암시적인 any는 no)를 true로 설정하는 것이고, strict를 true로 설정하면 noImplicitAny도 true로 설정되죠. 타입스크립트 프로젝트에서 strict 모드를 설정하는 것은, 프로젝트에 엄격한 룰을 강제해서 추후에 코드를 수정하기 쉽게 만들어주는데, 이러한 프로젝트에서 막상 타입 지정하기가 귀찮아서 any로 일단 선언해두고 사용하는 경우가 있습니다. 이런 게 반복되고 도배되기 시작하면, 이건 타입스크립트가 아니라&amp;nbsp;&lt;b&gt;anyscript&lt;/b&gt;라고 부를 수도 있을 만한 상황이 될 수도 있겠죠. 즉, 귀찮아서 잠시 사용할 수 있을지는 몰라도, any는 어떤 타입이든 모두 올 수 있음을 말하기 때문에 자바스크립트를 쓰는 것과 다름이 없어지는 상황이 되어서 권장하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt; &amp;zwj; ️ unknown?&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 것으로 unknown도 있는데, any와의 차이는 뭘까요? any는 아무거나 다 올 수 있고, 그 이후 어떤 동작을 해도 되는 것에 비해, unknown도 아무거나 다 올 수 있지만, 그 이후는 &lt;b&gt;어떤 동작도 허용하지 않습니다.&lt;/b&gt; 말이 어려운데 코드를 통해서 살펴보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;const sayNumber = (num: number) =&amp;gt; {
  console.log('num: ', num)
}

const sum = (a: any, b: any): any =&amp;gt; a + b
const three = sum(1, 2)
sayNumber(three)

const minus = (a: any, b: any): unknown =&amp;gt; a - b
const five = minus(7, 2)
sayNumber(five) // 'unknown' 형식의 인수는 '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;sayNumber라는 함수가 있습니다. 이 함수는 number 형식의 num이라는 값을 입력받아서, 콘솔에 출력해주는 함수입니다. 다음으로 sum이라는 함수는 a, b를 입력 받아서 a+b를 리턴해주는 함수입니다. 이 함수의 return type을 보면 any로 명시하였죠. 변수 three는 sum 함수에 1, 2를 전달해서 3이라는 return 값을 받았지만 이 변수의 type은 any입니다. minus라는 함수는 a, b를 입력 받아서 a-b를 리턴해주는 함수입니다. 이 함수의 return type은 unknown으로 명시하였습니다. 변수 five는 minus 함수에 7, 2를 전달해서 5라는 return 값을 받았지만 이 변수의 type은 unknown입니다.&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;rArr; sayNumber함수에 &lt;b&gt;any type&lt;/b&gt;의 three를 전달하면, &lt;b&gt;아무런 에러 없이&lt;/b&gt; &quot;num: 3&quot;이 출력됩니다. 하지만 sayNumber함수에 &lt;b&gt;unknown type&lt;/b&gt;의 five를 전달하면 &amp;lsquo;unknown&amp;rsquo; 형식의 인수는 &amp;lsquo;number&amp;rsquo; 형식의 매개 변수에 할당될 수 없습니다. 라는 &lt;b&gt;에러 메시지&lt;/b&gt;가 나오게 됩니다. 타입을 unknown으로 지정은 할 수 있지만, 해당 타입으로 지정된 값을 사용할 때가 되면 그 타입이 어떤 타입인지 명확히 알아야 사용할 수 있게 막아주는 역할을 한다고 보면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드의 경우 minus 함수의 return type을 명시적으로 지정해주거나 five 변수의 type을 number라고 타입 단언을 해주면 사용할 수 있게 됩니다.&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;const minus = (a: any, b: any): unknown =&amp;gt; a - b
const five = minus(7, 2) as number
sayNumber(five)
&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;물론 위의 예제처럼 타입 단언을 이용하기보다는 minus 함수의 타입을 명확하게 지정해주거나 generic을 사용하는 게 일반적이긴 하겠지만, unknown을 설명하기 위해 만든 예제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 정리해보면 any, unknown 둘 다 &amp;lsquo;아무거나&amp;rsquo;에 들어갈 수 있지만 &lt;b&gt;unknown은 그것을 사용하는 쪽에서 특별한 처리를 강제하게 해서, 안전하게 사용할 수 있게 해줍니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  unknown을 사용해야 할 상황&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 unknown에 대해서 알아보았는데, any와 같이 사용하지 말아야만 할까요? 적은 상황이지만, unknown은 아래의 예제와 같이 사용할 케이스가 있습니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const isNil = (param: unknown): boolean =&amp;gt; param === null || param === undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;isNil이라는 함수는 param을 입력받아서, 해당 param이 null이나 undefined인지를 체크해서 true/false를 리턴해줍니다. 이 경우, param은 단순히 null, undefined인지에 대한 체크만 하기 때문에, &lt;b&gt;어떠한 타입이 들어올지 몰라도 됩니다. 이때 unknown을 사용할 수 있습니다.&lt;/b&gt; 물론 이때 any를 사용할 수도 있지요. 프로젝트의 설정에 따라서 any를 아예 사용하지 못하게 하는 경우도 있는데, isNil의 param 같은 경우 &lt;b&gt;unknown 타입이 적절&lt;/b&gt;하다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 예시를 더 들어보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;function prettyPrint(x: unknown): string {
  if (Array.isArray(x)) {
    return &quot;[&quot; + x.map(prettyPrint).join(&quot;, &quot;) + &quot;]&quot;
  }
  if (typeof x === &quot;string&quot;) {
    return `&quot;${x}&quot;`}
  if (typeof x === &quot;number&quot;) {
    return String(x)
  }
  return &quot;etc.&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 prettyPrint 함수는 x라는 param을 입력받는데, 그 param이 array, string, number일 때와 그 밖의 상황에 대해서 처리를 하고 있는데, 3번째 줄에 있는 map(), join()은 array에서 사용할 수 있는 javascript 내장함수입니다. x가 any일 때는, x가 어떤 것이라고 하더라도 map(), join()을 사용할 수 있는데, x가 unknown일 때는, x가 array일 때만 map(), join()을 사용할 수 있게 강제해줍니다. (그냥 사용한다면, &amp;lsquo;x&amp;rsquo; is of type &amp;lsquo;unknown&amp;rsquo;. 이라는 에러 메시지를 보여줍니다) 따라서, any 대신 unknown을 사용해서 더 안전한 코드를 작성할 수 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  any, unknown 결론&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;any: 아무때나 쓸 수 있지만, typescript를 쓰는 의미가 사라짐&lt;/li&gt;
&lt;li&gt;unknown: 어쩔 수 없이 써야하는 상황이 있을 때, 방어처리를 통해 안전하게 사용가능함&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Front-end/TypeScript</category>
      <category>Any</category>
      <category>typescript</category>
      <category>Unknown</category>
      <author>이안92</author>
      <guid isPermaLink="true">https://iancoding.tistory.com/357</guid>
      <comments>https://iancoding.tistory.com/357#entry357comment</comments>
      <pubDate>Sun, 11 Feb 2024 17:55:27 +0900</pubDate>
    </item>
    <item>
      <title>Jira 이슈 링킹이란? (Issue Linking)</title>
      <link>https://iancoding.tistory.com/356</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-02-11 오후 4.23.20.png&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9fjvX/btsEELDTjD4/k2rQKVbzry8R8o6DkdYK81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9fjvX/btsEELDTjD4/k2rQKVbzry8R8o6DkdYK81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9fjvX/btsEELDTjD4/k2rQKVbzry8R8o6DkdYK81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9fjvX%2FbtsEELDTjD4%2Fk2rQKVbzry8R8o6DkdYK81%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;300&quot; height=&quot;79&quot; data-filename=&quot;스크린샷 2024-02-11 오후 4.23.20.png&quot; data-origin-width=&quot;408&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  이슈 링킹이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이슈들의 &lt;b&gt;관계를 정의&lt;/b&gt;하는 필드로써 하나의 관계에는 &lt;b&gt;자동태와 수동태&lt;/b&gt;로 관계를 설정할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;장점은?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 이슈 담당자로 하여금 이 이슈가 어디서 &lt;b&gt;파생&lt;/b&gt;된 이슈인지 혹은 어떤 작업이 &lt;b&gt;선행&lt;/b&gt;되어야 하는지 명시적으로 알려줄 수 있는 기능이므로 잘 사용하면 &lt;b&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; &amp;nbsp;사용법은?&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCWmnv/btsEGOGfvxP/LRqGIr00wHLTpDK21ZW7EK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCWmnv/btsEGOGfvxP/LRqGIr00wHLTpDK21ZW7EK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCWmnv/btsEGOGfvxP/LRqGIr00wHLTpDK21ZW7EK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCWmnv%2FbtsEGOGfvxP%2FLRqGIr00wHLTpDK21ZW7EK%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;948&quot; height=&quot;288&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&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;스크린샷 2024-02-11 오후 4.20.30.png&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCHQE5/btsEEZB0Ikr/feYt5DxpL8cXRapn79kwQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCHQE5/btsEEZB0Ikr/feYt5DxpL8cXRapn79kwQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCHQE5/btsEEZB0Ikr/feYt5DxpL8cXRapn79kwQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCHQE5%2FbtsEEZB0Ikr%2FfeYt5DxpL8cXRapn79kwQ0%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;1260&quot; height=&quot;552&quot; data-filename=&quot;스크린샷 2024-02-11 오후 4.20.30.png&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt; &amp;nbsp;Blocks(병목) - is blocked by, blocks&lt;br /&gt;Cloners(복제) - is cloned by, clones&lt;br /&gt;Duplicate(중복) - is duplicated by, duplicates&lt;br /&gt;Relates(관계됨) - relates to&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 A 이슈와 B 이슈가 있을 때 A 이슈가 반드시 먼저 끝나야 B 이슈를 작업할 수 있는 상황인 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rArr; A blocks B 또는 B is blocked by A 로 표현할 수 있다.&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://evan-moon.github.io/2019/06/16/jira-customizing-issue/&quot;&gt;JIRA 프로젝트 이슈 커스터마이징하기&lt;/a&gt;&lt;/p&gt;</description>
      <category>TeaTime</category>
      <category>issue linking</category>
      <category>jira</category>
      <category>jira issue linking</category>
      <category>이슈링킹</category>
      <category>지라</category>
      <category>지라 이슈</category>
      <category>지라 이슈링킹</category>
      <author>이안92</author>
      <guid isPermaLink="true">https://iancoding.tistory.com/356</guid>
      <comments>https://iancoding.tistory.com/356#entry356comment</comments>
      <pubDate>Sun, 11 Feb 2024 16:24:53 +0900</pubDate>
    </item>
    <item>
      <title>[오류해결] npm ERR! Cannot read properties of null (reading 'pickAlgorithm')</title>
      <link>https://iancoding.tistory.com/353</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 프로젝트의 repo를 npm install로 설치하는데 이와 같은 에러가 떴다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-04 15.49.49.png&quot; data-origin-width=&quot;2474&quot; data-origin-height=&quot;244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxny6r/btrVo4TJGSa/pVdNP09ldXkC9VyOnPCpXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxny6r/btrVo4TJGSa/pVdNP09ldXkC9VyOnPCpXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxny6r/btrVo4TJGSa/pVdNP09ldXkC9VyOnPCpXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcxny6r%2FbtrVo4TJGSa%2FpVdNP09ldXkC9VyOnPCpXk%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;2474&quot; height=&quot;244&quot; data-filename=&quot;스크린샷 2023-01-04 15.49.49.png&quot; data-origin-width=&quot;2474&quot; data-origin-height=&quot;244&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;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp;해결방안&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0. node-modules 폴더가 있다면 삭제. (없으면 다음 단계로 바로 넘어가도 된다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 터미널에 아래와 같이 입력.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672815191941&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm cache clear --force&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 다시 설치해주면 에러없이 설치가 완료된다.&lt;/p&gt;
&lt;pre id=&quot;code_1672815212671&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완료! ✨&lt;/p&gt;</description>
      <category>Error</category>
      <category>pickAlgorithm</category>
      <author>이안92</author>
      <guid isPermaLink="true">https://iancoding.tistory.com/353</guid>
      <comments>https://iancoding.tistory.com/353#entry353comment</comments>
      <pubDate>Wed, 4 Jan 2023 15:56:02 +0900</pubDate>
    </item>
    <item>
      <title>[React] 글자 수 이상일 때 '...' 처리하기</title>
      <link>https://iancoding.tistory.com/351</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0Tesy/btrIT9TyyjZ/JkzkMIIjbItiDNk6WhkTL1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0Tesy/btrIT9TyyjZ/JkzkMIIjbItiDNk6WhkTL1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0Tesy/btrIT9TyyjZ/JkzkMIIjbItiDNk6WhkTL1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0Tesy%2FbtrIT9TyyjZ%2FJkzkMIIjbItiDNk6WhkTL1%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;300&quot; height=&quot;324&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&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;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp;글자 수 초과 시 ... 처리하는 방법&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: #5d5d5d;&quot;&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;조건을 줘서 substr 메서드를 이용하면 간단하게 처리할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1659533774753&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const truncate = (str, n) =&amp;gt; {
  return str?.length &amp;gt; n ? str.substr(0, n - 1) + &quot;...&quot; : str;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 truncate라는 함수를 만든 후 jsx, tsx에서 가져다 쓰면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1659533869417&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;span&amp;gt;{truncate(movie.overview, 100)}&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 100자 초과 시 나머지 글자를 자르고 &quot;...&quot;가 붙어서 원하는 대로 처리된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-08-03 22.40.40.png&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sz8zj/btrIPXUabVL/tLQzYN1Emk0LZQgA3ZuAJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sz8zj/btrIPXUabVL/tLQzYN1Emk0LZQgA3ZuAJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sz8zj/btrIPXUabVL/tLQzYN1Emk0LZQgA3ZuAJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsz8zj%2FbtrIPXUabVL%2FtLQzYN1Emk0LZQgA3ZuAJ0%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;1354&quot; height=&quot;642&quot; data-filename=&quot;스크린샷 2022-08-03 22.40.40.png&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Front-end/React</category>
      <category>substr</category>
      <category>리액트 글자 이상</category>
      <category>리액트 글자수</category>
      <category>리액트 글자수 초과</category>
      <author>이안92</author>
      <guid isPermaLink="true">https://iancoding.tistory.com/351</guid>
      <comments>https://iancoding.tistory.com/351#entry351comment</comments>
      <pubDate>Wed, 3 Aug 2022 22:41:56 +0900</pubDate>
    </item>
    <item>
      <title>[React] 리액트 Hooks 총 정리</title>
      <link>https://iancoding.tistory.com/347</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IWQVR/btrIBTDnFmX/fN31mjGwcZjl0W3ERrnoDK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IWQVR/btrIBTDnFmX/fN31mjGwcZjl0W3ERrnoDK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IWQVR/btrIBTDnFmX/fN31mjGwcZjl0W3ERrnoDK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIWQVR%2FbtrIBTDnFmX%2FfN31mjGwcZjl0W3ERrnoDK%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;300&quot; height=&quot;324&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&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;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp; React Hooks&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; React Hooks는 ReactConf 2018에서 발표된 class없이 state를 사용할 수 있는 새로운 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class Component로 사용되어온 React에서 느껴왔던 불편함이나 문제점들을 해결하기 위해서 개발되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 React는 주로 Class Component를 사용하고 React Hooks는 Functional Component를 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-30 18.00.19.png&quot; data-origin-width=&quot;1616&quot; data-origin-height=&quot;1094&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xZCvN/btrIxZSoG23/us5klziySKCfTIBufV55P1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xZCvN/btrIxZSoG23/us5klziySKCfTIBufV55P1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xZCvN/btrIxZSoG23/us5klziySKCfTIBufV55P1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxZCvN%2FbtrIxZSoG23%2Fus5klziySKCfTIBufV55P1%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;1616&quot; height=&quot;1094&quot; data-filename=&quot;스크린샷 2022-07-30 18.00.19.png&quot; data-origin-width=&quot;1616&quot; data-origin-height=&quot;1094&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, Class 컴포넌트와 비교했을 때 함수형 컴포넌트를 이용하면 더 간결한 코드, 더 빠른 성능, 더 나은 가독성을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 컴포넌트에서는 클래스 컴포넌트에서 사용하던 리액트의 생명주기를 사용하기 못했기 때문에,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-30 18.02.18.png&quot; data-origin-width=&quot;2346&quot; data-origin-height=&quot;1078&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCnkib/btrIy9T4l03/jOq0XHUiCYcAidrXw5tUD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCnkib/btrIy9T4l03/jOq0XHUiCYcAidrXw5tUD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCnkib/btrIy9T4l03/jOq0XHUiCYcAidrXw5tUD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCnkib%2FbtrIy9T4l03%2FjOq0XHUiCYcAidrXw5tUD1%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;2346&quot; height=&quot;1078&quot; data-filename=&quot;스크린샷 2022-07-30 18.02.18.png&quot; data-origin-width=&quot;2346&quot; data-origin-height=&quot;1078&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 컴포넌트가 더 간결하고 빠르더라도 클래스형 컴포넌트를 써왔지만, 이것은 React 16.8 Hooks 업데이트로 변경되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 함수형 컴포넌트에서도 생명주기를 사용할 수 있기에 데이터를 가져오고 컴포넌트를 시작하자마자 API도 호출할 수 있게 되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-30 18.05.33.png&quot; data-origin-width=&quot;2344&quot; data-origin-height=&quot;1230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3R4P5/btrIADUTLln/nhVxTVMNZzqtmMgrw33kQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3R4P5/btrIADUTLln/nhVxTVMNZzqtmMgrw33kQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3R4P5/btrIADUTLln/nhVxTVMNZzqtmMgrw33kQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3R4P5%2FbtrIADUTLln%2FnhVxTVMNZzqtmMgrw33kQ1%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;2344&quot; height=&quot;1230&quot; data-filename=&quot;스크린샷 2022-07-30 18.05.33.png&quot; data-origin-width=&quot;2344&quot; data-origin-height=&quot;1230&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class Component에서는 생명주기를 이용할 때 componentDidMount와 componentDidUpdate 그리고 componentWillUnmount를 다르게 처리를 해주지만 리액트 훅을 사용할 때는 useEffect 안에서 다 처리해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;componentDidMount, componentDidUpdate, componentWillUnmount 모두를&lt;/span&gt;&amp;nbsp;Hooks에서는 usEffect를 이용해 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp; React State&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트에서 데이터가 변할 때 화면을 다시 렌더링 해주기 위해서는 React State를 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React State란 컴포넌트의 렌더링 결과물에 영향을 주는 데이터를 갖고 있는 객체이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;State가 변경되면 컴포넌트는 리렌더링(Re-rendering)된다. 또한 State는 컴포넌트 안에서 관리된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-30 18.25.00.png&quot; data-origin-width=&quot;2200&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FgKql/btrIzFyS0dw/GkTbBre42Acw3tt4kReaB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FgKql/btrIzFyS0dw/GkTbBre42Acw3tt4kReaB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FgKql/btrIzFyS0dw/GkTbBre42Acw3tt4kReaB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFgKql%2FbtrIzFyS0dw%2FGkTbBre42Acw3tt4kReaB0%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;2200&quot; height=&quot;568&quot; data-filename=&quot;스크린샷 2022-07-30 18.25.00.png&quot; data-origin-width=&quot;2200&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hooks에서는 state를 정의하고 위의 setValue와 같이 이용해 state를 업데이트한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-30 18.04.19.png&quot; data-origin-width=&quot;2162&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnvbZT/btrItmgke5n/bGFVE2KbCTVJZ1Xqxbp3W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnvbZT/btrItmgke5n/bGFVE2KbCTVJZ1Xqxbp3W0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnvbZT/btrItmgke5n/bGFVE2KbCTVJZ1Xqxbp3W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnvbZT%2FbtrItmgke5n%2FbGFVE2KbCTVJZ1Xqxbp3W0%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;2162&quot; height=&quot;392&quot; data-filename=&quot;스크린샷 2022-07-30 18.04.19.png&quot; data-origin-width=&quot;2162&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-30 18.04.39.png&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzolzw/btrIxCXqmIH/q3cE52DhTlNDM1Tr6OdECk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzolzw/btrIxCXqmIH/q3cE52DhTlNDM1Tr6OdECk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzolzw/btrIxCXqmIH/q3cE52DhTlNDM1Tr6OdECk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdzolzw%2FbtrIxCXqmIH%2Fq3cE52DhTlNDM1Tr6OdECk%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;1528&quot; height=&quot;166&quot; data-filename=&quot;스크린샷 2022-07-30 18.04.39.png&quot; data-origin-width=&quot;1528&quot; data-origin-height=&quot;166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Props는 Properties의 줄임말로 상속하는 부모 컴포넌트로부터 자녀 컴포넌트에 데이터를 전달하는 방법으로 쓰이고, 읽기 전용(immutable)로 자녀 컴포넌트 입장에서는 변하지 않는다. (변하게 하고자 하면 부모 컴포넌트에서 state를 변경시켜줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;State는 부모 컴포넌트에서 자녀 컴포넌트로 데이터를 보내는게 아닌 해당 컴포넌트 내부에서 데이터를 전달하고, 변경이 가능(mutable)하며 state가 변하면 Re-render된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-30 18.27.47.png&quot; data-origin-width=&quot;2200&quot; data-origin-height=&quot;1182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lstB5/btrIyxBlayl/RJH1gKZHbMLGvm9Qy3v1BK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lstB5/btrIyxBlayl/RJH1gKZHbMLGvm9Qy3v1BK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lstB5/btrIyxBlayl/RJH1gKZHbMLGvm9Qy3v1BK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlstB5%2FbtrIyxBlayl%2FRJH1gKZHbMLGvm9Qy3v1BK%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;2200&quot; height=&quot;1182&quot; data-filename=&quot;스크린샷 2022-07-30 18.27.47.png&quot; data-origin-width=&quot;2200&quot; data-origin-height=&quot;1182&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;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp; HOC(Higher Order Component)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HOC란 컴포넌트를 인자로 받아서 새로운 리액트 컴포넌트를 리턴하는 함수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면에서 재사용 가능한 로직만을 분리해서 component로 만들고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재사용 불가능한 UI와 같은 다른 부분들은 parameter로 받아서 처리하는 방법이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-30 18.10.03.png&quot; data-origin-width=&quot;2290&quot; data-origin-height=&quot;1528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mFzpK/btrIynZkSk0/upQXvlgfRcZkLLtFtrGv0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mFzpK/btrIynZkSk0/upQXvlgfRcZkLLtFtrGv0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mFzpK/btrIynZkSk0/upQXvlgfRcZkLLtFtrGv0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmFzpK%2FbtrIynZkSk0%2FupQXvlgfRcZkLLtFtrGv0k%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;2290&quot; height=&quot;1528&quot; data-filename=&quot;스크린샷 2022-07-30 18.10.03.png&quot; data-origin-width=&quot;2290&quot; data-origin-height=&quot;1528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 A 페이지와 B 페이지는 같은 소스를 사용하고 있는 부분이 있는데 그 부분은 유저 리스트를 가져오는 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떠한 페이지에서든 유저 리스트를 가져와야 하는 애플리케이션을 만드려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 모든 페이지에서 유저 리스트를 가져오기 위해서 똑같은 소스를 넣어준다면 너무 많은 중복이 되기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복이 되는 부분은 따로 HOC컴포넌트를 만들어 준다.&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-30 18.14.12.png&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rS9kN/btrIA19wr5w/fEjAYkakIq3klbk5jK3bk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rS9kN/btrIA19wr5w/fEjAYkakIq3klbk5jK3bk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rS9kN/btrIA19wr5w/fEjAYkakIq3klbk5jK3bk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrS9kN%2FbtrIA19wr5w%2FfEjAYkakIq3klbk5jK3bk0%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;2420&quot; height=&quot;1422&quot; data-filename=&quot;스크린샷 2022-07-30 18.14.12.png&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1422&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;유저 리스트를 가져오는 공통적인 부분은 HOC 컴포넌트에 넣어주고 그 HOC 컴포넌트로 각각의 컴포넌트를 감싸주면 모든 컴포넌트에 따로 인증을 위한 부분은 넣어주지 않아도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hooks가 나오기 전에는 이 방법이 추천되는 방법이었지만 여기도 문제가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 너무나 많은 Wrapper 컴포넌트가 생길 수 있다는 것이다.&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/bJpsX0/btrIzD8RXQK/pok3pTtPlHKf3KLtGL2PKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJpsX0/btrIzD8RXQK/pok3pTtPlHKf3KLtGL2PKk/img.png&quot; style=&quot;width: 34.1856%; margin-right: 10px;&quot; width=&quot;600&quot; height=&quot;915&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1542&quot; data-origin-height=&quot;2352&quot; data-filename=&quot;스크린샷 2022-07-30 18.16.28.png&quot; data-widthpercent=&quot;34.59&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJpsX0/btrIzD8RXQK/pok3pTtPlHKf3KLtGL2PKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJpsX0%2FbtrIzD8RXQK%2Fpok3pTtPlHKf3KLtGL2PKk%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;1542&quot; height=&quot;2352&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JM0Zt/btrIwHLu8RI/bAIrp3kkW50Tien1O3kAH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JM0Zt/btrIwHLu8RI/bAIrp3kkW50Tien1O3kAH1/img.png&quot; style=&quot;width: 64.6516%;&quot; width=&quot;400&quot; height=&quot;323&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;920&quot; data-origin-height=&quot;742&quot; data-filename=&quot;스크린샷 2022-07-30 18.16.40.png&quot; data-widthpercent=&quot;65.41&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JM0Zt/btrIwHLu8RI/bAIrp3kkW50Tien1O3kAH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJM0Zt%2FbtrIwHLu8RI%2FbAIrp3kkW50Tien1O3kAH1%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;920&quot; height=&quot;742&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같은 문제는 Custom React Hooks를 이용해서 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Hooks에서는 HOC 대신 Custom Hooks를 이용해 컴포넌트를 만들어 처리해준다. Wrapper가 너무 많아지는 일을 방지한다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-30 18.17.54.png&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHtocq/btrIA2ghoKp/LHrJmswky3xm4K7QmoFYtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHtocq/btrIA2ghoKp/LHrJmswky3xm4K7QmoFYtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHtocq/btrIA2ghoKp/LHrJmswky3xm4K7QmoFYtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHtocq%2FbtrIA2ghoKp%2FLHrJmswky3xm4K7QmoFYtK%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;2274&quot; height=&quot;1644&quot; data-filename=&quot;스크린샷 2022-07-30 18.17.54.png&quot; data-origin-width=&quot;2274&quot; data-origin-height=&quot;1644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp;React.memo (컴포넌트 렌더링 최적화)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트앱에서 여러 컴포넌트로 나누는 이유는 재사용성을 위해서도 이지만 각 컴포넌트의 렌더링의 최적화를 위해서 이기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Form에서 글을 타이핑을 할 때 원래는 Form 컴포넌트와 그 State 값을 가지고 있는 App 컴포넌트만 렌더링이 되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 글자 입력 시마다 props가 바뀌지 않아서 렌더링 하지 않아도 되는 Form 이외의 리스트를 출력하는 List, Lists 컴포넌트가 있다고 하면 그 컴포넌트들까지 다시 렌더링 되는 걸 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때 &lt;b&gt;React.memo&lt;/b&gt;를 적용하면 간단하게 문제를 해결할 수 있다.&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/3o29F/btrIBUwoTOT/3Fy0uRQmKla2mwoVcbD3rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3o29F/btrIBUwoTOT/3Fy0uRQmKla2mwoVcbD3rk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;272&quot; data-filename=&quot;스크린샷 2022-07-31 21.21.04.png&quot; style=&quot;width: 47.0653%; margin-right: 10px;&quot; data-widthpercent=&quot;47.62&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3o29F/btrIBUwoTOT/3Fy0uRQmKla2mwoVcbD3rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3o29F%2FbtrIBUwoTOT%2F3Fy0uRQmKla2mwoVcbD3rk%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;880&quot; height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XQWOr/btrIGx73Gtz/q2ZmOccxAZf4gkb3JikW6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XQWOr/btrIGx73Gtz/q2ZmOccxAZf4gkb3JikW6K/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;968&quot; data-origin-height=&quot;272&quot; data-filename=&quot;스크린샷 2022-07-31 21.21.46.png&quot; style=&quot;width: 51.7719%;&quot; data-widthpercent=&quot;52.38&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XQWOr/btrIGx73Gtz/q2ZmOccxAZf4gkb3JikW6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXQWOr%2FbtrIGx73Gtz%2Fq2ZmOccxAZf4gkb3JikW6K%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;968&quot; height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 렌더링이 필요치 않은 Lists, List 컴포넌트가 없는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;useCallback (함수 최적화)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 컴포넌트가 렌더링 될 때 그 안에 있는 함수도 다시 만들게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 똑같은 함수를 컴포넌트가 리렌더링 된다고 해서 계속 다시 만드는 것은 좋은 현상이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이렇게 컴포넌트가 리렌더링될 때마다 함수를 계속 다시 만든다고 하면 만약이 함수가 자식 컴포넌트에 props로 내려준다면&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;함수를 만들어 props로 함수를 넘겨주면 React.memo로 감싸줘서 리렌더링되지 않던 컴포넌트들이 다시 한 글자 입력 시마다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lists 컴포넌트와 List 컴포넌트까지 다시 리렌더링 되는 것을 볼 수있다.&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;b&gt;useCallback&lt;/b&gt; 적용은 useCallback 안에 콜백함수와 의존성 배열을 순서대로 넣어주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-31 21.27.19.png&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dxj52/btrIxZFFD80/gAJJBY6A1akUWXnArNL8vK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dxj52/btrIxZFFD80/gAJJBY6A1akUWXnArNL8vK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dxj52/btrIxZFFD80/gAJJBY6A1akUWXnArNL8vK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDxj52%2FbtrIxZFFD80%2FgAJJBY6A1akUWXnArNL8vK%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;862&quot; height=&quot;338&quot; data-filename=&quot;스크린샷 2022-07-31 21.27.19.png&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 내에서 참조하는 state, props가 있다면 의존성 배열에 추가해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useCallback으로 인해서 data가 변하지 않는 다면 함수는 새로 생성되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로 생성되지 않기에 메모리에 새로 할당되지 않고 동일 참조 값을 사용하게 된다.&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;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp;useMemo (결과 값 최적화)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Memoization(메모이제이션)은 비용이 많이 드는 함수 호출의 결과를 저장하고 동일한 입력이 다시 발생할 때 캐시된 결과를 반환하여 컴퓨터 프로그램의 속도를 높이는 데 주로 사용되는 최적화 기술이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-31 21.29.49.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;396&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcfnVR/btrIGysnh4D/oDC7L5tpBJ87NDLwgkHw60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcfnVR/btrIGysnh4D/oDC7L5tpBJ87NDLwgkHw60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcfnVR/btrIGysnh4D/oDC7L5tpBJ87NDLwgkHw60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcfnVR%2FbtrIGysnh4D%2FoDC7L5tpBJ87NDLwgkHw60%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;1198&quot; height=&quot;396&quot; data-filename=&quot;스크린샷 2022-07-31 21.29.49.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;396&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Component 내의 compute 함수가 만약 복잡한 연산을 수행하면 결과 값을 리턴하는데 오랜 시간이 걸리게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 시에 컴포넌트가 계속 리렌더링 된다면 연산을 계속 수행하는데 오랜 시간이 걸려서 성능에 안좋은 영향을 미치게 되며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;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;이러한 현상을 해결해주기 위해서 사용하는 것이 &lt;b&gt;useMemo&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;compute 함수에 넘겨주는 a, b의 값이 이전과 동일하다면 컴포넌트가 리렌더링 되더라도 연산을 다시 하지않고 이전 렌더링 때 저장해두었던 값을 재활용하게 된다.&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;useMemo로 감싸준 후에 첫번째 인수에 의존성 배열에 compute 함수에서 사용하는 값을 넣어준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-31 21.30.54.png&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AAKSt/btrIzE8GEGV/7JVi5Eo7pRKgDej92pMsyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AAKSt/btrIzE8GEGV/7JVi5Eo7pRKgDej92pMsyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AAKSt/btrIzE8GEGV/7JVi5Eo7pRKgDej92pMsyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAAKSt%2FbtrIzE8GEGV%2F7JVi5Eo7pRKgDej92pMsyk%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;1600&quot; height=&quot;296&quot; data-filename=&quot;스크린샷 2022-07-31 21.30.54.png&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;296&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;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp;크롬 확장 프로그램 - React Developer Tools&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ko&quot;&gt;https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ko&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1659270724860&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;React Developer Tools&quot; data-og-description=&quot;Adds React debugging tools to the Chrome Developer Tools. Created from revision 336ac8ceb on 7/13/2022.&quot; data-og-host=&quot;chrome.google.com&quot; data-og-source-url=&quot;https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ko&quot; data-og-url=&quot;https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mR7wJ/hyPf8nTX5c/SgKgarJzPF1t6K3VDWCjuK/img.jpg?width=128&amp;amp;height=128&amp;amp;face=0_0_128_128&quot;&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mR7wJ/hyPf8nTX5c/SgKgarJzPF1t6K3VDWCjuK/img.jpg?width=128&amp;amp;height=128&amp;amp;face=0_0_128_128');&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;React Developer Tools&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Adds React debugging tools to the Chrome Developer Tools. Created from revision 336ac8ceb on 7/13/2022.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;chrome.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 렌더링되는 것을 확인하기 위해 리액트 확장 프로그램을 크롬 익스텐션으로 다운로드 받아 설정해주면 쉽게 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-31 21.35.22.png&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IHQFu/btrIyxPLPVm/OizrC013vmzPt789PoSAM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IHQFu/btrIyxPLPVm/OizrC013vmzPt789PoSAM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IHQFu/btrIyxPLPVm/OizrC013vmzPt789PoSAM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIHQFu%2FbtrIyxPLPVm%2FOizrC013vmzPt789PoSAM0%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;1208&quot; height=&quot;478&quot; data-filename=&quot;스크린샷 2022-07-31 21.35.22.png&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Components 탭에서 Highligh updates... 부분을 체크해주면 쉽게 컴포넌트가 렌더링 되는 것을 확인할 수 있다.&lt;/p&gt;</description>
      <category>Front-end/React</category>
      <category>crud</category>
      <category>Filter</category>
      <category>jsx</category>
      <category>JSX key</category>
      <category>map</category>
      <category>map key</category>
      <category>react</category>
      <category>SPA</category>
      <category>리액트</category>
      <category>리액트 CRUD</category>
      <author>이안92</author>
      <guid isPermaLink="true">https://iancoding.tistory.com/347</guid>
      <comments>https://iancoding.tistory.com/347#entry347comment</comments>
      <pubDate>Sun, 31 Jul 2022 21:35:37 +0900</pubDate>
    </item>
    <item>
      <title>[React] localStorage 값 저장하고 불러오기</title>
      <link>https://iancoding.tistory.com/349</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L02WM/btrIC0JLynG/iVGARu0m8xw4vGDxxG4791/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L02WM/btrIC0JLynG/iVGARu0m8xw4vGDxxG4791/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L02WM/btrIC0JLynG/iVGARu0m8xw4vGDxxG4791/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL02WM%2FbtrIC0JLynG%2FiVGARu0m8xw4vGDxxG4791%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;300&quot; height=&quot;324&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;735&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;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp;localStorage 값 저장하기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;localStorage에 데이터 값을 담으면 페이지를 refresh 해도 데이터가 계속 남아 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1659259064110&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;Window.localStorage - Web API | MDN&quot; data-og-description=&quot;localStorage 읽기 전용 속성을 사용하면 Document 출처의 Storage 객체에 접근할 수 있습니다. 저장한 데이터는 브라우저 세션 간에 공유됩니다.&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage&quot; data-og-url=&quot;https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qlqPd/hyPhxM2QT3/p2DGf1iBPBjTkDcviembik/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qlqPd/hyPhxM2QT3/p2DGf1iBPBjTkDcviembik/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&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;Window.localStorage - Web API | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;localStorage 읽기 전용 속성을 사용하면 Document 출처의 Storage 객체에 접근할 수 있습니다. 저장한 데이터는 브라우저 세션 간에 공유됩니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트의 이벤트핸들러에서 setData시 localStorage.setItem을 이용해 동일하게 값을 담아주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-31 18.20.55.png&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd95xv/btrIEbK5uJn/oDxpK3PmkJAofQZv4N8l01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd95xv/btrIEbK5uJn/oDxpK3PmkJAofQZv4N8l01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd95xv/btrIEbK5uJn/oDxpK3PmkJAofQZv4N8l01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd95xv%2FbtrIEbK5uJn%2FoDxpK3PmkJAofQZv4N8l01%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;860&quot; height=&quot;280&quot; data-filename=&quot;스크린샷 2022-07-31 18.20.55.png&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체나 배열을 저장해줄시에는 JSON.stringify를 이용해서 텍스트로 변환시켜준 후에 저장해주면 된다.&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/rRr9e/btrIx0YQSMk/wPKZkNj8hdioHupbdUlkK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rRr9e/btrIx0YQSMk/wPKZkNj8hdioHupbdUlkK1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;252&quot; data-filename=&quot;스크린샷 2022-07-31 18.22.29.png&quot; style=&quot;width: 41.1133%; margin-right: 10px;&quot; data-widthpercent=&quot;41.6&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rRr9e/btrIx0YQSMk/wPKZkNj8hdioHupbdUlkK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrRr9e%2FbtrIx0YQSMk%2FwPKZkNj8hdioHupbdUlkK1%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;1006&quot; height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HTfcH/btrIt9adBxR/6p4iYp00fk3IoPr5kvOWb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HTfcH/btrIt9adBxR/6p4iYp00fk3IoPr5kvOWb0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;162&quot; data-filename=&quot;스크린샷 2022-07-31 18.24.26.png&quot; style=&quot;width: 57.7239%;&quot; data-widthpercent=&quot;58.4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HTfcH/btrIt9adBxR/6p4iYp00fk3IoPr5kvOWb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHTfcH%2FbtrIt9adBxR%2F6p4iYp00fk3IoPr5kvOWb0%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;908&quot; height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Application-Storage-Local Storage를 확인해보면 JSON.stringify없이 저장해둔 데이터는 [Object Object]와 같이 저장되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;box-sizing: border-box; font-family: Arial, 돋움, Dotum, AppleGothic, sans-serif; border-width: 0px 0px 2px 10px; word-spacing: 3px; border-bottom-style: solid; border-bottom-color: #cccccc; padding: 3px 5px; border-left-style: solid; border-left-color: #55555b; margin: 5px 0px; letter-spacing: 1px; line-height: 1.5; border-image: initial;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #5d5d5d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: Nanum Gothic;&quot;&gt;&amp;nbsp;localStorage 값 불러오기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값을 불러올 때는 useState 기본값에 넣어주면 된다. 이때 JSON.stringify로 객체를 string으로 변환해준 것을 다시 객체로 변환해주기 위해 JSON.parse를 이용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-07-31 18.29.02.png&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjso3Q/btrIBUpw2a2/CakwSrkcCzpngCKue4Op8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjso3Q/btrIBUpw2a2/CakwSrkcCzpngCKue4Op8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjso3Q/btrIBUpw2a2/CakwSrkcCzpngCKue4Op8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjso3Q%2FbtrIBUpw2a2%2FCakwSrkcCzpngCKue4Op8K%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;872&quot; height=&quot;352&quot; data-filename=&quot;스크린샷 2022-07-31 18.29.02.png&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Front-end/React</category>
      <category>getItem</category>
      <category>JSON.parse</category>
      <category>JSON.stringify</category>
      <category>LocalStorage</category>
      <category>localStorage 값 불러오기</category>
      <category>localStorage 값 저장</category>
      <category>setItem</category>
      <category>[Object Object]</category>
      <author>이안92</author>
      <guid isPermaLink="true">https://iancoding.tistory.com/349</guid>
      <comments>https://iancoding.tistory.com/349#entry349comment</comments>
      <pubDate>Sun, 31 Jul 2022 18:29:51 +0900</pubDate>
    </item>
  </channel>
</rss>