<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Journey to Dev</title>
    <link>https://raadi.tistory.com/</link>
    <description>개발에 관련된 여러 이야기들을 담는 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Fri, 26 Jun 2026 13:25:03 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Raadian</managingEditor>
    <image>
      <title>Journey to Dev</title>
      <url>https://tistory1.daumcdn.net/tistory/4497685/attach/e18a1f164c5c4c0cb99dbfd79dbe9699</url>
      <link>https://raadi.tistory.com</link>
    </image>
    <item>
      <title>2023-Memoirs</title>
      <link>https://raadi.tistory.com/170</link>
      <description>&lt;h1&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/h1&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;그 결과, 사고 싶은 것도 사고 먹고 싶은거랑 하고 싶은 것도 하면서 전반적인 만족도가 컸던 해였다.&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;h1&gt;&lt;b&gt;2023년에 이룬 것&lt;/b&gt;&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Vue랑 React 중급 단계까지 올려보기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Vue&lt;/b&gt;의 경우, 외주 업무를 여러번 진행하면서 Option API에 대한 전반적인 스킬을 향상한 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로, deep 셀렉터를 이용한 기존 scoped를 깨트리지 않으면서 스타일링을 하는 방법을 익힌 것과 어느 타이밍에 created와 watch, computed를 사용하는 감각들이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, Composition API와 SSR(Nuxt)를 접할 기회가 없어 내년에는 기회가 있다면 익혀보고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;React&lt;/b&gt;의 경우 실무에서 다양하게 접한게 행운이라 할 정도로 기회가 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 메모이제이션을 통해 함수를 재활용하는 useCallback과 렌더링 값을 재활용하는 useMemo를 적재적소에 이용하는 요령을 깨달아 내 기준에 생각하는 중급 수준의 초입에 다다른 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째로, 18버전 이후에 생긴 기능인 부분 렌더링(Suspense)을 통해 Layout Shifting과 같은 렌더링 최적화 문제를 해결하여 좀 더 쾌적한 클라이언트 환경을 서비스 계층에 제공할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 번째는, Redux 이외의 전역 상태관리 라이브러리를 접할 수 있었는데 Recoil이라는 것을 통해 좀 더 hooks 친화적인 상태관리를 할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, SSR 프레임워크를 팀단위로 접할 수 있었는데 NextJS를 통해 전반적인 SSR을 익힐 수 있게 되었고 무엇보다 Remix로도 다른 방식의 SSR을 익힐 수 있었다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;MacOS로 개발하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바야흐로 23년 1분기&amp;hellip;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;m2 프로의 성능이 m1에 비해 그닥 시원치않아 언제까지고 m3를 기다릴 수는 없기에 m1 프로 막차를 타기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히 결과는 성공적이었고 전반적인 만족도는 최상이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초반에 windows와 같은 UX에서 좀 헤매긴 했지만 어찌저찌 적응해서 이제는 개발은 거의 MacOS로만 하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;2023년에 추가로 이룬 것&lt;/b&gt;&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;한 직장에서 1년 재직&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 20대 생활은 집, 학교, 군대 말고는 한 곳에서 1년 이상 머무른 적이 없었다&amp;hellip;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기설과를 전공한 다음 첫 회사에서 항공 부품 QA로 5개월, 그 후 개발자로 전직하여 첫 직장에서는 4개월, 그 다음 직장에서도 4개월&amp;hellip;&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;아직도 내 능력에 확신이 들지는 않지만 늘 하겠다는 의지와 겸손한 마음을 가지면서 나아가고 싶다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Ruby on Rails 실무 경험&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌다보니 &lt;b&gt;Ruby on Rails&lt;/b&gt;로 API를 만드는 외주 업무를 받게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 처음엔 나말고도 여럿이서 맨땅에 헤딩하여 개발을 하게 되었는데 어쩌다보니 나 혼자 개발을 하게 되었다&amp;hellip;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불행 중 다행히도 기존 V1에서 V2로 기능을 업그레이드 하는 유지보수 작업이어서 API 기능을 만드는 것에만 집중할 수 있었고, 난이도도 한 기능에 일주일 이하일 정도로 그렇게 어렵지는 않았던 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 6개월 이하의 실무 경험이었기 때문에 의미있을정도의 역량은 키우지는 못해 다소 아쉽긴했다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;블록체인 관련 실무 경험&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작년 블록체인 업계에서 잠깐이나마 몸 담았지만 본격적인 경험을 쌓기도 전에 회사가 망해&amp;hellip; 아쉬움이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데, 운이 좋게도 올해에는 NFT와 토큰 거래와 같은 이더리움 기반의 기술들을 많이 접할 수 있게 되었고 내년에도 이와 같은 실무 경험을 계속 쌓게 될거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;2023년에 이루지 못한 것&lt;/b&gt;&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Angular OR Svelte 독학하기&lt;/b&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;이 것보다 우선적으로 배우고 싶은거랑 해야 되는게 많기에&amp;hellip;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;React Native 독학하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 말 즈음에 Flutter 관련 업무를 토스받다보니, RN을 배우는 것에 대한 중요성이 크게 낮아졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 꼭 필요한 상황이 아니라면 접하지는 않을 것이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;알고리즘 공부하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘과 청소의 공통점은 해야되긴 해야되는데 하기 싫다는 마음인거 같다&amp;hellip;&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;h1&gt;&lt;b&gt;2024년에 하고 싶은 것&lt;/b&gt;&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;NestJS 실무 접하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내년에 할 업무에 백엔드로 API를 만드는게 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략적인건 아직 Node.js로 뭘한다는 것만 있어서, 명확하게 정해지진 않았는데 만약 프레임워크 선정을 하는 기회가 생길때 NestJS로 하고 싶다라는 어필을 하고 싶다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;알고리즘 공부하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어처피 안할거 알지만&amp;hellip; 그래도 한 번쯤을 하게 될거 같다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;머신러닝 공부하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확히는 사이킷런을 통해 추천 영화 데이터를 출력하는 API를 만드는 토이 프로젝트를 하고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 딥러닝을 배웠던 마음가짐으로 임하고 싶다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;오픈 소스 개발 혹은 기여하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 관련 유튜브 영상을 보던 중 흥미를 끌었던 &lt;a href=&quot;https://www.youtube.com/watch?v=tgQDtLA57KQ&amp;amp;t=920s&quot;&gt;&lt;b&gt;영상&lt;/b&gt;&lt;/a&gt; 하나가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃허브에서 오픈 소스를 만들던게 우연히 알골리아 개발하는 사람에게 눈에 띄여 소개를 받게 되었고 그 길로 이직을 하게 되었다는 스토리인데(&lt;s&gt;물론 영어도 잘해서 갔지만은&amp;hellip;&lt;/s&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;다만, 정확히 어떤 오픈 소스를 할건지는 정하지 못했지만 내년에 윤곽을 잡게 되면 본격적으로 하게 될 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;마무리하며&amp;hellip;&lt;/b&gt;&lt;/h1&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;다만, 아직까지는 내 운이 좋다는 마음이기에 이게 확신이 들려면 계속 부딪혀야 할거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 하고 싶은것도 하는게 좋지만 그에 따른 책임도 져야되기에 균형을 맞춰가면서 24년을 보내고 싶다.&lt;/p&gt;</description>
      <category>Self-Study/기타</category>
      <category>개발</category>
      <category>회고록</category>
      <author>Raadian</author>
      <guid isPermaLink="true">https://raadi.tistory.com/170</guid>
      <comments>https://raadi.tistory.com/170#entry170comment</comments>
      <pubDate>Fri, 29 Dec 2023 12:34:56 +0900</pubDate>
    </item>
    <item>
      <title>[Nextjs] 14버전 정리</title>
      <link>https://raadi.tistory.com/169</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nextjs.org/blog/next-14&quot;&gt;https://nextjs.org/blog/next-14&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Turbocharged(Nextjs 컴파일러) 성능 개선&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Turbopack&lt;/b&gt;을 통한 Nextjs의 컴파일러의 성능이 개선되었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;local 서버 시작시 기존 대비 최대 &lt;b&gt;53.3%&lt;/b&gt; 속도 증가&lt;/li&gt;
&lt;li&gt;새로고침시 기존 대비 최대 &lt;b&gt;94.7%&lt;/b&gt;의 코드 업데이트 속도 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 아직 준비 단계 이므로 향후 안정화가 되면 정식으로 업데이트가 될 예정이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 호환성을 위해 &lt;b&gt;webpack&lt;/b&gt;은 계속 지원할 것이라고 한다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Forms와 Mutations&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 14버전을 통해 &lt;b&gt;Form&lt;/b&gt;과 &lt;b&gt;Mutations&lt;/b&gt;의 기능을 좀 더 단순화 했다고 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Server Actions&lt;/b&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;export default function Page() {
  async function create(formData: FormData) {
    'use server';
    const id = await createItem(formData);
  }
 
  return (
    &amp;lt;form action={create}&amp;gt;
      &amp;lt;input type=&quot;text&quot; name=&quot;name&quot; /&amp;gt;
      &amp;lt;button type=&quot;submit&quot;&amp;gt;Submit&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Page Router의 경우, &lt;a href=&quot;https://react.dev/blog/2023/05/03/react-canaries&quot;&gt;React Canaries&lt;/a&gt;를 기반으로 구축하여 좀 더 안정적인 서버액션을 포함하는 React의 기능들을 반영하였다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Caching, Revalidation, Redirectiong 등&amp;hellip;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;revalidatePath() / revalidateTag()&lt;/b&gt;&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캐싱된 데이터를 재검증&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;redirect()&lt;/b&gt;&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 경로로 리다이렉션&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;cookies()&lt;/b&gt;&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cookie 설정 및 읽기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;useOptimistic()&lt;/b&gt; &amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;능동적인 UI 업데이터 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;useFormState()&lt;/b&gt; &amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버의 오류 포착 및 표시 &amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;useFormStatus()&lt;/b&gt; &amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버를 통한 클라이언트에 로딩 표시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Partial 렌더링(준비중)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 Nextjs의 고질적인 문제였던 SSR의 문제(&lt;b&gt;Layout Shifting&lt;/b&gt;)에서 나온 솔루션으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전에 대략적인 HTML을 먼저 렌더링을 한 뒤 세부사항들을 가져오는 형식으로 성능적인 문제들을 어느정도 해결했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이번 14버전에서는 React의 렌더링을 최적화 하는 기능들을 도입하여 SSR에 맞게 수정했다고 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;React의 Suspense을 공식적으로 지원&lt;/b&gt;이러한 점을 두어, Suspense 기능을 사용하면 내부에서 정적 HTML Shell이 먼저 제공을 한 뒤 Stream을 통해 추가적인 정보들을 가져오게끔 구현이 되었다고 한다.
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;/** Suspense 사용시 먼저 정적인 HTML Shell을 제공한다. */

&amp;lt;main&amp;gt;
  &amp;lt;header&amp;gt;
    &amp;lt;h1&amp;gt;My Store&amp;lt;/h1&amp;gt;
    &amp;lt;div class=&quot;cart-skeleton&quot;&amp;gt;
      &amp;lt;!-- Hole --&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/header&amp;gt;
  &amp;lt;div class=&quot;banner&quot; /&amp;gt;
  &amp;lt;div class=&quot;product-list-skeleton&quot;&amp;gt;
    &amp;lt;!-- Hole --&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;section class=&quot;new-products&quot; /&amp;gt;
&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;/** cookies라는 기능으로 streaming을 통해 ShoppingCart 컴포넌트의 내부 구성 요소를 가져온다. */

import { cookies } from 'next/headers'
 
export default function ShoppingCart() {
  const cookieStore = cookies()
  const session = cookieStore.get('session')
  return ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;/** cookies라는 기능으로 streaming을 통해 ShoppingCart 컴포넌트의 내부 구성 요소를 가져온다. */

import { cookies } from 'next/headers'
 
export default function ShoppingCart() {
  const cookieStore = cookies()
  const session = cookieStore.get('session')
  return ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Metadata 개선&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지의 내용들을 SSR하기 위해 필요한 Metadata들을 꾸미는 기능들이 강력해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 차단 및 비차단 메타데이터를 분리하여 비차단 메타이터가 Partial 렌더링 된 페이지에 정적 HTML Shell을 제공하는데에 지장을 주지 않도록 개선이 된다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 아래의 Metadata의 옵션은 더 이상 사용되지 않아 향 후 버전에서 삭제된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;viewport &lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;viewport의 초기 확대 및 축소와 기타 속성들을 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;colorScheme &lt;/b&gt;&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;viewport의 지원 모드(light / dark)를 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;themeColor &lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;viewport 주변의 클라이언트(Chrome)가 렌더링해야 하는 색상을 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신, 향후 &lt;b&gt;&lt;a title=&quot;generateViewport&quot; href=&quot;https://nextjs.org/docs/app/api-reference/functions/generate-viewport&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;generateViewport&lt;/a&gt;&lt;/b&gt;라는 기능을 통해 보다 통합된 Metadata의 옵션들을 다룰 예정이라고 한다.&lt;/p&gt;</description>
      <category>Self-Study/React</category>
      <category>Next14</category>
      <category>nextjs</category>
      <category>React</category>
      <author>Raadian</author>
      <guid isPermaLink="true">https://raadi.tistory.com/169</guid>
      <comments>https://raadi.tistory.com/169#entry169comment</comments>
      <pubDate>Mon, 30 Oct 2023 13:01:47 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] Date 타입 데이터 관리</title>
      <link>https://raadi.tistory.com/168</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=CSWc0HYjxEs&quot;&gt;https://www.youtube.com/watch?v=CSWc0HYjxEs&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.ibm.com/docs/ko/rtw/9.0.0?topic=reference-formatting-parsing-date-time-patterns&quot;&gt;https://www.ibm.com/docs/ko/rtw/9.0.0?topic=reference-formatting-parsing-date-time-patterns&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ohgyun.com/416&quot;&gt;https://ohgyun.com/416&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://marsland.tistory.com/530&quot;&gt;https://marsland.tistory.com/530&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Intl&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Intl&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tc39.es/proposal-temporal/docs/&quot;&gt;https://tc39.es/proposal-temporal/docs/&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;개요&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Javascript&lt;/b&gt;의 경우 &lt;b&gt;Java&lt;/b&gt;와 흡사한 문법이 많은 언어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중 하나가 &lt;b&gt;Date&lt;/b&gt; 타입인데, 이 언어가 생긴 뒤로 날짜 관련 데이터 사용이 어떻게 변화했는지 알아보자.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;new Date()&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 일반적으로 &lt;b&gt;Date&lt;/b&gt; 타입을 쓴다면 사용하게 되는 과정으로 &lt;b&gt;Javascript&lt;/b&gt;가 생긴 이래로 가장 오래 사용된 문법이다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// RFC 형식 시간으로 날짜 가져오기
let date1 = new Date(); // Sat Feb 04 2023 12:22:15 GMT+0900 (한국 표준시)
date1.getFullYear(); // 2023
date1.getMonth() + 1; // 2
date1.getDate(); // 4
date1.getTime(); // 1675480935089
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;  RFC 822 : RFC(국제 인터넷 표준화 기구)에서 정한 데이터 규격으로, 자바스크립트 상에선 현지 시간으로 출력이 된다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// ISO 형식 시간으로 날짜 가져오기
let date1 = new Date().toISOString(); 
console.log(date1); // 2023-02-04T03:22:15.089Z
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;  ISO 8601 : ISO(국제 표준화 기구)에서 정한 데이터 규격으로, 자바스크립트 상에선 국제협정시(UTC)를 기준으로 출력이 된다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;moment.js&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Javascript&lt;/b&gt;에서 많이 사용 중인 &lt;b&gt;외부 날짜 라이브러리&lt;/b&gt;로, 기존 new Date()와 달리 보다 다양한 기능들을 지원한다.&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;let now = moment().format();
console.log(now); // YYYY-MM-DDTHH:MM:SS+09:00
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, &lt;b&gt;moment&lt;/b&gt;의 경우 Javascript가 지금처럼 자리 잡히기 이전에 만들어진 체계이기 때문에 그만큼 오래된 방식이고 최신 &lt;b&gt;Tree Shaking&lt;/b&gt;*에 적합하지 않아 최근 사이트에 맞게 적용하기 어려운 형태이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이러한 이유들로 인해 2020년 10월 6월 이후로 업데이트가 되지 않아 &lt;b&gt;사후지원이 중단&lt;/b&gt;되었다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;  Tree Shaking : 모듈을 번들링 할 때 사용하지 않는 코드를 정리하여 최적화 하는 과정&lt;/b&gt;&lt;/blockquote&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Intl&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ECMAScript&lt;/b&gt;에서 정한 &lt;b&gt;Javascript 내장 라이브러리&lt;/b&gt;로, 날짜 출력을 비롯하여 &lt;b&gt;문자, 시간, 날짜비교&lt;/b&gt;까지 지원한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let datetime = now Date();

let convertIntl = new Intl.DateTimeFormat('kr').format(datetime);
console.log(convertIntl); // YYYY. M. D. (한국 날짜 형식으로 출력)

let customIntl = new Intl.DateTimeFormat('kr', { dateStyle: 'full', timeStyle: 'full' }).format(datetime);
console.log(customIntl); // 원하는 날짜 형식으로 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let dDay = now Intl.RelativeTimeFormat().format(-10, 'days');
console.log(dDay); // 지정된 날짜로 부터 시간차 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Temporal&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;향 후, &lt;b&gt;Javascript&lt;/b&gt;에 내장 적용 예정인 라이브러리로 최신화 된 Javascript의 생태계에 맞게 &lt;b&gt;다양한 날짜 기능을 제공&lt;/b&gt;한다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;let nowDateTime = Temporal.Now.plainDateTimeISO();
console.log(nowDateTime.toString()); // YYYY-MM-DDTHH:MM:SS:ms

let nowDate = Temporal.Now.plainDateISO();
console.log(nowDate.toString()); // YYYY-MM-DD

let nowTime = Temporal.Now.plainTimeISO();
console.log(nowTime.toString()); // HH:MM:SS:ms

let nowCustomDate = new Temporal.PlainDate(2023, 2, 4);
console.log(nowCustomDate.toString()); // 2023-02-04
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;let now = Temporal.Now.plainDateTimeISO();

now = now.add({ days: 10, months: 3, years: 1 });
console.log(now); // 현재 날짜에 수치를 더함

now = now.subtract({ days: 10, months: 3, years: 1 }); 
console.log(now); // 현재 날짜에 수치를 뺌

now = now.round({ smallestUnit: 'hour', roundingMode: 'floor' });
console.log(now); // 현재 날짜에 반올림&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;let dDay = Temporal.PlainDateTime.from('2023-12-31T23:59:59');
let now = Temporal.Now.plainDateTimeISO();

let result = dDay.since(now); // 기준날짜에서 현재날짜 시간차 계산
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Self-Study/Javascript</category>
      <category>JavaScript</category>
      <author>Raadian</author>
      <guid isPermaLink="true">https://raadi.tistory.com/168</guid>
      <comments>https://raadi.tistory.com/168#entry168comment</comments>
      <pubDate>Sat, 4 Feb 2023 14:11:10 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] Jest의 기본 개념</title>
      <link>https://raadi.tistory.com/167</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jestjs.io/&quot;&gt;https://jestjs.io/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.daleseo.com/jest-snapshot/&quot;&gt;https://www.daleseo.com/jest-snapshot/&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Jest란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jest는 &lt;b&gt;테스트 프레임워크&lt;/b&gt;로 단순성에 초점을 맞춰 설계되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 지원하는 프레임워크 및 라이브러리는 &lt;b&gt;Babel, Typescript, Node, React, Angular, Vue&lt;/b&gt; 등이 있다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Jest가 가진 특성&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Zero Config&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jest aims to work out of the box, config free, on most JavaScript projects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Jest&lt;/b&gt;의 경우 여러 자바스크립트 프레임워크 및 라이브러리에 호한 목적으로 설계 되었기 때문에 별도의 설정 과정 없이 사용 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// 먼저 npm을 통해 Jest를 설치한 후
npm install &amp;mdash;save-dev jest&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 별도의 테스트 파일(자바스크립트 확장자 이름 앞에 .test를 붙인다)을 만들고 코드만 작성하면 준비 완료!
function sum(a, b) {
  return a + b;
}
module.exports = sum;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;{
  &quot;scripts&quot;: {
    &quot;test&quot;: &quot;jest&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// 이 후엔 터미널로 test 명령어를 실행 한 뒤 CLI에서 원하는 테스트 작업을 수행하면 된다.
PASS  ./sum.test.js
✓ adds 1 + 2 to equal 3 (5ms)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Snapshots&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Make tests which keep track of large objects with ease. Snapshots live either alongside your tests, or embedded inline.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jest의 경우 구현된 기능의 예상 결과를 예측하고자 할 때 이러한 작업과정을 쉽게 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 예를 들어 배열 타입을 반환하는 함수를 만들었다 칠때...
const multipleTimesNumbers(getNumber) {
	let arr = [];
	for (let i=0; i&amp;lt;getNumber; i++) {
		arr.push(i);
	}
	
	return arr;
}

export default multipleTimesNumbers;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 이 후엔 터미널로 test 명령어를 실행 한 뒤 CLI에서 원하는 테스트 작업을 수행하면 된다.
import multipleTimesNumbers as mtns from &quot;./multipleTimesNumbers&quot;;

test(&quot;Is Correct Three Times?&quot;, () =&amp;gt; {
	expect(mtns(3)).toMatchInlineSnapshot();
});&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Isolated&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tests are parallelized by running them in their own processes to maximize performance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jest의 경우 테스트에 초점을 맞추기 위해 별도의 프로세스에서 실행이 된다.(병렬성)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Great API&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;From&amp;nbsp;it to&amp;nbsp;expect - Jest has the entire toolkit in one place. Well documented, well maintained, well good.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jest는 test 코드가 직관적으로 설계 되어있어 협업 과정에서 어떠한 기능을 테스트하고자 하는지 빠르게 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// test 함수 내부의 expect 기능을 통해 기댓값이 무엇인지 알 수 있다.
import multipleTimesNumbers as mtns from &quot;./multipleTimesNumbers&quot;;

test(&quot;Is Correct Three Times?&quot;, () =&amp;gt; {
	expect(mtns(3)).toMatchInlineSnapshot();
});&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Self-Study/Javascript</category>
      <category>JavaScript</category>
      <category>jest</category>
      <author>Raadian</author>
      <guid isPermaLink="true">https://raadi.tistory.com/167</guid>
      <comments>https://raadi.tistory.com/167#entry167comment</comments>
      <pubDate>Mon, 9 Jan 2023 11:08:39 +0900</pubDate>
    </item>
    <item>
      <title>2022-Memoirs</title>
      <link>https://raadi.tistory.com/166</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;주의&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  내용의 대부분이 작성자의 기억 이므로 &lt;b&gt;일부 미화(?)&lt;/b&gt;가 섞여 들어갔을 수도 있습니다.&lt;/blockquote&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벌써 &lt;b&gt;2023년 검은 토끼의 해&lt;/b&gt;가 밝았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2021년 코로나로 인해 여러모로 고통 받았던 나는 2022년 만큼은 건강하게 달려보자&amp;hellip; 했지만 어림도 없지, &lt;b&gt;담석 1cm&lt;/b&gt;와 &lt;b&gt;간수치 250 IU/L&lt;/b&gt;을 얻고 몇 개월 내내 간 건강에 신경쓰게 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개발 커리어&lt;/b&gt;는 늘 그렇듯 올해도 기회가 오면 놓치지 않고 잡아보자! 였지만 아직 날개가 덜 핀거 같다. 항상 매의 눈으로 존버가 필요한 시기다&amp;hellip;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;본론&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2022년에 이룬 것&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;재취업&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하긴 했다. 4개월 이지만(&amp;hellip;)&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;h3 data-ke-size=&quot;size23&quot;&gt;앱개발 독학하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코핀홀딩스 재직시절 앱 개발 투입 대비 차 &lt;b&gt;Flutter&lt;/b&gt;를 독학했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 실 개발 업무로 이어지지 않았지만 기본적인 앱 개발을 알 수 있었던 것 같다.&lt;/p&gt;
&lt;figure id=&quot;og_1672642027182&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - roqhdehd502/flutter-todo: Flutter를 이용한 미니 프로젝트 입니다.&quot; data-og-description=&quot;Flutter를 이용한 미니 프로젝트 입니다. Contribute to roqhdehd502/flutter-todo development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/roqhdehd502/flutter-todo&quot; data-og-url=&quot;https://github.com/roqhdehd502/flutter-todo&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/czPFk2/hyQ81S1S5C/6oHNXUcHDKHxREOK1t39K0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/roqhdehd502/flutter-todo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/roqhdehd502/flutter-todo&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/czPFk2/hyQ81S1S5C/6oHNXUcHDKHxREOK1t39K0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;GitHub - roqhdehd502/flutter-todo: Flutter를 이용한 미니 프로젝트 입니다.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Flutter를 이용한 미니 프로젝트 입니다. Contribute to roqhdehd502/flutter-todo development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Vue 개발하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2021년의 나는 나름 &lt;b&gt;Vue&lt;/b&gt; 개발을 한 것 같지만, 제대로 개발 현장에 투입되어보니 그냥 수박 겉핥기 수준도 안됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코핀홀딩스 당시 업무 대비 차 &lt;b&gt;Vue3&lt;/b&gt;를 처음부터 다시 시작하여 어느새 걸음마 단계를 뗄 무렵 두 프로젝트에 투입이 되었고 비록 사내 프로젝트라 결과물이 남지 않았지만 어느정도 쌓은 실력에 만족하게 되었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2022년에 추가로 이룬 것&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ELK(Elasticsearch, Logstash, Kibana) 독학&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코핀홀딩스 재직시 인원이 없어 백엔드 업무도 겸해야 했던 나는 &lt;b&gt;Java, ELK&lt;/b&gt; 파트를 인수인계 받아 진행을 해야했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java는 &lt;b&gt;WebFlux&lt;/b&gt;만 스터디하면 됐으니 그렇다 쳤지만 ELK는 완전 몰랐기에 부랴부랴 독학하여 진행을 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 과정에서 엘라스틱 서치가 가진 &lt;b&gt;역 인덱스&lt;/b&gt;의 매력을 깨닫게 되어 나중에 검색 기능을 만들게 된다면 한 번 도입해보고 싶다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;NextJS 프로젝트 독학 및 개발&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;22년 10월 경, 이력서는 완성이 됐지만 포트폴리오가 매우 부실하는 걸 깨달은 나는 모자란 하나를 채우기 위해 &lt;b&gt;NextJS&lt;/b&gt; 개인 프로젝트를 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 과정에서 &lt;b&gt;CSR(Crient Side Rendering)&lt;/b&gt; 이외에 &lt;b&gt;SSR(Server Side Rendering)&lt;/b&gt;과 &lt;b&gt;SSG(Static Side Generation)&lt;/b&gt;의 매력 또한 느꼈던 것 같다.&lt;/p&gt;
&lt;figure id=&quot;og_1672642029833&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - roqhdehd502/rounded-round: 리액트, Next.js를 기반으로 한 음반 플랫폼 웹 사이트 개인 프로젝트 &quot; data-og-description=&quot;리액트, Next.js를 기반으로 한 음반 플랫폼 웹 사이트 개인 프로젝트 입니다. Contribute to roqhdehd502/rounded-round development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/roqhdehd502/rounded-round&quot; data-og-url=&quot;https://github.com/roqhdehd502/rounded-round&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rrl0H/hyQ8YosfAG/5cUosulwVIloVVmQ9p8lfK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/roqhdehd502/rounded-round&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/roqhdehd502/rounded-round&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rrl0H/hyQ8YosfAG/5cUosulwVIloVVmQ9p8lfK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;GitHub - roqhdehd502/rounded-round: 리액트, Next.js를 기반으로 한 음반 플랫폼 웹 사이트 개인 프로젝트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;리액트, Next.js를 기반으로 한 음반 플랫폼 웹 사이트 개인 프로젝트 입니다. Contribute to roqhdehd502/rounded-round development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Atomica 프로젝트 개발 (진행 중)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바야흐로 22년 12월&amp;hellip;&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;순간 마음 속으로 무언가 주저했지만 찬밥 더운밥 가릴 형편이 아니었다. 나는 바로 하겠다고 답변을 했고 이윽고 리액트 개발과 관련된 테스크가 들어왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맡고 있는 곳은 일본 쪽 기업으로 현지 담당자 분과 협업하면서 진행을 하였고 지금도 진행 중이다.&lt;/p&gt;
&lt;figure id=&quot;og_1672642032152&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;コワーキングスペースのATOMica（アトミカ）&quot; data-og-description=&quot;「多種多様な地域の人々」と「地域のあらゆる願い/相談」を集め、そして繋げるための仕組みを「ソーシャルコワーキング」と名付け、有意義で心躍るような出会いや共創を持続的に生み出&quot; data-og-host=&quot;atomica.co.jp&quot; data-og-source-url=&quot;https://atomica.co.jp/&quot; data-og-url=&quot;https://atomica.co.jp/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/czzijm/hyQ8YosfES/208idrAjPJFpctQy0idrk0/img.jpg?width=2210&amp;amp;height=1658&amp;amp;face=908_918_1042_1063,https://scrap.kakaocdn.net/dn/9ulmB/hyQ6QFBwUJ/QnE8z9Tcdg1ko0CP6EKzq0/img.jpg?width=2210&amp;amp;height=1658&amp;amp;face=908_918_1042_1063,https://scrap.kakaocdn.net/dn/IPNEL/hyQ84IYX58/hrfXNpssV2lsnkWuJ4m6Wk/img.png?width=468&amp;amp;height=360&amp;amp;face=0_0_468_360&quot;&gt;&lt;a href=&quot;https://atomica.co.jp/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://atomica.co.jp/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/czzijm/hyQ8YosfES/208idrAjPJFpctQy0idrk0/img.jpg?width=2210&amp;amp;height=1658&amp;amp;face=908_918_1042_1063,https://scrap.kakaocdn.net/dn/9ulmB/hyQ6QFBwUJ/QnE8z9Tcdg1ko0CP6EKzq0/img.jpg?width=2210&amp;amp;height=1658&amp;amp;face=908_918_1042_1063,https://scrap.kakaocdn.net/dn/IPNEL/hyQ84IYX58/hrfXNpssV2lsnkWuJ4m6Wk/img.png?width=468&amp;amp;height=360&amp;amp;face=0_0_468_360');&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;コワーキングスペースのATOMica（アトミカ）&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;「多種多様な地域の人々」と「地域のあらゆる願い/相談」を集め、そして繋げるための仕組みを「ソーシャルコワーキング」と名付け、有意義で心躍るような出会いや共創を持続的に生み出&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;atomica.co.jp&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2022년에 이루지 못한 것&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&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;23년도에 하고 싶은 목록을 이룬 다면 N순위로 진행해보고 싶은 사항이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/roqhdehd502/IiCoTe-Practice&quot;&gt;GitHub - roqhdehd502/IiCoTe-Practice: 나동빈 저 이것이 코딩 테스트다의 실습 자료물입니다.&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672642033367&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - roqhdehd502/IiCoTe-Practice: 나동빈 저 이것이 코딩 테스트다의 실습 자료물입니다.&quot; data-og-description=&quot;나동빈 저 이것이 코딩 테스트다의 실습 자료물입니다. Contribute to roqhdehd502/IiCoTe-Practice development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/roqhdehd502/IiCoTe-Practice&quot; data-og-url=&quot;https://github.com/roqhdehd502/IiCoTe-Practice&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/buuqn7/hyQ8RJDxPN/gkUu9FzlpKoFyYhNBcl3CK/img.png?width=360&amp;amp;height=360&amp;amp;face=0_0_360_360&quot;&gt;&lt;a href=&quot;https://github.com/roqhdehd502/IiCoTe-Practice&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/roqhdehd502/IiCoTe-Practice&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/buuqn7/hyQ8RJDxPN/gkUu9FzlpKoFyYhNBcl3CK/img.png?width=360&amp;amp;height=360&amp;amp;face=0_0_360_360');&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;GitHub - roqhdehd502/IiCoTe-Practice: 나동빈 저 이것이 코딩 테스트다의 실습 자료물입니다.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;나동빈 저 이것이 코딩 테스트다의 실습 자료물입니다. Contribute to roqhdehd502/IiCoTe-Practice development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2023년에 하고 싶은 것&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Vue랑 React 중급 단계까지 올려보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 기본적인 실전 및 이론은 어느정도 할 줄 알게 된거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 남은 건 **최적화(렌더링 및 메모이제이션 등)**를 얼마나 심도 있게 하느냐 인 거 같은데&amp;hellip; 어려운 숙제이지만 꼭 달성하고 싶은 과제이기도 하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MacOS로 개발하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;탐난다. 맥북 프로가&amp;hellip;&lt;/s&gt; M3가 올해 출시된다면 무지성으로 지르고, 아니라면 M2라도 지르고 싶다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Angular OR Svelte 독학하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;React&lt;/b&gt;랑 &lt;b&gt;Vue&lt;/b&gt;를 했으니&amp;hellip; 이제 다음 프론트엔트 프레임워크나 라이브러리를 익힐 차례가 온 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;욕심 같아선 둘 다 하고 싶지만 선택과 집중으로 하나라도 독학 해보고 싶다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;React Native 독학하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;22년도엔 플러터로 개발을 했다면 올해에는 리액트로 쌓은 경험치를 발판 삼아 이를 앱 개발로 이어가고 싶다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;알고리즘 공부하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;22년도 처럼 빡세게 공부하는 것이 아닌 어느정도 여유있게 공부하고 싶다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&lt;b&gt;마무리하며&amp;hellip;&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 19년도의 내가 지금의 나를 만날 때 &lt;b&gt;&amp;ldquo;무슨 개발자가 되었냐?&amp;rdquo;&lt;/b&gt; 라고 묻는다면 나는 어떻게 답할 수 있을지 모르겠다. 그렇기 때문에 아직도 내 개발 실력은 창피하고 남루하게 느껴진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 아직도 마음 한 켠 자신감은 남아 있기에 유지가 된다면 올 23년은 그래도 덜 창피한 개발자가 될 수 있지 않을까 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;늘 불안정 하긴 해도 올해는 내 커리어에 작은 꽃을 피우길 희망한다.&lt;/p&gt;</description>
      <author>Raadian</author>
      <guid isPermaLink="true">https://raadi.tistory.com/166</guid>
      <comments>https://raadi.tistory.com/166#entry166comment</comments>
      <pubDate>Mon, 2 Jan 2023 15:47:54 +0900</pubDate>
    </item>
    <item>
      <title>[React] Redux Vs. Recoil</title>
      <link>https://raadi.tistory.com/165</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://recoiljs.org/ko/&quot;&gt;https://recoiljs.org/ko/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@katanazero86/redux-recoil-내용-정리&quot;&gt;https://velog.io/@katanazero86/redux-recoil-내용-정리&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Recoil이란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;React 기반 전역 상태관리 라이브러리&lt;/b&gt;로 기존 &lt;b&gt;Context API의 기능적 한계를 보완&lt;/b&gt;하기 위한 목적으로 생겼다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Recoil과 Redux의 차이점&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Redux&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux의 경우 &lt;b&gt;Flux 아키텍쳐&lt;/b&gt; 기반으로 데이터 흐름을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 Type과 Payload를 가진 &lt;b&gt;Action&lt;/b&gt;을 생성하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 &lt;b&gt;Dispatcher&lt;/b&gt;에게 전달하고 여러 Action들의 상태 값을 가진 &lt;b&gt;Store&lt;/b&gt;에게 전달한 뒤,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Store 내부의 상태 값이 변경&lt;/b&gt;되면 &lt;b&gt;View&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;따라서, &lt;b&gt;중앙 집중식으로 Store를 관리&lt;/b&gt;하여 전역적인 상태 관리가 이루어지기에 프로젝트의 규모가 커질수록 안정적일 수 있으나, 그만큼 불필요한 렌더링 등 &lt;b&gt;성능 이슈&lt;/b&gt;가 생길 수도 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Recoil&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Recoil의 경우 &lt;b&gt;Atomic 모델&lt;/b&gt; 기반의 데이터 흐름을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Atoms&lt;/b&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;또한, &lt;b&gt;Selectors&lt;/b&gt;란 순수 함수를 통해 &lt;b&gt;캐싱&lt;/b&gt;하는 기능도 있어 여러 Atoms 와의 조합 등 세부적인 요소를 기대할 수 있다.&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;성능에 이점&lt;/b&gt;을 챙길 수 있으나, Redux와 달리 &lt;b&gt;다양한 기능 지원이 아직 부족&lt;/b&gt;하기 때문에 안정성을 꾀하기엔 아직 시간이 필요할 것으로 보인다.&lt;/p&gt;</description>
      <category>Self-Study/React</category>
      <category>React</category>
      <category>Recoil</category>
      <category>redux</category>
      <author>Raadian</author>
      <guid isPermaLink="true">https://raadi.tistory.com/165</guid>
      <comments>https://raadi.tistory.com/165#entry165comment</comments>
      <pubDate>Thu, 8 Dec 2022 13:20:45 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] Base64 이미지 최적화</title>
      <link>https://raadi.tistory.com/164</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/베이스64&quot;&gt;https://ko.wikipedia.org/wiki/베이스64&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blue-boy.tistory.com/227&quot;&gt;https://blue-boy.tistory.com/227&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/35940290/how-to-convert-base64-string-to-javascript-file-object-like-as-from-file-input-f/38935990&quot;&gt;https://stackoverflow.com/questions/35940290/how-to-convert-base64-string-to-javascript-file-object-like-as-from-file-input-f/38935990&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;서론&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  핵심만 보고 싶으신 분은 하단의 &lt;b&gt;&amp;ldquo;그래서 어떻게 최적화 할 것인가?&amp;rdquo;&lt;/b&gt; 파트만 보시면 됩니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글과 사진을 다채롭게 표현 하고자 할 때 &lt;b&gt;위지윅(WYSIWYG, What You See Is What You Get)&lt;/b&gt; 기능이 담긴 &lt;b&gt;텍스트 에디터&lt;/b&gt;가 필요한 순간이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 어느 순간 이미지와 같은 데이터가 포함 된 글을 포스팅 하기 전에 반드시 부딪히는 순간이 있는데 바로, &lt;b&gt;Base64&lt;/b&gt; 이다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Base64란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;위키피디아&lt;/b&gt;에선 &lt;b&gt;Base64&lt;/b&gt;를 다음과 같이 정의하고 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;8비트 이진 데이터(예를 들어 실행 파일이나, ZIP 파일 등)를 문자 코드에 영향을 받지 않는 공통 ASCII 영역의 문자들로만 이루어진 일련의 문자열로 바꾸는 인코딩 방식을 가리키는 개념 (&amp;hellip; 후략)&lt;/span&gt;&lt;/p&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;즉, 우리가 접하고 있는 &lt;b&gt;이미지와 동영상과 같은 이진(바이너리) 데이터&lt;/b&gt;를 컴퓨터가 인식할 수 있는 **로우 레벨 단계(공통 ASCII 코드 문자)**로 &lt;b&gt;번역&lt;/b&gt;된 것을 &lt;b&gt;Base64&lt;/b&gt;라 이해하면 편할 것이다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;그런데 Base64가 왜?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, &lt;b&gt;&amp;lsquo;Base64가 잘못된 기능은 아니다.&amp;rsquo;&lt;/b&gt; 라고 짚고 넘어가고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 앞서 말했다시피 데이터를 다루는 과정에서 &lt;b&gt;컴퓨터가 이해&lt;/b&gt;할 수 있도록 보다 안전한 &lt;b&gt;공통 ASCII 코드 문자&lt;/b&gt; 형태로 운용되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 기존 &lt;b&gt;바이너리 데이터&lt;/b&gt;에서 상대적으로 &lt;b&gt;저차원인 Base64로 변환&lt;/b&gt;하는 경우 그만큼 더 &lt;b&gt;변환되는 크기가 커질 수 밖에 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 곧 &lt;b&gt;DB에 Base64가 그대로 적용된 상태에서 insert&lt;/b&gt;가 될 경우 &lt;b&gt;그만큼 부하가 온다&lt;/b&gt;는 의미가 되는데 그렇다면, 전 후를 비교하여 데이터가 얼마나 커지는지 한 번 알아보자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;base64 적용 전 / 후&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;텍스트 에디터에 첨부하고자 하는 이미지의 크기&lt;/b&gt;는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAfZNW/btrSBDS2SOM/NfCpmZfZnV6jje7dlbZMlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAfZNW/btrSBDS2SOM/NfCpmZfZnV6jje7dlbZMlK/img.png&quot; data-alt=&quot;크기가 10.4KB 인 것을 확인할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAfZNW/btrSBDS2SOM/NfCpmZfZnV6jje7dlbZMlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAfZNW%2FbtrSBDS2SOM%2FNfCpmZfZnV6jje7dlbZMlK%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;411&quot; height=&quot;301&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;크기가 10.4KB 인 것을 확인할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;텍스트 에디터에 적용&lt;/b&gt; 후, &lt;b&gt;Base64에 적용한 이미지의 크기&lt;/b&gt;는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ocGTL/btrSDexYUn9/HsFnzOxunVmziWlvE4Ilt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ocGTL/btrSDexYUn9/HsFnzOxunVmziWlvE4Ilt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ocGTL/btrSDexYUn9/HsFnzOxunVmziWlvE4Ilt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FocGTL%2FbtrSDexYUn9%2FHsFnzOxunVmziWlvE4Ilt1%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;574&quot; height=&quot;512&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgweHW/btrSDFWoWqg/kYR4rWJqgiSFHcj0pp35r0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgweHW/btrSDFWoWqg/kYR4rWJqgiSFHcj0pp35r0/img.png&quot; data-alt=&quot;확실히 크기가 10.4KB인 전보다 데이터가 커졌음을 알 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgweHW/btrSDFWoWqg/kYR4rWJqgiSFHcj0pp35r0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgweHW%2FbtrSDFWoWqg%2FkYR4rWJqgiSFHcj0pp35r0%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;898&quot; height=&quot;550&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;확실히 크기가 10.4KB인 전보다 데이터가 커졌음을 알 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 1~2개 아닌 데이터의 경우 당장 체감이 오지 않을 수 있지만 이것이 &lt;b&gt;수십개, 수백개 이상의 규모&lt;/b&gt;가 될 경우 상당한 크기의 데이터 규모를 부담할 수 밖에 없다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;그래서 어떻게 최적화 할 것인가?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 이러한 문제로 인해 &lt;b&gt;Base64 형태의 데이터를 최적화는 필수 불가결&lt;/b&gt; 해지는데 필자는 다음과 같이 &lt;b&gt;추상화 및 구현&lt;/b&gt;을 하기로 했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주어진 조건&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Javascript (예제는 NextJS에서 이루어졌으나 구현 할 코드 대부분이 Plane 자바스크립트 코드)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Google Firebase Storage&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Quill Editor&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;요구사항 및 추상화&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 텍스트 에디터 작성이 완료되고 submit 클릭 이벤트가 이루어질때 최적화 한다.&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;로직 단순화&lt;/b&gt; 및 &lt;b&gt;파이어베이스 스토리지 파일 업로드 및 다운로드 하는 과정을 최소화 &lt;/b&gt;하기 위해서 이다.&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 텍스트 에디터의 base64 이미지 경로를 탐색하여 배열 A에 담는다.&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이후 &lt;b&gt;파이어베이스 스토리지에 저장된 이미지 url로 변경&lt;/b&gt;할 때 &lt;b&gt;비교 군&lt;/b&gt;으로 쓰기 위해서 이다.&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. base64 이미지를 File 객체의 형태로 변환 후 배열 B에 담는다.&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;파이어베이스 스토리지에 업로드 및 다운로드 과정을 최적화&lt;/b&gt; 하기 위해서 이다.&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. File 객체로 변환한 이미지 이름에 규칙을 부여한다.&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;파이어베이스 스토리지&lt;/b&gt;의 경우, 같은 이름의 파일명이 업로드 될 때 알아서 &lt;b&gt;덮어쓰기가 되는 기능&lt;/b&gt;이 있다.&lt;br /&gt;따라서, 이후 텍스트 에디터 내용에 UPDATE 기능이 생길 때 이를 대비할 목적으로 &lt;b&gt;각 이미지 명 마다 규칙을 부여&lt;/b&gt; 한다.&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 파이어베이스 스토리지에 업로드 후 데이터의 URL을 받아 배열 C에 담는다.&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이유는 2번과 동일&amp;hellip;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 기존에 작성한 텍스트 에디터 내용을 탐색 후 배열 A의 요소와 매칭될 때 배열 C의 요소로 변경한다.&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;적용 전 내용, 비교할 내용 들, 변경할 내용&lt;/b&gt; 들을 각 그룹으로 두어&lt;br /&gt;최종적으로 &lt;b&gt;파이어베이스 스토리지에 업로드 된 이미지 URL를 적용한 내용으로 변경&lt;/b&gt;을 마친다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;요구사항 및 추상화&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 작성한 내용 속 base64 이미지 경로 추출 (배열 A)&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const findBase64s = (includeBase64) =&amp;gt; {
		// 정규식을 이용하여 base64 경로만 추출한다.
    const base64Match = Array.from(includeBase64.matchAll(/&amp;lt;img[^&amp;gt;]+src=[&quot;']([^'&quot;&amp;gt;]+)['&quot;]/gi));
    return base64Match.map(item =&amp;gt; item.pop() || '');
}

// contents: event.htmlValue
const extractBase64s = findBase64s(contents); 
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. base64 경로를 File 객체로 변환 (배열 B)&lt;/h3&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;const convertBase64ToFiles = (base64URLs, imageUuid) =&amp;gt; {
    let base64ToFiles = [];

    for (let i=0; i&amp;lt;base64URLs.length; i++) {
        const arr = base64URLs[i].split(',');
        const mime = arr[0].match(/:(.*?);/)[1];
        const fileExtension = mime.substring('image/'.length, mime.length);
        const bstr = atob(arr[1]);
        const n = bstr.length;
        const u8arr = new Uint8Array(n);

        while(n--) {
            u8arr[n] = bstr.charCodeAt(n);
        }

        base64ToFiles.push(new File([u8arr], `${imageUuid}_${i}.${fileExtension}`, {type:mime}));
    }

    return base64ToFiles;
}

// imageUuid: 파일명에 규칙성을 부여하기 위해 필자는 Uuid 뒤에 넘버링을 붙이기로 했다
const base64ToFiles = convertBase64ToFiles(extractBase64s, imageUuid);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 배열 B를 파이어베이스 스토리지에 업로드 후 downloadURL 가져오기 (배열 C)&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;/**
* contentsStorageRef 중복코드가 있는데 이건 사전에 함수 scope 밖에 선언하자...
*/

const uploadContentsImages = async (storage, imageFiles, imageUuid, uid) =&amp;gt; {
    for (let i=0; i&amp;lt;imageFiles.length; i++) {
        const contentsStorageRef = firebaseStorage.ref(storage, `customercontentsimages/${uid}/${imageUuid}_${i}`);
        await firebaseStorage.uploadBytes(contentsStorageRef, imageFiles[i])
          .then((snapshot) =&amp;gt; {
              console.log(`thumbnail images ${i}`, snapshot);
          }).catch((error) =&amp;gt; {
              console.log(&quot;contents image upload error!&quot;, error);
          });
    }
}

const downloadContentsImages = async (storage, imageFiles, imageUuid, uid) =&amp;gt; {
    let downloadURLs = [];
    
    for (let i=0; i&amp;lt;imageFiles.length; i++) {
        const contentsStorageRef = firebaseStorage.ref(storage, `customercontentsimages/${uid}/${imageUuid}_${i}`);
        await firebaseStorage.getDownloadURL(contentsStorageRef)
          .then((url) =&amp;gt; {
              downloadURLs.push(url);
          }).catch((error) =&amp;gt; {
              console.log(&quot;contents image download error!&quot;, error);
          });
    }
    console.log(&quot;downloadURLs&quot;, downloadURLs);

    return downloadURLs;
}

await uploadContentsImages(storage, base64ToFiles, thumbnailUuid, contentObj.uid);
const contentImages = await downloadContentsImages(storage, base64ToFiles, thumbnailUuid, contentObj.uid);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 기존 내용, 배열 A와 대조 후 base64 경로가 일치하면 배열 C로 변경하기&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;let afterContents = contents;

for (let i=0; i&amp;lt;base64ToFiles.length; i++) {
    afterContents = afterContents.replaceAll(extractBase64s[i], contentImages[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;되&amp;hellip;된다!&lt;/s&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;이 후 개선할 사항&lt;/h1&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;따라서, &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;b&gt;파이어베이스 스토리지에 더미 데이터가 남는 경우&lt;/b&gt;도 감안을 해야 할 것 같다.&lt;/p&gt;</description>
      <category>Self-Study/계란으로 바위치기</category>
      <category>JavaScript</category>
      <category>nextjs</category>
      <category>React</category>
      <author>Raadian</author>
      <guid isPermaLink="true">https://raadi.tistory.com/164</guid>
      <comments>https://raadi.tistory.com/164#entry164comment</comments>
      <pubDate>Thu, 1 Dec 2022 19:46:42 +0900</pubDate>
    </item>
    <item>
      <title>[React] Next.js 레이아웃 설정</title>
      <link>https://raadi.tistory.com/163</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://logfetch.com/nextjs-multiple-layouts/&quot;&gt;https://logfetch.com/nextjs-multiple-layouts/&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;개요&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Next.js&lt;/b&gt;의 경우 기존 &lt;b&gt;React&lt;/b&gt;와 달리 별다른 &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;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;레이아웃 기본 설정&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;레이아웃 파일 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;레이아웃 파일&lt;/b&gt;을 생성한 뒤 다음과 같이 구현한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;/** DefaultLayout.js */
/** 레이아웃 파일 명칭은 자유! */

import { NavigationBar } from '../components/Header/NavigationBar';
import { Footer } from '../components/Footer/Footer';

// children : 해당 레이아웃에 종속될 컴포넌트
export default function DefaultLayout({ children }) {
  return (
      &amp;lt;&amp;gt;
          {/* 이런 식으로 공통되는 구현부와 다르게 해야하는 구현부를 작성한다 */}
          &amp;lt;NavigationBar /&amp;gt;
          &amp;lt;div&amp;gt;
              { children }
          &amp;lt;/div&amp;gt;
          &amp;lt;Footer /&amp;gt;
      &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;레이아웃 파일 적용하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/pages/_app.js&lt;/b&gt; 내부에 해당 &lt;b&gt;레이아웃 파일을 적용&lt;/b&gt;한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;/** _app.js */

import '../styles/globals.css'
// 만든 레이아웃 가져오기
import DefaultLayout from '../layouts/DefaultLayout'; 

function MyApp({ Component, pageProps }) {
    return (
        &amp;lt;&amp;gt;
            {/* 이런 식으로 태그를 씌워 레이아웃을 적용한다! */}
            &amp;lt;DefaultLayout &amp;gt;
                &amp;lt;Component {...pageProps} /&amp;gt;
            &amp;lt;/DefaultLayout &amp;gt;
        &amp;lt;/&amp;gt;
    ) 
}

export default MyApp;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;325&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjNx81/btrO50we9AL/yuwAG8kjZKUxXDBCYJaEp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjNx81/btrO50we9AL/yuwAG8kjZKUxXDBCYJaEp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjNx81/btrO50we9AL/yuwAG8kjZKUxXDBCYJaEp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjNx81%2FbtrO50we9AL%2FyuwAG8kjZKUxXDBCYJaEp1%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;942&quot; height=&quot;325&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;325&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bis7f9/btrO3Vb6qrr/Xy0Ot06AWUDD6WCMtoU4ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bis7f9/btrO3Vb6qrr/Xy0Ot06AWUDD6WCMtoU4ek/img.png&quot; data-alt=&quot;이런식으로 공통되는 구현부를 재활용한다!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bis7f9/btrO3Vb6qrr/Xy0Ot06AWUDD6WCMtoU4ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbis7f9%2FbtrO3Vb6qrr%2FXy0Ot06AWUDD6WCMtoU4ek%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;942&quot; height=&quot;476&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이런식으로 공통되는 구현부를 재활용한다!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;다양한 레이아웃 설정&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 &lt;b&gt;다양한 레이아웃&lt;/b&gt;을 통해 페이지를 다채롭게(?) 만들어보자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;레이아웃 파일 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;똑같이 &lt;b&gt;레이아웃 파일&lt;/b&gt;을 생성해서 구현한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;/** EmptyLayout.js */

// 레이아웃 파일마다 props는 공통적으로 적용할 것!
export default function EmptyLayout({ children }) {
  return (
      &amp;lt;&amp;gt;
          &amp;lt;div&amp;gt;
              { children }
          &amp;lt;/div&amp;gt;
      &amp;lt;/&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;레이아웃 파일 적용하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/pages/_app.js&lt;/b&gt; 내부에 해당 &lt;b&gt;레이아웃 파일을 적용&lt;/b&gt;한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;/** _app.js */

import '../styles/globals.css'
// 만든 레이아웃 가져오기
import DefaultLayout from '../layouts/DefaultLayout';
import EmptyLayout from '../layouts/EmptyLayout';

// 여러 레이아웃 별로 Key:Value를 설정한다 (Key 명칭은 자유!)
const layouts = { 
    L1: DefaultLayout,
    L2: EmptyLayout,
};

function MyApp({ Component, pageProps }) {
    // 해당 레이아웃 별(Component.layout) 지정된 페이지(children)를 불러온다
    const Layout = layouts[Component.layout] || ((children) =&amp;gt; &amp;lt;&amp;gt;{children}&amp;lt;/&amp;gt;);

    return (
        &amp;lt;&amp;gt;
            {/* 정의 된 Layout 태그로 레이아웃을 적용 */}
            &amp;lt;Layout&amp;gt;
                &amp;lt;Component {...pageProps} /&amp;gt;
            &amp;lt;/Layout&amp;gt;
        &amp;lt;/&amp;gt;
    ) 
}

export default MyApp;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;레이아웃 파일 지정하기&lt;/h2&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;pre class=&quot;javascript&quot;&gt;&lt;code&gt;/** pages/index.js */

import { NewAlbum } from '../components/Main/NewAlbum';
import { PopularContent } from '../components/Main/PopularContent';

// export할 함수명.layout = &quot;_app.js에 지정한 레이아웃 Key 명칭&quot;;
Home.layout = &quot;L1&quot;;
export default function Home() {

    return (
      &amp;lt;&amp;gt;
          &amp;lt;NewAlbum /&amp;gt;
          &amp;lt;PopularContent /&amp;gt;
      &amp;lt;/&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;/** pages/auth/signIn.js */

// 이런 식으로 각 페이지마다 원하는 레이아웃을 지정하면 된다!
signIn.layout = &quot;L2&quot;;
export default function signIn() {
    return (
        &amp;lt;&amp;gt;
            ...
        &amp;lt;/&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;611&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cc2Fp0/btrODO5Vhig/P1xhzHk1p7dR88rltZGqyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cc2Fp0/btrODO5Vhig/P1xhzHk1p7dR88rltZGqyK/img.png&quot; data-alt=&quot;네비게이션 바가 있는 레이아웃 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cc2Fp0/btrODO5Vhig/P1xhzHk1p7dR88rltZGqyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcc2Fp0%2FbtrODO5Vhig%2FP1xhzHk1p7dR88rltZGqyK%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;945&quot; height=&quot;611&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;611&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;네비게이션 바가 있는 레이아웃 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWtcDT/btrOGoypfFR/gX3VslJFNJHl4kBxyrbLGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWtcDT/btrOGoypfFR/gX3VslJFNJHl4kBxyrbLGK/img.png&quot; data-alt=&quot;네비게이션 바가 없는 레이아웃 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWtcDT/btrOGoypfFR/gX3VslJFNJHl4kBxyrbLGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWtcDT%2FbtrOGoypfFR%2FgX3VslJFNJHl4kBxyrbLGK%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;960&quot; height=&quot;576&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;네비게이션 바가 없는 레이아웃 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Self-Study/계란으로 바위치기</category>
      <category>layout</category>
      <category>next.js</category>
      <category>React</category>
      <category>레이아웃</category>
      <author>Raadian</author>
      <guid isPermaLink="true">https://raadi.tistory.com/163</guid>
      <comments>https://raadi.tistory.com/163#entry163comment</comments>
      <pubDate>Wed, 19 Oct 2022 23:14:13 +0900</pubDate>
    </item>
    <item>
      <title>[React] React의 라이프사이클</title>
      <link>https://raadi.tistory.com/162</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kyun2da.dev/react/리액트-라이프사이클의-이해/&quot;&gt;https://kyun2da.dev/react/리액트-라이프사이클의-이해/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@minbr0ther/React.js-리액트-라이프사이클life-cycle-순서-역할&quot;&gt;https://velog.io/@minbr0ther/React.js-리액트-라이프사이클life-cycle-순서-역할&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://react.vlpt.us/basic&quot;&gt;https://react.vlpt.us/basic&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;서론&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;React&lt;/b&gt;에서 &lt;b&gt;데이터가 업데이트&lt;/b&gt; 되는 상황은 기본적으로 &lt;b&gt;4가지&lt;/b&gt;이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;props가 바뀌는 경우&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;state가 바뀌는 경우&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부모 Component가 다시 렌더링 되는 경우&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Force Update 기능으로 인해 강제로 다시 렌더링 되는 경우&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 이벤트를 원활하게 처리하기 위해선 &lt;b&gt;라이프사이클(Life-Cycle)이&lt;/b&gt; 필요한데 React에서는 어떤 방식으로 흘러가는지 기술한다.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;React의 라이프사이클 (Hooks)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;React의 라이프사이클&lt;/b&gt;은 크게 &lt;b&gt;Mounting(생성) &amp;rArr; Updating(변경) &amp;rArr; UnMounting(삭제)&lt;/b&gt; 으로 이루어진다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;useState&lt;/h2&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;state와 setState의 형식&lt;/b&gt;으로 처리된다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function App() {
    const [number, setNumber] = useState(0);

    // setState를 통한 데이터 변경
    return (
        &amp;lt;button onClick={() =&amp;gt; setNumber(number + 1)}&amp;gt;숫자 증가&amp;lt;/button&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; setNumber(number - 1)}&amp;gt;숫자 감소&amp;lt;/button&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;useEffect&lt;/h2&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;pre class=&quot;arcade&quot;&gt;&lt;code&gt;// DOM이 업데이트 될 때 호출
useEffect(() =&amp;gt; {}); 

// DOM이 최초로 생성될 때만 호출
useEffect(() =&amp;gt; {}, []); 

// 특정 DOM만 최초로 생성될 때 호출, 특정 DOM 중 하나라도 변경되어도 다시 호출
useEffect(() =&amp;gt; {}, [DOM 1, DOM 2]); 
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;useEffect의 경우 기존 클래스 형 에서의 componentDidMount와&amp;nbsp;componentDidUpdate ,&amp;nbsp;componentWillUnmoun 기능이 합쳐졌다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;useContext&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Context API&lt;/b&gt;*를 이용한 &lt;b&gt;상태 값을 가져오는데 사용&lt;/b&gt;된다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;const value = useContext(사전에 정의한 Context 기능);
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Context API : React에서 전역적으로 상태를 관리하는 API. 과도한 props로 인한 로직 추적의 어려움을 개선해준다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;useReducer&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useState와 비슷한 기능으로, &lt;b&gt;컴포넌트 상에서 업데이트하는 상태 로직&lt;/b&gt;을 &lt;b&gt;외부로 분리&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function reducer(state, action) {
    switch (action.type) {
        case 'INCREMENT':
            return state + 1;
        case 'DECREMENT':
            return state - 1;
        default:
            return state;
    }
}

function Counter() {
    const [number, dispatch] = useReducer(reducer, 0);

    const onIncrease = () =&amp;gt; {
        dispatch({ type: 'INCREMENT' });
    };

    const onDecrease = () =&amp;gt; {
        dispatch({ type: 'DECREMENT' });
    };

    return (
        &amp;lt;div&amp;gt;
            &amp;lt;h1&amp;gt;{number}&amp;lt;/h1&amp;gt;
            &amp;lt;button onClick={onIncrease}&amp;gt;숫자 증가&amp;lt;/button&amp;gt;
            &amp;lt;button onClick={onDecrease}&amp;gt;숫자 감소&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;reducer : 현재 상태와 액션 객체를 파라미터로 받아와서 새로운 상태를 반환해주는 함수&lt;/b&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;useRef&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특정 DOM를 가리킬 때 사용&lt;/b&gt;되며 &lt;b&gt;useRef&lt;/b&gt;의 &lt;b&gt;.current&lt;/b&gt;로 전달된 인자로 초기화된 변경 가능한 &lt;b&gt;ref 객체로 반환&lt;/b&gt;한다. 이때, &lt;b&gt;반환된 객체는 라이프사이클에 따라 유지되어 사라진다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function InputSample() {
    const [name, setName] = useState('');
    const nameInput = useRef();

    const onReset = () =&amp;gt; {
        setInputs(name = '');
        nameInput.current.focus();
    };

    return (
        &amp;lt;div&amp;gt;
            &amp;lt;input
              name=&quot;name&quot;
              placeholder=&quot;이름&quot;
              value={ name }
              ref={ nameInput }
            /&amp;gt;
            &amp;lt;button onClick={ onReset }&amp;gt;초기화&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;useMemo&lt;/b&gt;&lt;/h2&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;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// 메모이제이션 된 특정 데이터가 없는 경우 렌더링 될 때마다 다시 계산
useMemo(() =&amp;gt; computeExpensiveValue(state), []);

// 메모이제이션 된 특정 데이터가 변경될 때 다시 계산
useMemo(() =&amp;gt; computeExpensiveValue(state1, state2), [state1]);
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;메모이제이션 : 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술&lt;/b&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;useCallback&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모이제이션 된 Callback을 반환&lt;/b&gt;하는 기능으로, &lt;b&gt;이미 연산 된 함수를 재활용한다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;useCallback(() =&amp;gt; { 함수(a, b); },
    [a, b],
);
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Self-Study/React</category>
      <category>React</category>
      <category>라이프사이클</category>
      <author>Raadian</author>
      <guid isPermaLink="true">https://raadi.tistory.com/162</guid>
      <comments>https://raadi.tistory.com/162#entry162comment</comments>
      <pubDate>Thu, 13 Oct 2022 15:19:52 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 데이터 바인딩의 이해</title>
      <link>https://raadi.tistory.com/161</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;References&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sungjk.github.io/2015/11/22/AngularJS(2).html&quot;&gt;https://sungjk.github.io/2015/11/22/AngularJS(2).html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@sunaaank/data-binding&quot;&gt;https://velog.io/@sunaaank/data-binding&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.datadriveninvestor.com/implementing-two-way-data-binding-without-using-any-framework-703963d00a94&quot;&gt;https://medium.datadriveninvestor.com/implementing-two-way-data-binding-without-using-any-framework-703963d00a94&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;데이터 바인딩이란?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 바인딩(Data Binding)&lt;/b&gt;은 &lt;b&gt;제공자(개발자)&lt;/b&gt;와 &lt;b&gt;사용자&lt;/b&gt;가 접하는 &lt;b&gt;데이터를 동일&lt;/b&gt;하게 묶는 기법으로, &lt;b&gt;자바스크립트 상에서 선언 및 반환한 데이터&lt;/b&gt;를 &lt;b&gt;HTML 상에서도 동일하게 보일 수 있게 끔&lt;/b&gt; 하는 것이다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    ...
&amp;lt;head&amp;gt;    
&amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;sample&quot;&amp;gt;변경 전&amp;lt;/div&amp;gt;

    &amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
        let dataSample = document.getElementById('sample');
        /** innerHTML를 통해 '변경 후'라는 데이터 바인딩을 함으로써 html상에서도 같은 데이터로 보여진다  */
        dataSample.innerHTML = '변경 후';
    &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;데이터 바인딩의 종류&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단방향 데이터 바인딩&lt;/h2&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;p data-ke-size=&quot;size16&quot;&gt;이를 이용한 대표적인 예시가 &lt;b&gt;리액트(React) 라이브러리&lt;/b&gt;로, &lt;b&gt;View 내부에서 부모 &amp;rArr; 자식 순으로 업데이트 된 데이터를 전달&lt;/b&gt;한 뒤 이를 &lt;b&gt;어플리케이션에게 콜백(Callback)&lt;/b&gt; 하는 형태이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DceWO/btrOtHL0cF6/I3QXcCXYfsR18Wrq5pWhtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DceWO/btrOtHL0cF6/I3QXcCXYfsR18Wrq5pWhtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DceWO/btrOtHL0cF6/I3QXcCXYfsR18Wrq5pWhtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDceWO%2FbtrOtHL0cF6%2FI3QXcCXYfsR18Wrq5pWhtk%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;720&quot; height=&quot;375&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;양방향 데이터 바인딩&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Controller(혹은 ViewModel)&lt;/b&gt;나 &lt;b&gt;View&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;이를 이용한 대표적인 예시가 &lt;b&gt;뷰(Vue) 프레임워크&lt;/b&gt;로, &lt;u&gt;&lt;b&gt;v-model&lt;/b&gt;과 &lt;b&gt;v-on*&lt;/b&gt;&lt;/u&gt;의 기능을 들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;v-model&lt;/b&gt;의 경우, &lt;b&gt;Model 상에서 업데이트&lt;/b&gt;가 될 때 &lt;b&gt;ViewModel&lt;/b&gt;을 거쳐 &lt;b&gt;View와 데이터를 일치&lt;/b&gt;시키는 방식이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;v-on&lt;/b&gt;의 경우, &lt;b&gt;View 상에서 업데이트&lt;/b&gt;가 될 때 &lt;b&gt;ViewModel&lt;/b&gt;을 거쳐 &lt;b&gt;Model과 데이터를 일치&lt;/b&gt;시킨다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Vue의 이런 기능을 이유로 MVVM 패턴이라고 일컫기도 한다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGDF7w/btrOtFHq3tz/mOYFQBbTkILyBxd2I0m8a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGDF7w/btrOtFHq3tz/mOYFQBbTkILyBxd2I0m8a1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGDF7w/btrOtFHq3tz/mOYFQBbTkILyBxd2I0m8a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGDF7w%2FbtrOtFHq3tz%2FmOYFQBbTkILyBxd2I0m8a1%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;690&quot; height=&quot;430&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Self-Study/Javascript</category>
      <category>JavaScript</category>
      <category>데이터바인딩</category>
      <author>Raadian</author>
      <guid isPermaLink="true">https://raadi.tistory.com/161</guid>
      <comments>https://raadi.tistory.com/161#entry161comment</comments>
      <pubDate>Thu, 13 Oct 2022 15:16:06 +0900</pubDate>
    </item>
  </channel>
</rss>