<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>horang-e.log</title>
        <link>https://velog.io/</link>
        <description>좋아하는걸 배우는건 신나🎵</description>
        <lastBuildDate>Thu, 30 Jan 2025 09:56:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>horang-e.log</title>
            <url>https://velog.velcdn.com/images/horang-e/profile/d1a7e452-777d-44cc-ae27-4ec0c774ee32/image.webp</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. horang-e.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/horang-e" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[이메일 입력시 xn-- 텍스트로 자동 변환]]></title>
            <link>https://velog.io/@horang-e/%EC%9D%B4%EB%A9%94%EC%9D%BC-%EC%9E%85%EB%A0%A5%EC%8B%9C-xn-%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%A1%9C-%EC%9E%90%EB%8F%99-%EB%B3%80%ED%99%98</link>
            <guid>https://velog.io/@horang-e/%EC%9D%B4%EB%A9%94%EC%9D%BC-%EC%9E%85%EB%A0%A5%EC%8B%9C-xn-%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%A1%9C-%EC%9E%90%EB%8F%99-%EB%B3%80%ED%99%98</guid>
            <pubDate>Thu, 30 Jan 2025 09:56:57 GMT</pubDate>
            <description><![CDATA[<p>실무중 발생한 에러에 대해 정리한 내용을 정리하고 공유해보려고 한다. 당시 들어온 패치건 중 이상한 오류가 있었다. 키보드는 한글로 설정되어 있고 메일 입력칸 아래 자동으로 뜨는 이메일을 선택 후 변경하려고 했을 때 한글이 입력되는게 아닌 혼자 알수없는 모양의 형식의 도메인으로 변경이 되는 현상이 발견되었고 해당 문제를 해결한 내용을 정리해봤다.
<img src="https://velog.velcdn.com/images/horang-e/post/bc287845-e04e-44d5-9fd0-87e0248b21c3/image.png" alt=""></p>
<p>🍪 상황 : 메일 입력란에 메일 영문으로 입력 후 한글로 바꾸고 입력시 영상과 마찬가지로 한글이 노출되는것이 아니라 자기 맘대로 xn--등의 텍스트로 자동 변경되는 문제 발생 </p>
<p>🍪 세부 상황 : <a href="mailto:accountname@domain.net">accountname@domain.net</a> 에서 한글로 변경후 타이핑시 accountname은 예상대로 한글이 입력됨 하지만 domain 혹은 net 부분에 한글 타이핑시 자동으로 텍스트가 변경되는것을 확인 </p>
<p>🍪 오류 이유 : input의 type을 email로 설정시 자체적으로 비 ASCII 코드가 들어올때 자동으로 <a href="//ko.wikipedia.org/wiki/%ED%93%A8%EB%8B%88%EC%BD%94%EB%93%9C">Punycodehttps</a> 로 변환됨</p>
<p>🍪 오류 해결 : <strong>간단하게 input의 타입을 text로  변경하여 해결</strong></p>
<p>이미 validation으로 이메일 타입을 체크하고 있기 때문에 문제가 생길 가능성이 없어서 그렇게 가능!</p>
<p>🍪 궁금증</p>
<p>그럼 왜 type email을 쓰지? 해당 타입으로 validation을 해주는것도 아니고 발생했던 오류처럼 어리둥절하게 퓨니코드로 변환되는데? 뭔가 이점이 있으니까 타입이 따로 빠져있는거 아닐까? type password 는 자동으로 * 표시를  해주니까 쓴다고 치는데… 뭐지?</p>
<p>🍪 클로드 답변</p>
<pre><code>1. 모바일 키보드 최적화
모바일에서 자동으로 @ 기호가 포함된 키보드를 보여줍니다
.com 등의 일반적인 도메인을 빠르게 입력할 수 있는 단축키를 제공합니다
2. 기본적인 이메일 형식 검증
submit 시점에 브라우저가 기본적인 이메일 형식 검증을 수행합니다
하지만 이것만으로는 불충분해서 보통 추가 검증이 필요합니다
3. 자동완성(autocomplete) 지원
브라우저의 자동완성 기능이 이메일 필드임을 인식하고 적절한 제안을 합니다
4. 접근성(Accessibility) 향상
스크린리더가 해당 필드가 이메일 입력란임을 인식하고 사용자에게 알려줍니다</code></pre><ul>
<li>답변의 내용을 보니 이메일 입력시에 포커스가 되면 자동으로 내가 입력했던 이메일들이 올라왔던걸 본적이 있다! 아마 해당 조건을 활성화시켜주는게 아닐까? 하는 생각을 한다.재밌다!!!!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[<React.Fragment>]]></title>
            <link>https://velog.io/@horang-e/React.Fragment</link>
            <guid>https://velog.io/@horang-e/React.Fragment</guid>
            <pubDate>Sat, 02 Nov 2024 15:10:03 GMT</pubDate>
            <description><![CDATA[<p>프레임 없는 프론트엔드 북 스터디를 하다가 &quot;프래그먼트&quot;라는 단어를 보고 꽂혀서 평소에 자주 사용하는 React.Fragment가 다른 div랑 무슨 차이인지가 너무 궁금해졌다. 그래서 찾아보니 개발 초기에 자주 보이는 에러인 </p>
<p><code>Failed to compile.
./src/App.js
Line 6:  Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment &lt;&gt;..&lt;/&gt;?</code></p>
<p>이 놈 때문이였는데. </p>
<pre><code class="language-js">return(
&lt;div&gt;hi&lt;/div&gt;
&lt;div&gt;bye&lt;/div&gt;
)</code></pre>
<p>이렇게 코드를 치면 위와 같은 에러가 발생하게 된다.(진짜 생판 몰랐을때 이거몇번 발생 했던 에러..) 
이처럼 최상위 태그가 있어야만 동작하는 이유는 리액트엔진이 해석하고 랜더링 하는 형태를 보면 더 쉽게 이해된다. 자바스크립트는 두 개 이상 리턴하지 못하기 때문.</p>
<pre><code class="language-js">//이러면 안됨!
return (
    React.createElement(&#39;div&#39;, {}, &#39;hi&#39;)
    React.createElement(&#39;div&#39;, {}, &#39;bye&#39;)
);</code></pre>
<p>그렇기 때문에 최상위 태그가 반드시 필요한거시다! 근데 저 태그를 감싸기 위해서 <div> 태그를 감싸준다고 하면? 추가적인 노드가 생성된다.</p>
<pre><code class="language-js">return (
  &lt;div&gt;
    &lt;div&gt;hi&lt;/div&gt;
    &lt;div&gt;bye&lt;/div&gt;
  &lt;/div&gt;
);
//리액트 엔진이 해석
return (
  React.createElement(&#39;div&#39;, null,
    React.createElement(&#39;div&#39;, null, &#39;hi&#39;),
    React.createElement(&#39;div&#39;, null, &#39;bye&#39;)
  )
);</code></pre>
<p>  근데 노드를 만들고 싶지 않으면? 그 때 사용하는것이 바로 Fragment 태그다. Fragment 태그는 최상위 태그로서 작동하고 key 값 또한 추가 할 수 있지만 노드를 생성하진 않는다. 너무 신기해...🥹</p>
<pre><code class="language-js">return (
  &lt;Fragment&gt;
    &lt;div&gt;hi&lt;/div&gt;
    &lt;div&gt;bye&lt;/div&gt;
  &lt;/Fragment&gt;
);
//리액트 엔진이 해석
return (
  React.createElement(React.Fragment, null,
    React.createElement(&#39;div&#39;, {}, &#39;hi&#39;),
    React.createElement(&#39;div&#39;, {}, &#39;bye&#39;)
  )
);</code></pre>
<p>이 내용이 더욱 와 닿고 신기했던 이유는 실제로 실무에서 개발을 하면서도 불필요하게 컴포넌트를 감싸기 위한 div 가 들어가야 하는 경우를 인지 하고 있었기 때문이다! 뭔가 굳이 없어도 되는 노드인데 추가되네 라고 생각을 가끔 했었기 때문에 이런 내용을 보고 좀 신기했다 ㅎㅎ 앞으로도 개발 할 때 잘 사용해야 할 것 같다.</p>
<blockquote>
<p>참고 : <code>&lt;&gt;&lt;/&gt;</code> 와 <code>&lt;Fragment&gt;&lt;/Fragment&gt;</code>는 똑같은 역할을 한다. 다만 Fragment 태그만 key값을 사용 할 수 있다.</p>
</blockquote>
<p>  <a href="https://www.memberstack.com/blog/react-fragment">참고글</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[github.io, Next.js(app router), tailwindcss 사용하여 나만의 사이트 만들기!]]></title>
            <link>https://velog.io/@horang-e/github.io-Next.jsapp-router-tailwindcss-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-%EB%82%98%EB%A7%8C%EC%9D%98-%EC%82%AC%EC%9D%B4%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@horang-e/github.io-Next.jsapp-router-tailwindcss-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-%EB%82%98%EB%A7%8C%EC%9D%98-%EC%82%AC%EC%9D%B4%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Fri, 11 Oct 2024 07:49:40 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/horang-e/post/577d2bbb-48ab-42fd-aee7-7edc082d21cd/image.png" alt=""></p>
<blockquote>
<p>이번에 포트폴리오의 필요성을 느껴 github page를 통해 배포하는 방법을 찾아 보고 서칭하고  성공한 내용을 담은 블로그다.!.! ㅎㅂㅎ</p>
</blockquote>
<h3 id="github-setting">Github Setting</h3>
<p><a href="https://docs.github.com/ko/pages/quickstart">공식문서</a>를 보면 아주 자세히 설명이 되어있다. 그치만 링크의 링크는 피곤하니까~</p>
<ol>
<li>우상단의 New 클릭 하여 새로운 레포 만들기
<img src="https://velog.velcdn.com/images/horang-e/post/1126d397-0865-4380-9da1-10a4efc17fd9/image.png" alt=""></li>
<li>레포 이름을 <strong>사용자깃허브아이디.github.io</strong> 로 생성!
<img src="https://velog.velcdn.com/images/horang-e/post/91a490e8-1e96-464b-b93e-cfcb4a842063/image.png" alt=""></li>
<li>세팅 진입
<img src="https://velog.velcdn.com/images/horang-e/post/23233fa4-6478-4ddd-b1be-5a55de5884d9/image.png" alt=""></li>
<li>code and automation에서 Pages클릭
<img src="https://velog.velcdn.com/images/horang-e/post/aa0728c5-9488-4179-8da8-fc4b3905e42a/image.png" alt=""></li>
<li>Build and deployment에서 브랜치 설정 후 save클릭! </li>
</ol>
<ul>
<li>위 과정은 해당 브랜치에 변경사항이 푸시되면 자동으로 배포를 실행하게 자체적으로 내장되어있다.
<img src="https://velog.velcdn.com/images/horang-e/post/78c6c765-b0b6-4bdc-b183-b6def94de61e/image.png" alt=""></li>
</ul>
<p>이 과정을 모두 거치고 나면 main 브랜치의 index.html이 http://사용자깃허브아이디.github.io 에 배포된다. 참 쉽쥬~? </p>
<p><em>근데.. Next.js는 메인 디렉토리에 index.html이 없는걸요..ㅠ 그러면 뭐가 나와요?!</em>
<img src="https://velog.velcdn.com/images/horang-e/post/5a8e912d-baf3-41b4-87ec-c720f132910e/image.png" alt="">
<img src="https://velog.velcdn.com/images/horang-e/post/d1ca0185-15a5-4985-82b4-54db14b5a6df/image.png" alt="">
그럼 어쩌냐며는! 이제 다음 과정을 살펴보자</p>
<h3 id="nextjs-setting">Nextjs Setting</h3>
<p>프로젝트 생성은 <a href="https://nextjs.org/docs/getting-started/installation">공식문서</a>를 참고해서 만들자 <del>.</del> </p>
<p>일단 기본적으로 지식을 가지고 가보자. Next.js는 서버에서 React의 JavaScript 코드를 실행하여 초기 HTML이 생성된다. 이 html을 우리는 배포해야한다. 그러기 위해서는 빌드, 빌드된 파일 배포 등의 과정을 거쳐야 우리가 원하는 화면이 노출될것이다!</p>
<p>그러니까 요약해보자면</p>
<blockquote>
<p>빌드 -&gt; 빌드된 파일 푸시 -&gt; 자동배포</p>
</blockquote>
<p>이렇게 과정을 거쳐야 한다는 것이다.
이 과정들을 좀 더 편하게 진행 하기 위해 gh-pages라는 라이브러리를 다운받아서 사용한다.</p>
<pre><code>npm install gh-pages</code></pre><p>그리고 package.json에 몇가지를 추가한다.</p>
<pre><code class="language-js">  &quot;homepage&quot;: &quot;https://사용자아이디.github.io/&quot;,
  &quot;scripts&quot;: {
    &quot;dev&quot;: &quot;next dev&quot;,
    &quot;build&quot;: &quot;next build&quot;,
    &quot;predeploy&quot;: &quot;npm run build&quot;,
    &quot;deploy&quot;: &quot;touch out/.nojekyll &amp;&amp; gh-pages -d out -t true&quot;,
    &quot;start&quot;: &quot;next start&quot;,
    &quot;lint&quot;: &quot;next lint&quot;
  },</code></pre>
<p>그리고 next.config.mjs도 수정한다.</p>
<pre><code class="language-js">/** @type {import(&#39;next&#39;).NextConfig} */

const nextConfig = {
  output: &#39;export&#39;,
  reactStrictMode: true,
  images: {
    unoptimized: true
  },
  trailingSlash: true,
};


export default nextConfig;
</code></pre>
<p>이렇게 수정후 </p>
<pre><code>npm run deploy</code></pre><p>명령어를 실행하면 predeploy를 먼저 실행 후 deploy 명령어를 실행한다. </p>
<p>📍 deploy명령어를 살펴보자.</p>
<pre><code>touch out/.nojekyll:

touch: 파일을 생성하는 Unix 명령어.
out/.nojekyll: &#39;out&#39; 디렉토리에 &#39;.nojekyll&#39;이라는 빈 파일을 생성.
목적: GitHub Pages가 Jekyll을 사용하여 사이트를 처리하는 것을 방지, Next.js와 같은 프레임워크로 빌드된 사이트에서 필요


gh-pages -d out -t true:

gh-pages: gh-pages 라이브러리를 실행. gh-pages 브랜치가 없다면 브랜치 생성, 있다면 해당 브랜치 aiming
-d out: &#39;out&#39; 디렉토리의 내용을 배포.일반적 Next.js의 빌드 출력 디렉토리.
-t true: &#39;dotfiles&#39;(점으로 시작하는 숨김 파일)도 포함하여 배포. 이는 &#39;.nojekyll&#39; 파일을 배포에 포함시키기 위해 필요.</code></pre><p>이런저런 과정을 거치고 나면 해당 레포지토리에 자동으로 gh-pages브랜치가 생성되고 build의 결과로 생긴 out폴더 안의 내용이 해당 브랜치로 푸시되어있다.</p>
<p><img src="https://velog.velcdn.com/images/horang-e/post/9ff6717a-2011-4bf7-b7cb-da186251c8b9/image.png" alt="">
그리고 아까 main브랜치로 고정시켜놨던 깃허브 세팅 또한 gh-pages로 변경후 저장한다.
<img src="https://velog.velcdn.com/images/horang-e/post/4e47ab24-5d1c-4c5c-9355-670c197f8147/image.png" alt="">
저장 이후 위 탭의 Actions를 누르면 배포되고있음을 확인 할 수 있다.
<img src="https://velog.velcdn.com/images/horang-e/post/18fe338f-2a32-4b6e-878c-d6ca580e73c0/image.png" alt="">
성공후 링크로 들어가면 성공적으로 배포되어 있는것을 확인 할 수 있다! 
<em>근데 아마 이상하게 npm run dev로 보는 페이지와는 다르게 css가 어딘가 없는것을 볼 수 있다. 그 세팅을 아래서 해보자!</em></p>
<h3 id="postcss-setting">postcss setting</h3>
<p>프로젝트 생성시 생성된 postcss.config.js를 수정해보자! 해당 파일은 css 후처리기로 모던 css 기능을 사용하고 브라우서 호환성을 높인다.(처음에 .mjs파일로 생성했는데 클로드씨가 js로 바꾸라고 해서 일단 그렇게 진행했음..)
일단 
<code>npm install autoprefixer --save-dev</code> ,</p>
<pre><code>module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};</code></pre><p>이렇게 수정후 npm run deploy를 진행하면 css가 적용된 모습을 확인할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프론트엔드 퍼포먼스 개선 2편 : 프리패칭]]></title>
            <link>https://velog.io/@horang-e/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%8D%BC%ED%8F%AC%EB%A8%BC%EC%8A%A4-%EA%B0%9C%EC%84%A0-2%ED%8E%B8-%ED%94%84%EB%A6%AC%ED%8C%A8%EC%B9%AD</link>
            <guid>https://velog.io/@horang-e/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%8D%BC%ED%8F%AC%EB%A8%BC%EC%8A%A4-%EA%B0%9C%EC%84%A0-2%ED%8E%B8-%ED%94%84%EB%A6%AC%ED%8C%A8%EC%B9%AD</guid>
            <pubDate>Sun, 22 Sep 2024 14:55:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/horang-e/post/5f8d90e4-256c-481d-b469-a40b776376a8/image.gif" alt=""></p>
<p>이번엔 저번 시리즈에 이어서 프리패칭 대해 공부한 내용을 정리해 보고자 한다!.!</p>
<h2 id="pre-fetching">PRE-FETCHING</h2>
<p>일단 프리패칭이란?
단어 그대로 <strong>pre-fetch</strong> 선행으로 fetching을 해오는 것을 뜻한다. mdn문서의 정의를 가져와보면 더 이해가 쉽게 되는데</p>
<blockquote>
<p>프리페치는 사용자가 가까운 미래에 탐색할 가능성이 &#39;있는&#39; 페이지에 대해 백그라운드에서 리소스를 추론적으로 가져오는 방식을 의미합니다. </p>
</blockquote>
<p>정의대로라면 사용자가 가까운 미래에 탐색할 가능성이 있는 페이지를 알아야 하는거잖아? 알 수 있는 방법은 여러가지가 있는데 그 부분은 내가 말하려는 내용과 살짝 멀어지기 때문에 생략해야지! (GA 심기..등)</p>
<h3 id="link-tag-prefetching">Link tag Prefetching</h3>
<pre><code class="language-js">&lt;link rel=&quot;prefetch&quot; href=&quot;/images/large-image.jpg&quot;&gt;
&lt;link rel=&quot;dns-prefetch&quot; href=&quot;https://example.com&quot;&gt;
&lt;link rel=&quot;preconnect&quot; href=&quot;https://example.com&quot;&gt;
&lt;link rel=&quot;prerender&quot; href=&quot;https://example.com/next-page&quot;&gt;</code></pre>
<p>link태그의 rel속성을 컨트롤 해서 원하는 href 리소스를 미리 가져와 캐시에 저장하는 방법이 있다. 속성은 여러가지가 있는데 간단하게 살펴보면..</p>
<ol>
<li><code>prefetch</code> : 특정 리소스 미리 요청</li>
<li><code>dns-prefetch</code> : 도메인의 dns조회를 미리 수행하여 실제 요청 시 시간을 절약</li>
<li><code>preconnect</code> : 서버와의 연결을 미리 설정</li>
<li><code>prerender</code> : 특정 페이지를 백그라운드에서 미리 랜더링</li>
</ol>
<h3 id="react-router-loader">React Router loader</h3>
<p>위는 html의 link태그를 사용한 방법이지만 React의 경우는? </p>
<pre><code class="language-js">import { createBrowserRouter, RouterProvider } from &#39;react-router-dom&#39;;

const router = createBrowserRouter([
  {
    path: &#39;/&#39;,
    element: &lt;Root /&gt;,
    loader: rootLoader,
    children: [
      {
        path: &#39;about&#39;,
        element: &lt;About /&gt;,
        loader: aboutLoader,
      },
    ],
  },
]);

function App() {
  return &lt;RouterProvider router={router} /&gt;;
}</code></pre>
<p>React Router의 loader기능을 사용하면 된다. react router의 공식 문서를 보면 이 방법은 해당 라우트의 컴포넌트가 랜더링 되기 전에 실행되는 함수를 정의할 수 있다.</p>
<h3 id="react-router-link">React Router Link</h3>
<pre><code class="language-js">// PrefetchLink.js
import React from &#39;react&#39;;
import { Link } from &#39;react-router-dom&#39;;

const PreFetchLink = ({ to, children, prefetch }) =&gt; {
  const prefetchComponent = () =&gt; {
    if (prefetch) {
      prefetch();
    }
  };

  return (
    &lt;Link to={to} onMouseEnter={prefetchComponent} onFocus={prefetchComponent}&gt;
      {children}
    &lt;/Link&gt;
  );
};

export default PreFetchLink;

//App.js
import PreFetchLink from &#39;./components/PreFetchLink&#39;;
...
...
&lt;PreFetchLink
   to=&quot;/&quot;
   prefetch={() =&gt; import(&#39;./components/Home&#39;)}&gt;
  Home
&lt;/PreFetchLink&gt;</code></pre>
<p>위 코드를 보면 실제로 해당 기능이 있는건 아니지만 Link컴포넌트에 onMouseEnter과 onFocus 기능을 사용해서 해당 children 에 마우스를 올리면 prefetch를 실행하여 해당 페이지를 미리 패칭해서 캐싱하게 된다. </p>
<p>위에 올린 세가지 방법 중 두번째 React Router loader의 경우 나머지 두가지 방법과 살짝 다르게 컴포넌트, 이미지, 리소스 등을 불러오는 것이 아닌 데이터를 미리 불러오는 방식으로 전통적인 프리패칭과는 좀 다르다.</p>
<h3 id="정리">정리</h3>
<p>이렇게 시리즈 두번째로 prefetching을 알아봤다. 여타 다른 방법과 마찬가지로 prefetching 또한 너무 과도하게 사용하게 된다면 불필요한 페칭, 캐시가 늘어 성능에 영향을 끼칠 수 있기 때문에 위에서 말한 <code>가까운 미래에 탐색할 가능성이 있는 페이지</code>를 여러가지 방법을 통해 확인 후 꼭 필요한 컴포넌트 등에만 적용해야 할 것 같다! </p>
<h2 id="마치며">마치며</h2>
<p>정리를 마치며 개인적으로 드는 생각은 1편 코드스플리팅에 비해서는 당장 내(개발자)눈에 엄청난 차이가 보인다! 유저 퍼포먼스가 엄청나게 개선되겠다! 이런방법이 있구나! 라는 생각은 사실 좀 덜 들기는 했다. 물론 내가 지금까지 했던 프로젝트의 사이즈가 작아서 그런게 크겠지만 나중에 실무에 적용해 볼 수 있는 큰 프로젝트도 해보고 싶따! 끗!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[어떤 개발자가 되고싶나요?]]></title>
            <link>https://velog.io/@horang-e/%EC%96%B4%EB%96%A4-%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EB%90%98%EA%B3%A0%EC%8B%B6%EB%82%98%EC%9A%94</link>
            <guid>https://velog.io/@horang-e/%EC%96%B4%EB%96%A4-%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EB%90%98%EA%B3%A0%EC%8B%B6%EB%82%98%EC%9A%94</guid>
            <pubDate>Thu, 12 Sep 2024 08:06:21 GMT</pubDate>
            <description><![CDATA[<p>최근 주니어 부트캠프에서 많은 개발자분들을 만나며 가장 많이 얘기 나눴던 부분이 </p>
<blockquote>
<p><strong>어떤 개발자가 되고 싶나요?</strong></p>
</blockquote>
<p>에 대한 내용의 대화였다. 모든 개발자 분들이 그렇진 않았지만 본인의 확고한 기준과 생각을 가진 개발자 분들이 너무나 멋져보여서 나도 한번 생각해보게 된 계기가 되었다.</p>
<p><img src="https://velog.velcdn.com/images/horang-e/post/ab7ed27c-92ea-469f-97a7-684abddea6a0/image.png" alt="부트캠프 초반">
<em>위 이미지는 부트캠프 초반에 멘토링 할 때 내가 썼던 내용이다.(아예 생각해본적이 없다는 증거..)</em></p>
<p>사실 그저 그냥 눈앞에 주어진 일만 수행하고 살아 왔기 때문에 나는 질문에 대한 답을 생각해본적이 진짜 첫 입사전에 말고는 없었다. 이번에 이력서도 쓰고 지원도 하고 부트캠프를 진행하면서 좀 그 질문에 대한 답을 진지하게 생각해 본 것 같다. 그래서 기록해두고 나중에 연차 찼을 때 또 보려고 기록해보려 한다. 🙄</p>
<h3 id="왜라는-질문에-답할-수-있는-개발자">&quot;왜?&quot;라는 질문에 답할 수 있는 개발자</h3>
<p><img src="https://velog.velcdn.com/images/horang-e/post/cda77879-5efe-48fa-9488-5dd0bad9219c/image.jpg" alt=""></p>
<p>내가 개발자에 큰 매력을 느꼈던 가장 큰 이유는 원인-해결-결과가 명확한게 아주 내스타일이였다..(이과-공대) 개발을 시작할 당시에 불확실한 입시준비를 하고 있었던 나였기 때문에 더욱 강하게 와닿았을 수 있을 것 같다.
이 내용과 약간 비슷하게 일을 하면서 느꼈던 되고싶은 개발자는 &quot;왜?&quot;에 대한 질문에 답할 수 있는 개발자가 되고 싶다는 점이였다. 의사 결정을 하던 어떤 업무를 하더라도 누군가 나의 결정에 대해 왜? 라고 물어보면 막힘없이 대답할 수 있는 개발자가 되고 싶다. 내가 어떤 결정을 할 때 내 스스로 의문을 품으면서 결정하는건 없었으면 한다...그러기 위해선? 끊임없이 공부해서 결정을 내릴때 명확한 근거를 가지고 결정을 내려야지! 라는 생각을 했다. </p>
<h3 id="누군가에게-인사이트를-줄-수-있는-개발자">누군가에게 인사이트를 줄 수 있는 개발자</h3>
<p><img src="https://velog.velcdn.com/images/horang-e/post/a99c6a55-c201-4e7f-b5dc-e2b1ad29dab1/image.jpeg" alt=""></p>
<p>이번 부트캠프를 하면서 가장 인상깊었던 부분이 비슷한 연차의 개발자 분들이 본인이 같은 연차의 개발자 분들에게 하고 싶은 내용의 발표를 준비해와서 공유해주시는 부분들이였다. 기술적인 내용, 본인의 가치관 등에 대한 내용이였는데 &quot;인사이트를 얻는다.&quot; 라는 문장에 대한 의미를 알게되었다. 사실 실무를 하면서 연차 높은 분들을 보면서 느꼈던 점은 오.. 역시 고연차 분들... 똑똑하셔 이거 뿐이였지만 비슷한 연차분들의 발표나 대화는 진짜 들으면서 벅찬? 느낌이 들었다. 나도 앞으로 개발자 분들이랑 대화를 나누면서 내 대화가 누군가에게 인사이트를 줄 수 있는 개발자가 되고싶다는 생각을 해보았다!</p>
<p>쓰고보니 죄다 공부해야 이룰 수 있는 목표들이다!....! 공부하자 나자신!!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[package.json에서 라이브러리 관리하기]]></title>
            <link>https://velog.io/@horang-e/package.json%EC%97%90%EC%84%9C-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@horang-e/package.json%EC%97%90%EC%84%9C-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 03 Sep 2024 08:28:34 GMT</pubDate>
            <description><![CDATA[<p>우리가 패키지json 파일을 보면 이것저것 콘텐츠가 많은데 이번엔 dependencis와 devDependencies 차이에 대해 적어보려고 한다!
<a href="https://docs.npmjs.com/cli/v10/configuring-npm/package-json#dependencies">npm공식문서</a></p>
<pre><code> &quot;dependencies&quot;: {
    &quot;chart.js&quot;: &quot;^4.3.0&quot;,
    &quot;react&quot;: &quot;^18.2.0&quot;,
    &quot;react-chartjs-2&quot;: &quot;^5.2.0&quot;,
    &quot;react-dom&quot;: &quot;^18.2.0&quot;,
    &quot;react-router-dom&quot;: &quot;^6.11.2&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;@babel/core&quot;: &quot;^7.22.1&quot;,
    &quot;@babel/preset-env&quot;: &quot;^7.22.4&quot;,
    &quot;@babel/preset-react&quot;: &quot;^7.22.3&quot;,
    &quot;babel-loader&quot;: &quot;^9.1.3&quot;,
    &quot;css-loader&quot;: &quot;^7.1.2&quot;,
    &quot;css-minimizer-webpack-plugin&quot;: &quot;^7.0.0&quot;,
    &quot;html-webpack-plugin&quot;: &quot;^5.5.0&quot;,
    &quot;style-loader&quot;: &quot;^4.0.0&quot;,
    &quot;terser-webpack-plugin&quot;: &quot;^5.3.10&quot;,
    &quot;webpack&quot;: &quot;^5.84.1&quot;,
    &quot;webpack-bundle-analyzer&quot;: &quot;^4.9.0&quot;,
    &quot;webpack-cli&quot;: &quot;^5.1.4&quot;,
    &quot;webpack-dev-server&quot;: &quot;^4.15.0&quot;
  },</code></pre><p>이렇게 dependencies와 devDependencies 두가지 항목으로 나눠져 있는걸 보곤 한다. 이 둘의 차이는 어떤걸까?</p>
<p>말 그대로 <code>dev</code>dependencies는 개발 당시에만 사용하는 라이브러리들로 실제 production 빌드에는 포함되지 않는다. 테스트 도구나 트랜스파일러 등의 라이브러리등은 실제로 production에 사용되는 라이브러리가 아니기 때문에 dependencies 가 아닌 devdependencies 에 포함시켜야 한다. 이렇게 함으로써 얻는 이점은?</p>
<p>첫번째 빌드 최적화가 가능하다 빌드시 프로덕션 환경에서는 dependencies 에 명시된 패키지들만 설치된다. 그로 인해 빌드 크기가 줄어들고 설치시간이 단축된다. 두번째 package.json파일만 보고도 어떤 패키지가 dev환경에서 사용되는 패키지인지 한눈에 확인 할 수 있다.</p>
<p>devdependencies로 다운 받는 명령어를 잠깐 알아보자! (npm 쓴다고 가정)</p>
<blockquote>
<p>npm install --save-dev [package-name]
npm i -D [package-name]
npm add -D [package-name]</p>
</blockquote>
<p>이렇게 세가지 명령어를 통해 디펜던시 패키지로 인스톨이 가능하다! 무분별한 npm i 보다 좀 계획..?적으로 분리해서 패키지 관리를 해야겠다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[날것의 항해 플러스 프론트엔드 후기( + 할인코드)(+ 항플 Lite 할인코드)]]></title>
            <link>https://velog.io/@horang-e/%EB%82%A0%EA%B2%83%EC%9D%98-%ED%95%AD%ED%95%B4-%ED%94%8C%EB%9F%AC%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%9B%84%EA%B8%B0-%ED%95%A0%EC%9D%B8%EC%BD%94%EB%93%9C-%ED%95%AD%ED%94%8C-Lite-%ED%95%A0%EC%9D%B8%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@horang-e/%EB%82%A0%EA%B2%83%EC%9D%98-%ED%95%AD%ED%95%B4-%ED%94%8C%EB%9F%AC%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%9B%84%EA%B8%B0-%ED%95%A0%EC%9D%B8%EC%BD%94%EB%93%9C-%ED%95%AD%ED%94%8C-Lite-%ED%95%A0%EC%9D%B8%EC%BD%94%EB%93%9C</guid>
            <pubDate>Mon, 26 Aug 2024 14:08:08 GMT</pubDate>
            <description><![CDATA[<p>이 글을 보고있는 당신!
<img src="https://velog.velcdn.com/images/horang-e/post/32ce36b0-fc62-4f5e-87f2-d71e1a8f5e46/image.jpeg" alt="">
주니어 부트 캠프에 대한 관심으로 파도타기(응?) 하다가 여기까지 오셨군요. 고민하고 계신 여러분들을 위해 제가 이번 항해 플러스 프론트엔드2기를 진행하며 느꼈던 점을 공유해 보고자 합니다.</p>
<blockquote>
<p>후기 한줄 요약 <strong>&quot;아 나 진짜 무능하고 별거없는 개 쪼랩 개발자구나..&quot;</strong></p>
</blockquote>
<p>일단 저는 <strong>비전공자</strong>, <strong>20대후반</strong>의 나이에 항해99를 통해 개발자로 직무전환을 하게 되었습니다. 개발자를 선택한 이유는 솔직히 돈 잘번댔고(<em>아님</em>), 개발자는 모셔간댔고(<em>아님</em>), 연차가 무기라고 했어서(<em>아님</em>) 였기 때문이였습니다. 물론 셋 다 아니였지만 직무 자체도 워낙 저랑 잘 맞았고 개발하는게 그냥 너무 재밌어서 개발자로 취직하고 2년의 실무도 큰 일테기 없이 진행 해 왔습니다.</p>
<p>실무를 진행한 회사는 <em>스타트업, 사수없음, 주니어 개발자들만 있음, 실사용 유저 거의 없음, 피쳐단위의 추가 개발만 계속 진행</em> 의 대환장 파티였고 어느 순간 무리없이 개발을 진행하는 개발자로서의 제 자신에 대해 이게 맞나?그냥 이렇게 그저그런 개발자로 쭉 살면 되는걸까? 라는 고민이 어느 순간 들기 시작했습니다.</p>
<p>이런 저런 이유로 회사를 그만 두게 되었고 그만 둔 후 &quot;<em>내 고민들을 어디에 풀고 이야기 나누지..?나만 이런걸까? 어떻게 시작해야하지?</em>&quot; 라는 생각이 들어 개발자 커뮤니티에 대한 고민이 생겼고 부트캠프를 진행했던 항해 99에서 <img src="https://velog.velcdn.com/images/horang-e/post/1a23f1f1-c482-4b95-b0ff-731b0ed5bd5a/image.jpeg" alt="광고문자">
이런 내용의 광고 글을 거의 수료후 2년간 계속..지속적으로 뇌속에 각인을 해왔었고(가스라이팅 당한건가..?) 자연스럽게 항해 플러스 프론트엔드를 찾아보게 되었습니다. 사이트 들어가자마자 어? 이거 신청해보고싶다.. 했던 이유는 바로 <strong>커리큘럼</strong>과 <strong>네트워킹</strong> 때문이였습니다. <img src="https://velog.velcdn.com/images/horang-e/post/622143e9-0e0e-4c20-828f-25a64881c8aa/image.png" alt="커리큘럼">
요즘 구직 글들을 보면 대부분의 회사에서 우대사항에 들어가있는 키워드들이 커리큘럼에 모두 들어가 있었기 때문에가 1빠따였고 비슷한 연차, 같은 직무, 돈을 낼만한 열정 이 세가지를 모두 갖춘 사람들이 모여서 공부를 한다는 사실이 또 한번 매력적이였습니다! (<em>+12개월 무이자할부..굉장히 매력적</em>) </p>
<p>아무튼 이러저러한 이유로 항해 플러스 2기가 시작되었고 기대했던 것 보다(기대가 크지 않았음..) 너무나 알차고 뿌듯한 10주를 보내게 되었습니다. 알찼던 이유를 생각해보면</p>
<hr>
<ol>
<li><strong>발제 자료들의 퀄리티</strong>
코치님들이 준비해주시는 발제 자료들과 발제 내용들이 굉장히 퀄리티 있고 충분히 발제 자료만으로도 공부할 수 있을정도로 꼼꼼했고 평생 소장하고 싶을 정도들의 퀄리티였습니다.</li>
<li><strong>비슷한 연차분들의 다양한 고민</strong>
저희 2기는 거의 대부분이 1~3년차 사이의 주니어 분들이셨는데 각자 처한 상황, 환경들에 대해 들을 수 있는 자리가 생겨 너무 좋았던것 같습니다. 중간에 수강생 분들이 본인들이 각자 정한 주제를 가지고 발표를 하는 세션이 있는데 그부분이 진짜 왕좋았어요... 막 인싸이트를 얻어가는 느낌? (+ 우리끼리 코드리뷰)</li>
<li><strong>루즈해지지 못하게 막는 과제</strong>
물론 발제날에 발제를 듣고 보는것도 너무 좋았지만 해당 발제와 맞는 내용의 과제를 가지고 일주일 동안 고민해보는게 또 하나의 오 나 열심히 했다! 하는 생각이 들게 하는 포인트? 였다고 생각해요. 물론 과제를 하고 통과함에 따라서 달라지는 뱃지 컬러..!도 한몫 하긴 했어요 ㅎㅎ</li>
<li><strong>세상 알찬 주1회 팀별 멘토링</strong>
팀별로 매주 1회씩 멘토님과 멘토링하는 그 한시간이 정말로 알찼던것 같아요. 궁금한 내용에 대해 답변해주시는것 또한 너무나 좋은 시간이였지만 멘토님들은 주로 어디서 인사이트를 얻고, 어떤식으로 실무 진행을 하시는지, 큰 회사들은 프로세스가 어떻게 되는지, 주니어들의 고민에 대해 어떻게 생각하시는지 등의 주니어 개발자로서의 궁금증을 듣고 함께 고민해주시고 공유해주시는게 정말 큰 힐링중에 하나였습니다. 공감해주시고 해결해 주시려고 하는게 그렇게 큰 힐링 포인트가 될줄은 몰랐지만... 최고의 힐링타임!</li>
<li><strong>운영진 분들의 빠른 피드백 수용</strong>
이 부분은 항해에 감동받았던 포인트 중 하나인데요 매주 발제가 끝날때 마다 해당 주차에 대한 피드백을 받아 매주 피드백을 수용하려고 노력하시는 모습이 좀 인상깊었습니다. 반영되지 않은 내용들도 있었지만 대부분은 반영 되었던 것 같아요.</li>
</ol>
<p>뭐 죄다 좋은점 밖에 없냐?? 하면 이제 단점, 비추내용 읊어볼게요(단호).</p>
<hr>
<ol>
<li><strong>정착되지 않은 시스템</strong>
위에 5번과 일맥 상통하는 내용인데 어떤 분들에게는 이 부분이 큰 단점이 될 수 있을것 같아요. 이건 같이 계셨던 분이 하셨던 말인데 우리도 돈을 내고 들어왔는데 우리한테 피드백을 받아서 시스템이 계속 수정되고 변화되는건 아닌것 같다라는 분이 있어서 그말을 듣고나니 그건 그렇네.. 라는 생각이 들곤 했죠. 물론 프론트엔드 플러스 코스가 2기라서 그렇겠지만 만약 나는 딱 짜여진 시스템에서 공부하고싶어! 하면 고민을 좀 해보셔야 할 수도?</li>
<li><strong>절대적인 시간 부족</strong>
이건 단점이라기 보다는 만약 내가 회사에서 <em>10주사이에 큰 프로젝트를 들어갈 일이 있다.</em> <em>우리회사는 야근이 일상이다.</em> <em>난 워라밸을 챙기고싶다</em>. 하는 현직자 분들은 다시한번 잘 생각해 보시는게 맞을것 같아요. 저는 물론 백수라 10주동안 과제하고 발제 소화하는데 그렇게 큰 무리는 없었지만 같이 하시는 분들은 일과 병행하는 공부 시간, 과제 때문에 엄청 스트레스를 받으시더라구요 ㅠ.ㅜ 사실 내가 돈을 더 잘 벌기 위해 돈을 투자해서 공부하는거잖아요? 근데 그 돈만큼 내가 공부하지 못했다는 자괴감, 안타까움 이런게 있으신것 같더라구요. 충분히 이해가 가기도 하구요. </li>
<li><strong>이력서에 쓸 내용은 없음</strong>
사실 첨에 신청하면서 어 이거 해봤다. 정도로 이력서에 써야지? 하는 생각이 어느정도 있었는데 사실 10주동안 그 많은 내용을 보고 배웠다. 라고 이력서에 써 봤자 담당자 입장에서는 그래서 그걸 배워서 실무에서 퍼포먼스를 냈어? 라고 한다면 사실 대답할 말이 없을것 같아요. 이걸 배워서 실제 현직에서 써먹고 성과를 내야! 이력서에 쓸 수 있을만한 내용들입니다. 우린 주니어니까요!</li>
</ol>
<p>이렇게 장점과 단점을 정리해 봤습니다. 여러분들의 결정에 어느정도 도움이 되었을까요..? 되었기를 바라면서..🫶</p>
<p>저는 항해 플러스 프론트엔드 2기 코스를 진행하면서 느꼈던 가장 큰 느낌은 위에 한줄 요약에서 말했듯이ㅋㅋ
<strong>&quot;아 나 진짜 무능하고 별거없는 개 쪼랩 개발자구나..&quot;</strong>
사실 앞에서도 말했지만 2년정도 실무를 하면서 동료분들한테 기술적 질문을 받고 해결해 주기도 하고 실무도 기술적으로 큰 문제 없이 잘 쳐내고 하다보니 내가 꽤나 잘 해나가고 있구나! 나 다른데서도 왠만큼 하는 개발자겠지? 하는 <em>오만방자한</em> 생각을 하고 살았었답니다.. 그런데 와서 공부해보니 나는 그저 햄스터통에서 휠을 아주 잘 굴리는 갇힌 개발자였구나! 라는 사실로(팩트) 얻어 맞았답니다. 그치만 어느 순간 잊고 살았던 배움에 대한 즐거움, 동료 개발자들, 멘토님들에게 얻는 인싸이트들이 너무나 달콤해서 <strong>나도 앞으로 인싸이트를 줄 수 있는 개발자</strong>가 되어야지! 하는 다짐을 한번 해봤답니다.</p>
<p>10주, 등록비가 절대 적고 짧은 시간이 아니지만 그 돈, 그 시간을 투자하는 개발자 동료분들을 만나 이야기를 나누고 공부할 수 있다는건 진짜 엄청나게 큰 장점인것 같습니다! 혹시 주니어 부트캠프를 고민하고 계신 분들이라면 여기저기 잘 비교해보시고 제 글을 참고해서 본인에게 맞는 부트캠프를 하셨으면 좋겠어요. 주니어 부트 캠프 자체는 진짜 여유가 있다면 꼭 한번 해보시는걸 추천드리는 바 입니다!<img src="https://velog.velcdn.com/images/horang-e/post/65e79b8b-1ad5-4cbc-a66d-17f849f33f57/image.png" alt=""></p>
<h3 id="할인코드">할인코드</h3>
<p>항플 신청 시 제가 제공해드린 할인코드를 사용하시면 20만원의 등록금을 할인 받으실 수 있습니다!
할인코드 : WE9tsU</p>
<p>항해 플러스 Lite 할인코드 : WE9tsU (10만원 등록금 할인)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프론트엔드 퍼포먼스 개선 1편 : 코드 스플리팅]]></title>
            <link>https://velog.io/@horang-e/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%A3%BC%EB%8B%88%EC%96%B4-%EC%9D%B4%EB%A0%A5%EC%84%9C%EC%97%90-%EC%9D%B8%EC%83%81%EC%A0%81%EC%9D%B8-%ED%95%9C-%EC%A4%84-%EB%82%A8%EA%B8%B0%EA%B8%B0%EC%84%B1%EB%8A%A5-%ED%96%A5%EC%83%81-%EC%BD%94%EB%93%9C-%EC%8A%A4%ED%94%8C%EB%A6%AC%ED%8C%85</link>
            <guid>https://velog.io/@horang-e/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%A3%BC%EB%8B%88%EC%96%B4-%EC%9D%B4%EB%A0%A5%EC%84%9C%EC%97%90-%EC%9D%B8%EC%83%81%EC%A0%81%EC%9D%B8-%ED%95%9C-%EC%A4%84-%EB%82%A8%EA%B8%B0%EA%B8%B0%EC%84%B1%EB%8A%A5-%ED%96%A5%EC%83%81-%EC%BD%94%EB%93%9C-%EC%8A%A4%ED%94%8C%EB%A6%AC%ED%8C%85</guid>
            <pubDate>Mon, 26 Aug 2024 12:12:20 GMT</pubDate>
            <description><![CDATA[<p>프론트엔드 개발자로서 할 수 있는 성능 향상..? 유저 퍼포먼스 개선? 주니어라면 한번쯤 내 프로젝트의 성능 향상을 하고싶다! 라는 생각을 해본 경험이 있다고 생각한다. 그리고 실무에서 성능 향상을 실제로 향상 시켜본 구체적인 경험은 채용 담당자 입장에서는 충분히 매력적일 것이라고도 생각된다. (수치화 까지 한다면 프론트엔드 이력서의 약점...보완.. 이 되지 않을까..?) 그래서 이번에 찍먹해볼 일이 있어 강의를 듣다가 더 찾아보고 싶어져서 이렇게 공부하게 되었다!</p>
<p><img src="https://velog.velcdn.com/images/horang-e/post/5f8d90e4-256c-481d-b469-a40b776376a8/image.gif" alt=""></p>
<p>일단은 위 컨닝페이퍼에서 코드스플리팅에 대해 먼저 공부하고 정리해 보고자 한다! </p>
<h2 id="code-splitting">CODE SPLITTING</h2>
<blockquote>
<p>코드 스플리팅은 말 그대로 코드 쪼개기! 이다.
코드를 쪼갤 수 있는 방법들은 아래와 같다.</p>
</blockquote>
<h3 id="라우팅-기반의-코드-스플리팅">라우팅 기반의 코드 스플리팅</h3>
<p>요지가 무언가 하니 프론트엔드는 html위에 js 스크립트를 그린다.  <img src="https://velog.velcdn.com/images/horang-e/post/cd53a786-9394-4cd9-b9b4-772ee098c2ea/image.png" alt="">
이런 페이지가 있다고 해보자. 
하나의 js파일에 모든 home, dashboard, profile, settings, advanved feature을 몰아넣고 조건에 따라 화면만 변경된다고 하면 첫 화면을 그릴 때 <strong>js청크 파일의 크기</strong>가 엄청나게 커져 첫 로딩이 한세월 걸릴 것이다.</p>
<p>*<em>하지만 만약 라우팅을 사용한다면? *</em></p>
<p>home, dashboard, profile, settings, advanved feature 모두 페이지 라우팅을 진행하게 된다면 해당 라우트 이동했을때에만 <strong>쪼개진 해당 컴포넌트의 js 청크</strong>가 로딩되게된다. 그렇게 된다면 기존에 모든 라우트가 한번에 로딩되게 하는것보다 유저의 청크 로딩 속도가 훨씬 빨라지게 되어 퍼포먼스 또한 향상이 될것이다!</p>
<h3 id="컴포넌트-기반-스플리팅">컴포넌트 기반 스플리팅</h3>
<p>큰 컴포넌트나 자주 사용되지 않는 컴포넌트를 별도로 분리하여 <strong>동적으로 로드</strong>할 수 있다. React.lazy()와 Suspense를 사용하면 이를 쉽게 구현할 수 있다. </p>
<pre><code class="language-js">// App.js
import React, { Suspense } from &#39;react&#39;;

// 동적으로 import할 컴포넌트를 React.lazy()
const HeavyComponent = React.lazy(() =&gt; import(&#39;./HeavyComponent&#39;));

function App() {
  return (
    &lt;div&gt;
      &lt;h1&gt;내 앱&lt;/h1&gt;
      &lt;Suspense fallback={&lt;div&gt;로딩 중...&lt;/div&gt;}&gt;
        &lt;HeavyComponent /&gt;
      &lt;/Suspense&gt;
    &lt;/div&gt;
  );
}

export default App;

// HeavyComponent.js
import React from &#39;react&#39;;

function HeavyComponent() {
  return &lt;div&gt;이것은 무거운 컴포넌트입니다.&lt;/div&gt;;
}

export default HeavyComponent;</code></pre>
<ul>
<li>어디선가 많이 들어본 Suspense! 이 친구를 사용하면 예시처럼 무거운 컴포넌트가 로딩되는 중 유저에게 백지를 보여주는것이 아닌 fallback의 화면을 보여주게된다. </li>
<li>React.lazy의 경우 동적으로 컴포넌트를 임포트하여 필요할 때만 로딩되게 한다.</li>
</ul>
<p>이 두가지 설정으로 <strong>초기 번들 사이즈를 줄여</strong> 유저는 무거운 컴포넌트가 로드되는 동안 빈 화면이 아닌 <strong>로딩 화면</strong>을 보며 로딩 중임을 확인 할 수 있다.</p>
<p>실제 프로젝트에서는 모달, 복잡한 차트, 대시보드와 같은 무거운 컴포넌트등에 적용하게 되면 효과를 볼 수 있다!</p>
<h3 id="이벤트-기반-스플리팅">이벤트 기반 스플리팅</h3>
<p>이벤트 기반 스플리팅은 단어에서 알 수 있겠지만 특정 사용자 상호작용이나 이벤트가 발생했을 때만 <strong>필요한 코드를 동적으로 로드</strong>한다. </p>
<pre><code class="language-js">import React, { useState } from &#39;react&#39;;

function App() {
  const [showModal, setShowModal] = useState(false);
  const [ModalComponent, setModalComponent] = useState(null);

  const handleOpenModal = async () =&gt; {
    if (!ModalComponent) {
      // 동적으로 모달 컴포넌트를 import
      const { default: Component } = await import(&#39;./Modal&#39;);
      setModalComponent(() =&gt; Component);
    }
    setShowModal(true);
  };

  return (
    &lt;div&gt;
      &lt;h1&gt;이벤트 기반 코드 스플리팅 예제&lt;/h1&gt;
      &lt;button onClick={handleOpenModal}&gt;모달 열기&lt;/button&gt;
      {showModal &amp;&amp; ModalComponent &amp;&amp; &lt;ModalComponent onClose={() =&gt; setShowModal(false)} /&gt;}
    &lt;/div&gt;
  );
}

export default App;

// Modal.js
import React from &#39;react&#39;;

function Modal({ onClose }) {
  return (
    &lt;div style={{ border: &#39;1px solid black&#39;, padding: &#39;20px&#39; }}&gt;
      &lt;h2&gt;모달 내용&lt;/h2&gt;
      &lt;p&gt;이 모달은 동적으로 로드되었습니다.&lt;/p&gt;
      &lt;button onClick={onClose}&gt;닫기&lt;/button&gt;
    &lt;/div&gt;
  );
}

export default Modal;</code></pre>
<p>예시를 읽어보기만 해도 어떤 느낌인지 살짝은 감이온다! 예시를 보면 handleOpen이라는 유저의 이벤트 발생시 Component를 동적으로 불러와 state로 저장하고 그 때! 화면에 동적으로 불러온 컴포넌트를 노출시켜준다. 
(이 방법은 너무나 신기하자나?0ㅇ0) 이런 이벤트 기반 스플리팅은 위 두가지 스플리팅 방법과 마찬가지로 <strong>초기 로드 속도</strong>를 줄여 유저 퍼포먼스를 향상 시켜준다.</p>
<h3 id="우선순위-기반-스플리팅">우선순위 기반 스플리팅</h3>
<p>중요하지 않은 기능이나 콘텐츠는 초기 로드 후 지연 로딩으로 처리한다. 이는 초기 페이지 로드 시간을 줄이는 데 도움이 된다.</p>
<pre><code class="language-js">import React, { Suspense, lazy } from &#39;react&#39;;

// 높은 우선순위 컴포넌트는 일반적인 방식으로 import
import Header from &#39;./Header&#39;;
import MainContent from &#39;./MainContent&#39;;

// 낮은 우선순위 컴포넌트는 lazy로 import
const Footer = lazy(() =&gt; import(&#39;./Footer&#39;));
const Sidebar = lazy(() =&gt; import(&#39;./Sidebar&#39;));
const Comments = lazy(() =&gt; import(&#39;./Comments&#39;));

function App() {
  return (
    &lt;div&gt;
      &lt;Header /&gt;
      &lt;MainContent /&gt;
      &lt;Suspense fallback={&lt;div&gt;로딩 중...&lt;/div&gt;}&gt;
        &lt;Footer /&gt;
      &lt;/Suspense&gt;
      &lt;Suspense fallback={&lt;div&gt;사이드바 로딩 중...&lt;/div&gt;}&gt;
        &lt;Sidebar /&gt;
      &lt;/Suspense&gt;
      &lt;Suspense fallback={&lt;div&gt;댓글 로딩 중...&lt;/div&gt;}&gt;
        &lt;Comments /&gt;
      &lt;/Suspense&gt;
    &lt;/div&gt;
  );
}

export default App;

// MainContent.js
import React, { useState, lazy, Suspense } from &#39;react&#39;;

const HeavyChart = lazy(() =&gt; {
  return new Promise(resolve =&gt; {
    // 3초 후에 컴포넌트 로드 (네트워크 지연 시뮬레이션)
    setTimeout(() =&gt; resolve(import(&#39;./HeavyChart&#39;)), 3000);
  });
});

function MainContent() {
  const [showChart, setShowChart] = useState(false);

  return (
    &lt;div&gt;
      &lt;h1&gt;메인 콘텐츠&lt;/h1&gt;
      &lt;p&gt;이 부분은 즉시 로드됩니다.&lt;/p&gt;
      &lt;button onClick={() =&gt; setShowChart(true)}&gt;차트 보기&lt;/button&gt;
      {showChart &amp;&amp; (
        &lt;Suspense fallback={&lt;div&gt;차트 로딩 중...&lt;/div&gt;}&gt;
          &lt;HeavyChart /&gt;
        &lt;/Suspense&gt;
      )}
    &lt;/div&gt;
  );
}

export default MainContent;</code></pre>
<p><strong>예시를 보면 세가지 포인트를 찾아낼 수 있다.</strong></p>
<ol>
<li>App컴포넌트에서 Header과 MainContent는 우선순위가 높게 간주되어 일반적인 방식으로 import, 나머지 Footer, Sidebar, Comments는 비교적 낮은 우선 순위로 간주되어 <strong>lazy import</strong>.</li>
<li>각 지연 컴포넌트는 Suspense로 감싸서 대체 UI 노출</li>
<li>MainContent에서 무거운 컴포넌트인 HeavyChart <em><strong>조건부</strong></em> 로딩</li>
</ol>
<p>이런 방법을 사용하여 우선순위 기반 스플리팅을 사용 할 수 있다. 이 방법은 사용사자 어떤 화면을 먼저 확인하고 봐야 하는지에 대한 파악이 필요할 것 같다! 측정 방법은... 성능 측정 도구를 사용해야 한다고 한다.</p>
<h3 id="벤더써드파티-라이브러리-스플리팅">벤더(써드파티 라이브러리) 스플리팅</h3>
<p>애플리케이션 코드와 서드파티 라이브러리를 분리하여 <strong>캐싱 효율</strong>을 높이고 빌드 시간을 줄이는 기법이다.이 방법은 <strong>웹팩</strong>에 해당 설정을 넣어두면 웹팩이 스스로 라이브러리코드와 앱 코드로 분리하고 캐싱하게 된다. 사실 여기까지만 들으면 잘 감이 오지 않는다.</p>
<pre><code>// 기존 방식의 결과
main.js (5MB) - 앱 코드 + React + 기타 라이브러리

&lt;script src=&quot;main.js&quot;&gt;&lt;/script&gt;

// 벤더 스플리팅 적용 후 결과
main.js (1MB) - 앱 코드
vendor-react.js (2MB) - React 라이브러리
vendor-other.js (2MB) - 기타 라이브러리

&lt;script src=&quot;vendor-react.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;vendor-other.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;main.js&quot;&gt;&lt;/script&gt;</code></pre><p>위를 보면 약간 이해가 되는데 기존 방식으로 진행시 main.js에서 앱코드와 모든 라이브러리 코딩을 직렬적으로 수행하지만 벤더 스플리팅 적용시 앱코드와 분리되어 <strong>병렬적</strong>으로 로딩된다.</p>
<p>이 방법의 장점은 </p>
<ol>
<li>필요 코드만 먼저 로드 가능하여 <strong>초기 로딩 속도가 증가</strong>될 수 있다.</li>
<li>캐싱을 통해 첫 랜더 이후 빠른 로딩이 가능하다.</li>
</ol>
<p>이렇게 두가지를 꼽을 수 있을것같다. 사용 방법은 차후에 정리해 보도록 해야겠다!</p>
<h3 id="공통-모듈-스플리팅">공통 모듈 스플리팅</h3>
<p>여러 페이지나 컴포넌트에서 공통으로 사용되는 모듈을 별도의 청크로 분리하여 중복을 줄이고 <strong>캐싱을 개선</strong>한다. 이 방법 역시 마찬가지로 <strong>웹팩</strong>에게 해줘!! 하는 방법중에 하나다. 작동 방식을 살펴보자!</p>
<pre><code class="language-js">// webpack.config.js
const path = require(&#39;path&#39;);

module.exports = {
  entry: {
    main: &#39;./src/index.js&#39;,
    admin: &#39;./src/admin.js&#39;
  },
  output: {
    filename: &#39;[name].[contenthash].js&#39;,
    path: path.resolve(__dirname, &#39;dist&#39;),
  },
  optimization: {
    splitChunks: {
      chunks: &#39;all&#39;,
      minSize: 0,
      cacheGroups: {
        common: {
          name: &#39;common&#39;,
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
};</code></pre>
<p>위는 공통모듈 스플리팅을 위한 웹팩 설정 내용이다. 해당 파일을 해석해보면 entry로 설정한 main, admin 파일에서 splitChunks &gt; cacheGroups을 통해 공통으로 임포트된 모듈을 자동으로 추출하여 common.js 파일을 만든다. </p>
<p>예를들어 main과 admin 파일이 아래와 같다고 가정하면.</p>
<pre><code class="language-js">// src/index.js
import { renderPage } from &#39;./common/utils&#39;;
import { fetchUserData } from &#39;./api&#39;;

async function renderUserPage() {
  const userData = await fetchUserData();
  renderPage(&#39;user&#39;, userData);
}

renderUserPage();

// src/admin.js
import { renderPage } from &#39;./common/utils&#39;;
import { fetchAdminData } from &#39;./api&#39;;

async function renderAdminPage() {
  const adminData = await fetchAdminData();
  renderPage(&#39;admin&#39;, adminData);
}

renderAdminPage();</code></pre>
<p>웹팩은 자동으로 renderPage 를 common.js로 분리하여 로드시 불러올 수 있게 해준다. 즉 정리해보자면 </p>
<pre><code>// 기존 방식 (코드 스플리팅 없음)
main.js:
  - index.js 코드
  - renderPage 함수 코드 (중복)
  - fetchUserData 함수 코드

admin.js:
  - admin.js 코드
  - renderPage 함수 코드 (중복)
  - fetchAdminData 함수 코드

// 공통 모듈 스플리팅 적용 후
main.[hash].js:
  - index.js 고유 코드
  - fetchUserData 함수 코드
  - common.[hash].js 참조

admin.[hash].js:
  - admin.js 고유 코드
  - fetchAdminData 함수 코드
  - common.[hash].js 참조

common.[hash].js:
  - renderPage 함수 코드</code></pre><p>이런식으로 분리되는 것이다. 이렇게 분리된 파일들은 다음과 같은 이점을 가지게 된다.</p>
<ol>
<li>중복코드 제거로 파일 다운로드 사이즈가 감소한다.</li>
<li>공통코드의 캐싱을 통해 빠른 로드가 가능하다.</li>
</ol>
<h3 id="packagejson-에서-패키지-관리하기">package.json 에서 패키지 관리하기</h3>
<p>우리가 패키지json 파일을 보면 </p>
<pre><code> &quot;dependencies&quot;: {
    &quot;chart.js&quot;: &quot;^4.3.0&quot;,
    &quot;react&quot;: &quot;^18.2.0&quot;,
    &quot;react-chartjs-2&quot;: &quot;^5.2.0&quot;,
    &quot;react-dom&quot;: &quot;^18.2.0&quot;,
    &quot;react-router-dom&quot;: &quot;^6.11.2&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;@babel/core&quot;: &quot;^7.22.1&quot;,
    &quot;@babel/preset-env&quot;: &quot;^7.22.4&quot;,
    &quot;@babel/preset-react&quot;: &quot;^7.22.3&quot;,
    &quot;babel-loader&quot;: &quot;^9.1.3&quot;,
    &quot;css-loader&quot;: &quot;^7.1.2&quot;,
    &quot;css-minimizer-webpack-plugin&quot;: &quot;^7.0.0&quot;,
    &quot;html-webpack-plugin&quot;: &quot;^5.5.0&quot;,
    &quot;style-loader&quot;: &quot;^4.0.0&quot;,
    &quot;terser-webpack-plugin&quot;: &quot;^5.3.10&quot;,
    &quot;webpack&quot;: &quot;^5.84.1&quot;,
    &quot;webpack-bundle-analyzer&quot;: &quot;^4.9.0&quot;,
    &quot;webpack-cli&quot;: &quot;^5.1.4&quot;,
    &quot;webpack-dev-server&quot;: &quot;^4.15.0&quot;
  },</code></pre><h3 id="정리">정리</h3>
<p>여기까지 코드스플리팅을 할 수 있는 6가지 방법에 대해 공부하고 알아봤다! 내가 생각하기에 6가지 내용에서 공통적으로 강조하는 내용은 </p>
<blockquote>
<p><strong>동적 로딩을 잘 활용할것!!! 그리고 웹팩을 통해 외부 라이브러리를 쪼개고 캐싱하자!!!</strong></p>
</blockquote>
<p>인것 같다. 물론 여러 참조한 문서들에서 공통적으로 했던 말은 무조건적인 코드 스플리팅은 좋지 않다는 얘기들이였다. 요청수 증가로 인한 트래픽상승 등의 문제가 생길 수 있기 때문에 회사의 인프라, 팀의 수준에 따라 진행해야 한다는 말이였다!</p>
<h2 id="마치며">마치며</h2>
<p><img src="https://velog.velcdn.com/images/horang-e/post/28fb87f0-c36a-4087-9776-53cf211c7d2f/image.jpeg" alt=""></p>
<p>코드 스플리팅을 공부하면서 계속 혼잣말로 읊조린 단어가 있다. &quot;와... 이런게있어? 우와..&quot; 계속 중얼중얼 거리면서 공부했던것 같다. 모두 실무수준에서 적용이 가능한 내용인것 같아 꼭프로젝트에 적용시켜 보고 싶다는 생각을 했던 것 같다. 나머지 7가지 내용도 차차 공부해야겠다! 끝!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터 페칭과 랜더링 시점 (feat. 낙관적 업데이트)]]></title>
            <link>https://velog.io/@horang-e/%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%8E%98%EC%B9%AD%EA%B3%BC-%EB%9E%9C%EB%8D%94%EB%A7%81-%EC%8B%9C%EC%A0%90-feat.-%EB%82%99%EA%B4%80%EC%A0%81-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8</link>
            <guid>https://velog.io/@horang-e/%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%8E%98%EC%B9%AD%EA%B3%BC-%EB%9E%9C%EB%8D%94%EB%A7%81-%EC%8B%9C%EC%A0%90-feat.-%EB%82%99%EA%B4%80%EC%A0%81-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8</guid>
            <pubDate>Thu, 22 Aug 2024 13:52:14 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.frontendmentor.io/challenges">https://www.frontendmentor.io/challenges</a> 에 있는 과제를 진행하다가 평소에 실무 개발을 진행하며 항상 궁금했던 부분에 대한 궁금증이 다시금 떠올랐다. 바로 데이터를 불러오고 랜더링 하는 시점에 대한 내용이였다!</p>
<p>예시로
<img src="https://velog.velcdn.com/images/horang-e/post/08835af7-ae73-49c5-be12-eb0acbee912e/image.png" alt="">
이런 컴포넌트가 있다고 할 때 수정, 삭제가 일어난다거나 +,-버튼을 누를 때 업데이트 이후 서버의 데이터를 가져오는 시점이 언제고 어떤식으로 반영해야할까? 라는 종류의 의문이 생겼다.
내가 생각했던 업데이트 시점,방법은 총 3가지였다.</p>
<pre><code>1. 글쓴이가 글을 수정 후 수정하기를 누른 시점에 서버 데이터 pull
    a. response로 수정된 데이터 가져오기
    b. get을 한번 더 요청하기
2. 글쓴이가 글을 수정 후 수정하기를 눌렀을 때는 로컬에서 데이터를 조작해서 눈엔 수정한대로 보이게 하고 이후 페이지 재 진입 혹은 다른 트리거 상황에서 서버 데이터를 pull</code></pre><p>2번의 경우 <strong>낙관적 업데이트</strong>에 해당하는데 여기서 낙관적 업데이트란?</p>
<h3 id="낙관적-업데이트">낙관적 업데이트</h3>
<p>낙관적 업데이트는 서버의 사용자 경험을 향상시키기 위해 등장한 개념이다. 
기존 프론트엔드의 업데이트의 경우는 1번을 따른다.</p>
<blockquote>
<p>사용자 동작 -&gt; 서버응답 -&gt; 들어온 응답으로 UI 업데이트</p>
</blockquote>
<p>하지만 이 경우 서버 응답을 기다릴 때 <strong><em>서버 응답 지연</em></strong> 등으로 인한 사용자의 경험이 저하 될 수 있어 낙관적 업데이트라는 개념이 등장했다. 말 그대로 &quot;<em>사용자가 업데이트 눌렀으니까 무조건 업데이트 됐을거야!</em>&quot;라는 낙관적인 생각을 가지고 UI를 업데이트 하게 된다. 이렇게 되면 사용자는 본인이 업데이트한 내용을 지연 없이 바로 눈으로 확인 할 수 있게 되고, 그로 인해 사용자의 경험성 또한 상승한다.
<em><del>약간 원영적사고..?</del></em></p>
<p>그럼 사용자 경험 향상을 위해서는 늘 르키비키적인 사고로 낙관적 업데이트를 해야하는건가? 하면 그건 아니다! 내가 보고 공부한 블로그에서 주신 예시가 가장 와닿아서 적어본다.</p>
<p>만약 e-commerce 관련 사이트라고 해보자! 사용자가 장바구니에 상품을 담고 결제를 클릭했을때 로딩창이 뜨고 결제가 진행되는것이 보통이다. 그런데 만약 여기서 낙관적 업데이트로 어! 결제 진행 된거야! 그니까 장바구니 비우자! 이렇게 되버리면 중간에 결제 취소등의 상황이 발생했을때 문제가 생길 가능성이 생긴다. </p>
<p>이처럼 서버 데이터와 UI의 일치성이 중요한 경우 르키비키적인 사고는 내려놓고 서버의 응답을 받아 진행해야한다. </p>
<h3 id="그래서-어떤-시점에">그래서 어떤 시점에..?</h3>
<p>사용자가 지연시간 없이 본인이 변경한 내용에 대해 즉각적으로 반영된게 보여야 한다? 그렇다면 르키비키적 사고로 낙관적 업데이트를 진행해보자!! 방법은 대강 말해보면</p>
<ol>
<li>처음 페이지 진입시 데이터를 가져온다. </li>
<li>유저가 업데이트를 진행한다.</li>
<li>서버에는 업데이트 내용을 전송하고 자체적으로 데이터 업데이트를 해서 UI 에 반영한다.
(업데이트 되었을거야 ㅎㅎ ( ͡°ʖ ͡°))</li>
</ol>
<p>물론 서버 업데이트 로직이 정확히 진행 되었을것이라는 자기 믿음이 필요하다 ㅋㅋㅋ 사실 2번이 &quot;낙관적 업데이트&quot; 라는 단어를 사용하는 업데이트 방식이 있다는건 첨 알았다. 이후 개발을 진행하면서 무조건적으로 서버 통신을 통해 ui 업데이트를 진행하지 않아도 된다면 낙관적 업데이트로 개발을 하여 사용자 경험을 개선해야 겠다!!</p>
<p><a href="https://tecoble.techcourse.co.kr/post/2023-08-15-how-to-improve-ux-with-optimistic-update/">참고 블로그</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Batching 그래서 넌 뭔데?]]></title>
            <link>https://velog.io/@horang-e/Batching-%EA%B7%B8%EB%9E%98%EC%84%9C-%EB%84%8C-%EB%AD%94%EB%8D%B0</link>
            <guid>https://velog.io/@horang-e/Batching-%EA%B7%B8%EB%9E%98%EC%84%9C-%EB%84%8C-%EB%AD%94%EB%8D%B0</guid>
            <pubDate>Mon, 08 Jul 2024 11:23:10 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 Batch : 일괄</p>
</blockquote>
<p>React 개발자라면 batching 단어를 한번쯤은 들어봤으리라 생각한다! 나 같은 경우도 직접 겪으면서 아! batching 이라는게 일어나는구나~ 라고 알아본적이 있다. 하지만 이번에 batching 에 대해 깊게 학습해볼 기회가 생겼고 React 공식 깃허브에 있는 batch 에 대해 <a href="https://github.com/reactwg/react-18/discussions/21">설명해둔 글</a>을 해석 + 분석 해보려고 한다!</p>
<h3 id="batching-이란">Batching 이란?</h3>
<blockquote>
<p>Batching은 여러개의 스테이트값들이 단 한번의 리랜더로 업데이트되는 현상을 말한다.</p>
</blockquote>
<p>이렇게만 들으면 잘 이해가 되지 않으니 예시를 한번 살펴보자라</p>
<pre><code class="language-jsx">function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);
  const [count2, setCount2] = useState(0)

  function handleClick() {
    setCount(c =&gt; c + 1); // 랜더 안됨
    setFlag(f =&gt; !f); // 랜더 안됨
    // 리액트는 배칭을 통해 마지막에 한번만 리랜더링 된다!
  }

  function handleClick2() {
  setCount(2); // 랜더 안됨
  setCount(5); // 랜더 안됨
  setCount(1); // 랜더 안됨
  // 리액트는 배칭을 통해 마지막에 한번만 리랜더링 된다!
  }

  console.log(count) // 0 -&gt; 1 

  return (
    &lt;div&gt;
      &lt;button onClick={handleClick}&gt;Next&lt;/button&gt;
      &lt;button onClick={handleClick2}&gt;Now&lt;/button&gt;
      &lt;h1 style={{ color: flag ? &quot;blue&quot; : &quot;black&quot; }}&gt;{count}&lt;/h1&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>즉, state인 count와 flag의 값을 변경함에 따라 2번의 리랜더링이 일어나는 것이 아닌 handleClick이 끝나는 시점에 리랜더링이 일어나는 것을 뜻한다.
배칭의 장점은 불필요한 리랜더링은 줄임으로써 퍼포먼스를 올릴 수 있게 된다. 또한 배칭은 아직 끝나지 않은 작업에 대한 업데이트를 막음으로써 효율을 높일 수 있게된다. 공식 문서에서 재밌는 예시를 들어놨다.<span style="color:grey">_ 우리가 레스토랑 알바를 할 때 손님이 음식을 주문하면 첫번째 음식을 주문하자마자 주방으로 달려가 주문을 넣는것이 아닌 손님이 주문하는 모든 음식을 듣고 차후에 주방으로 가서 주문을 넣는 것 또한 효율 때문이 아니겠는가 하는 것이다._</span> </p>
<p>React18 이전의 batch는 오직 브라우저 이벤트가 발생할 때만 자동적으로 batching 을 실행해 주었지만 18이후부터는 브라우저 이벤트 뿐만 아니라 promises, setTimeout, native event handlers 등의 다른 이벤트에서도 자동적으로 batching을 처리해준다! </p>
<pre><code class="language-jsx">function handleClick() {
  setCount(c =&gt; c + 1);
  setFlag(f =&gt; !f);
  // 이때만 리랜더링
}

setTimeout(() =&gt; {
  setCount(c =&gt; c + 1);
  setFlag(f =&gt; !f);
  // 이때만 리랜더링
}, 1000);

fetch(/*...*/).then(() =&gt; {
  setCount(c =&gt; c + 1);
  setFlag(f =&gt; !f);
  // 이때만 리랜더링
})

elm.addEventListener(&#39;click&#39;, () =&gt; {
  setCount(c =&gt; c + 1);
  setFlag(f =&gt; !f);
  // 이때만 리랜더링
});</code></pre>
<h3 id="난-싹-다-업데이트-하고-싶은데">난 싹 다 업데이트 하고 싶은데..?</h3>
<p>batching을 하는것이 사실 이론상은 안전하지만 난 따로따로 업데이트 하고싶은데? 한다면? <code>ReactDOM.flushSync()</code> 를 사용하면 batching 처리를 하지 않고 state 변경이 될 때마다 업데이트를 할 수 있게 해준다.</p>
<pre><code class="language-jsx">import { flushSync } from &#39;react-dom&#39;; 

function handleClick() {
  flushSync(() =&gt; {
    setCounter(c =&gt; c + 1);
  });
  // 업데이트 됨
  flushSync(() =&gt; {
    setFlag(f =&gt; !f);
  });
  // 업데이트 됨
}</code></pre>
<h3 id="🤔-흠-그럼-도대체-어떤식으로-동작하는거지">🤔 흠... 그럼 도대체 어떤식으로 동작하는거지?</h3>
<p>한번 생각을 해보자! 어떻게 진행이 되는걸까?</p>
<blockquote>
<ol>
<li>하나의 이벤트 내에서 여러번의 setState가 발생했을때 이것들을 한번에 처리하는 것을 Batching이라고 한다.</li>
<li>이것을 구현하기 위해서는 어떻게 해야할까?</li>
<li>setState 가 여러번 발생 했을때 해당 이벤트를 어디에 모아 뒀다가 가장 마지막에 들어오는 애만 1frame 후에 실행되게 해야한다. 그럼 이건 후입선출 이니까 stack을 사용한다. stack에 넣어두고 1frame 후에 stack에서 pop을 해서 실행하면 된다.</li>
<li>근데 그러면 이 과정들이 1frame 안에 일어났으며 한개의 스테이트값에 대한 변경만 발생했음을 알아야한다.</li>
<li>그러면 해당 스테이트값에 대한 인덱스를 키로 가지면서 밸류값으로 스택을 가지고 있어야하지..? 그리고 처음 딱 이벤트가 발생하는 시점에 setTimeout을 걸어두고 1frame 후에 실행되게 해야한다.</li>
</ol>
</blockquote>
<p>이런 의식의 흐름에 이르렀다. 여기서 1frame 은 react에서 처리하는 타이밍을 인위적으로 표시하기 위해 설정한 조건이다. 실제 리액트는 훨씬 더 복잡하게 처리하겠지..? </p>
<h3 id="공부하면서">공부하면서..</h3>
<p>공부를 하면서 느낀점은 이런식의 동작이 자동으로 돌아가는 React에 대한 경외감과 재밌다!!! 는 생각이였다. 물론 왠만하면 자동적으로 batching 이 되기 때문에 의식하면서 사용하지 않아도 되겠지만 사용하면서 음~ 배칭됐겠네! 하는 일말의 생각을 하면서 사용할 수 있을것같다. 재밌따!  </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[객체 World]]></title>
            <link>https://velog.io/@horang-e/%EA%B0%9D%EC%B2%B4-World</link>
            <guid>https://velog.io/@horang-e/%EA%B0%9D%EC%B2%B4-World</guid>
            <pubDate>Fri, 28 Jun 2024 12:40:13 GMT</pubDate>
            <description><![CDATA[<p>객체 지향 언어인 JavaScript를 2년째 쓰면서 정작 객체의 종류나 특성에 대해서는 알고 있지 못하다는 생각이 들어 포스트를 적게 되었다.</p>
<blockquote>
<p>객체란 Key, value 를 짝으로 가지고 있는 구조로 여러개의 속성을 하나의 변수에 저장 할 수 있다. </p>
</blockquote>
<p>_이번에 항플 프론트엔드 2주차 과제를 진행하면서 알게 된 점을 적어보자.
_</p>
<h3 id="원시-래퍼-객체">원시 래퍼 객체</h3>
<pre><code class="language-js">const a = &#39;1&#39;
const b = new String(1)
const c = 1
const d = new Number(1)
const e = true
const f = new Boolean(true)

console.log(a===b) //false
console.log(a==b) //true
console.log(c===d) //false
console.log(e===f) //false</code></pre>
<p>여기서 a와 b, c와 d, e와 f 가 다른 이유는 뭘까? 이유는 new String,new Number,new Boolean 으로 만든 값은 <strong>원시값</strong>인 &#39;1&#39;, 1 , true와는 다른 <strong>객체</strong>이기 때문이다. 찾아본 바에 따르면 원시 타입 값과 래퍼 객체는 서로 다르게 동작 할 수 있으므로 직접 래퍼 객체를 생성하는것은 권장되지 않는다고 합니다.</p>
<h3 id="nodelist">NodeList</h3>
<pre><code class="language-js">document.body.innerHTML = `&lt;div id=&quot;test&quot;&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/div&gt;`;
const spans = document.querySelectorAll(&#39;#test span&#39;);
console.log(spans); //NodeList(2) [span, span]</code></pre>
<p>NodeList는 DOM API로 생성된 객체로 배열과 유사하지만 Array.isArray 에서는 false로 도출된다. 그렇기 때문에 만약 array 조건에서 걸릴것이라고 생각하면 안된다. NodeList 의 경우에는 <code>target instanceof NodeList</code>  조건을 사용해서 걸러줘야한다.! (array처럼 array의 동작을 하기는 한다)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[컴포넌트 생성시 고려해야할 점]]></title>
            <link>https://velog.io/@horang-e/%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%83%9D%EC%84%B1%EC%8B%9C-%EA%B3%A0%EB%A0%A4%ED%95%B4%EC%95%BC%ED%95%A0-%EC%A0%90</link>
            <guid>https://velog.io/@horang-e/%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%83%9D%EC%84%B1%EC%8B%9C-%EA%B3%A0%EB%A0%A4%ED%95%B4%EC%95%BC%ED%95%A0-%EC%A0%90</guid>
            <pubDate>Mon, 24 Jun 2024 03:49:06 GMT</pubDate>
            <description><![CDATA[<p>새로운 프로젝트를 시작하거나 뭔가 새로운 단위의 컴포넌트를 개발할 때 가장 헷갈리고 고민했던 부분이 컴포넌트 분리에 대한 내용이였다. 이번에 멘토링을 진행하며 팀원분이 여쭤봤던 질문이 기억에 남아 정리하고 공유해보려한다.</p>
<h3 id="큰-단위의-컴포넌트-분류">큰 단위의 컴포넌트 분류</h3>
<p>코드를 짜다보면 한 페이지 내에서의 사이즈가 점점 커지고 도대체 어떤 부분에서 컴포넌트 분리를 해야하지? 라는 생각이 드는 시점이 항상 있다. 가장 기본적으로 해당 페이지에서 컴포넌트 분리가 필요하다! 라는 생각이 든 순간 확인해봐야 하는 부분은 다음과 같다.</p>
<pre><code class="language-js">const [aaa] = useState()
const [bbb] = useState()
const [ccc] = useState()
const [ddd] = useState()

const [aaa] = useMemo()
const [bbb] = useMemo()
const [ccc] = useMemo()
const [ddd] = useMemo()

const handlerA = () =&gt; 
const handlerB = () =&gt; 
const handlerC = () =&gt; 
const handlerD = () =&gt; 
const handlerE = () =&gt; </code></pre>
<p>위의 코드를</p>
<pre><code class="language-jsx">const [aaa] = useState()
const [aaa] = useMemo()
const handlerA = () =&gt; 

const [bbb] = useState()
const [bbb] = useMemo()
const handlerB = () =&gt; 

const [ccc] = useState()
const [ccc] = useMemo()
const handlerC = () =&gt; 

const [ddd] = useState()
const [ddd] = useMemo()
const handlerD = () =&gt; 

const handlerE = () =&gt; 
</code></pre>
<p>이처럼 분류가 가능하다면 일단 컴포넌트 분리의 가능성이 있다고 생각하고 상하 관계를 따져가며, 의존관계를 따져가며 분리가 가능한지 고민해 볼 수 있다. 나같은 경우에는 보통 첫번째 코드처럼 함수는 함수대로 변수는 변수대로 응집시켜두며 코딩을 하는데 컴포넌트별로 결합해서 나타내 두는게 나중에 컴포넌트를 분리할 때는 훨씬 편할 것 같다는 생각을 했다.</p>
<h3 id="컴포넌트의-성격에-따른-종류">컴포넌트의 성격에 따른 종류</h3>
<ol>
<li>UI 컴포넌트</li>
<li>UI + Domain</li>
<li>Domain</li>
<li>Layout</li>
<li>Section or Group</li>
</ol>
<blockquote>
<p>여기서 Domain 이란 서버에서 들어오는 데이터 형식 및 데이터를 뜻한다.</p>
</blockquote>
<p>이 중 메인으로 다뤄볼 컴포넌트는 UI 컴포넌트와 UI + Domain 컴포넌트이다.</p>
<h3 id="ui-컴포넌트">UI 컴포넌트</h3>
<p>UI 컴포넌트는 우리가 흔히 아는 <em>MUI, ANTD</em> 등의 디자인이 입혀진 컴포넌트를 뜻한다. UI 컴포넌트는 우리가 직접 만들지 않아도 앞에서 언급했던 css 프레임 워크를 가지고도 편히 사용할 수 있다. 하지만 우리는 ui 만 보여주는 것이 아닌 도메인 또한 연결해서 사용해야 한다. 보통 ui 컴포넌트만 따로분리하는 경우는 예시를 보면 쉽게 파악이 가능하다.
<img src="https://velog.velcdn.com/images/horang-e/post/7ba5027d-322f-4d5f-865e-8fbfefb625b5/image.png" alt="">
<img src="https://velog.velcdn.com/images/horang-e/post/fa312911-2bfe-414c-9824-f83309760959/image.png" alt=""></p>
<p>위의 두 사진은 각각 당근마켓의 인기당근 알바와 인기 중고차 아이템의 UI다. 내가 처음에 딱 봤을때 두 UI가 비슷하기 때문에 &quot;ItemCard라는 컴포넌트를 만들어 props로 알바 아이템인지,중고차 아이템인지 체크하는 부분을 넣어 구분하면 되겠다!&quot; 라고 생각했었다. 이 생각이 UI중심의 컴포넌트를 생성하게 되는 것이다.</p>
<pre><code class="language-tsx">interface IItemBoxProps {
  isCar : Boolean;
  ...
}

const ItemBox = (props : IItemBoxProps) =&gt; {
...
return (
...
  {isCar? 
   &lt;div&gt;{props.item.price}만원&lt;/div&gt;:
   &lt;div&gt;일급{props.item.price}&lt;/div&gt;}
)
}</code></pre>
<p>만약 앞으로 이 UI 가 변할일 없고 계속 이 형태를 유지한다고 하면 내가 만든 코드처럼 진행해도 자잘자잘한 부분만 변화하면서 사용하면 될 것 같지만 UI는 계속 뭔가 추가되고 삭제되고 하는 부분들이 분명히 있다. 해서 눈에보이는 UI 위주가 아닌 Domain 단위의 컴포넌트를 짜야한다.</p>
<h3 id="ui--domain-컴포넌트">UI + Domain 컴포넌트</h3>
<p>만약 위의 예시인 당근마켓의 개발자라고 상상해보자(으히히) 디자인쪽에서 &quot;이번에 당근마켓 알바 UI를 이렇게 변경해주세요!&quot;
<img src="https://velog.velcdn.com/images/horang-e/post/df377489-4885-41b5-8359-addaa532baab/image.png" alt="">
라고 요청이 들어왔다고 상상해보면 만약 위의 예시처럼 UI 위주의 컴포넌트를 짰을 때는 머리가 아주 아파질 것이다. 그도 그럴것이 중고차와 알바를 같은 UI로 묶었기 때문에 중고차는 원래 UI 그대로, 알바 UI는 변경 이렇게 처리를 해야하기 때문일 것이다. 하지만 만약 AlbaItemCard , CarItemCard 이렇게 따로 처리를 했다고 한다면? CarItemCard 는 그대로 두고 AlbaItemCard만 UI 를 변경하게 되면 되는것이다! 여기서 생각해 봐야 할 점은 <strong>컴포넌트 분리는 코드의 유지,보수를 쉽게하기 위함!</strong> 이라는 점이다. 그런 의미에서 UI 위주의 컴포넌트 분리 보다는 Domain 위주의 컴포넌트 분리가 부합하다고 본다..!</p>
<p>아주 흥미롭고 재밌어 ㅎ흫ㅎ</p>
<blockquote>
<p>이 내용은 항해 플러스 프론트엔드 2기를 진행하며 테오 코치님에게 여쭤보고 답변받은 내용을 정리한 글 입니다 :)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[PureComponent VS React.memo]]></title>
            <link>https://velog.io/@horang-e/PureComponent-VS-React.memo</link>
            <guid>https://velog.io/@horang-e/PureComponent-VS-React.memo</guid>
            <pubDate>Tue, 18 Jun 2024 13:47:08 GMT</pubDate>
            <description><![CDATA[<p><a href="https://ko.react.dev/reference/react/PureComponent#purecomponent">공식문서</a></p>
<blockquote>
<p>💡 PureComponent란?
클래스 컴포넌트에서 사용되는 Component로 해당 컴포넌트로 넘어오는 props 혹은 내부의 state를 이전값과 비교하여 변경시 리랜더링 되게 해주는 컴포넌트.</p>
</blockquote>
<blockquote>
<p>💡 React.memo란?
고차컴포넌트(HOC)로 props 값을 memoizing하고 있다가 값이 변경되면 해당 HOC를 리랜더링 되게해주는 함수.</p>
</blockquote>
<p>언뜻보면 비슷해 보이는 PureComponent 와 React.memo는 다음과 같은 차이가 있다.</p>
<h3 id="클래스형-컴포넌트-vs-함수형-컴포넌트">클래스형 컴포넌트 vs 함수형 컴포넌트</h3>
<p>PureComponent는 클래스형 컴포넌트에서 사용되며 사용 시 사용하려는 컴포넌트를 extend시켜 사용한다.</p>
<pre><code class="language-jsx">import {PureComponent} from &#39;React&#39;

Class ExampleComponent extends PureComponent {
...
}</code></pre>
<p>React.memo는 일반적으로 함수형 컴포넌트를 위한 HOC로 원하는 함수형 컴포넌트를 감싸서 사용한다.</p>
<pre><code class="language-jsx">const ExampleComponent=memo(({ crying }: TCryingProps) =&gt; {
  return &lt;p data-testid=&#39;dog&#39;&gt;강아지 &quot;{crying}&quot;&lt;/p&gt;;
});</code></pre>
<h3 id="props-비교-state-비교">props 비교, state 비교</h3>
<p>PureComponent는 props, state를 모두 비교하여 하나라도 변경되면 리랜더링 된다. React.memo는 props 만 비교하여 이전과 다르면 리랜더링 된다.</p>
<h3 id="purecomponent는-reactmemo를-사용해서-class-component에서-함수형-컴포넌트로-변환이-가능하다">PureComponent는 React.memo를 사용해서 class component에서 함수형 컴포넌트로 변환이 가능하다.</h3>
<p>공식문서의 예시를 참조해보자.</p>
<pre><code class="language-jsx">import { PureComponent, useState } from &#39;react&#39;;

class Greeting extends PureComponent {
  render() {
    console.log(&quot;Greeting was rendered at&quot;, new Date().toLocaleTimeString());
    return &lt;h3&gt;Hello{this.props.name &amp;&amp; &#39;, &#39;}{this.props.name}!&lt;/h3&gt;;
  }
}</code></pre>
<pre><code class="language-jsx">const Greeting = memo(function Greeting({ name }) {
  console.log(&quot;Greeting was rendered at&quot;, new Date().toLocaleTimeString());
  return &lt;h3&gt;Hello{name &amp;&amp; &#39;, &#39;}{name}!&lt;/h3&gt;;
});</code></pre>
<p>위의 예시처럼 하면 변환을 할 수 있다.</p>
<p>실제 실무나 코드 짤 때 기억하고 있다가 불필요한 리랜더링이 일어날때 적용해봐야겠다.!.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React.useRef()]]></title>
            <link>https://velog.io/@horang-e/React.useRef</link>
            <guid>https://velog.io/@horang-e/React.useRef</guid>
            <pubDate>Tue, 18 Jun 2024 11:17:25 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 useRef는 렌더링에 필요하지 않은 값을 참조할 수 있는 React Hook입니다.(공식문서)</p>
</blockquote>
<p>무지성 사용하던 Hook을 파악해보자;ㅅ;</p>
<h2 id="useref-사용">useRef 사용</h2>
<h3 id="📍값-참조">📍값 참조</h3>
<p>useRef는 처음에 준 초기값을 current 프로퍼티로 ref객체를 반환한다. 한마디로 정보를 저장하고 읽을수 있게 해준다. 이렇게만 말하면 useState와 차이가 없게 느껴지겠지만 state 값이 변경되면 리랜더링을 촉발하여 변경된 값을 시각적으로 출력시켜준다. 하지만 useRef의 ref 값은 값이 변경되더라도 리랜더링을 촉발시키지 않아 리랜더로 변하지 않아야하는 값을 사용하기에 적절하다. </p>
<h3 id="📍dom-조작">📍DOM 조작</h3>
<p>useRef는 DOM의 노드를 조작할 수 있게 한다.</p>
<pre><code class="language-jsx">&lt;input ref={inputRef}/&gt;</code></pre>
<p>위의 예시처럼 사용하게 되면 input의 node를 관리할 수 있게 된다. 여기서 노드 관리는 예시를 예로 들면 input의 속성 (focus, value...) 등을 관리, 사용할 수 있게 되는것을 말한다.</p>
<pre><code class="language-jsx">import { forwardRef, useRef } from &#39;react&#39;;

const MyInput = forwardRef((props, ref) =&gt; {
  return &lt;input {...props} ref={ref} /&gt;;
});

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    &lt;&gt;
      &lt;MyInput ref={inputRef} /&gt;
      &lt;button onClick={handleClick}&gt;
        Focus the input
      &lt;/button&gt;
    &lt;/&gt;
  );
}
</code></pre>
<h2 id="직접-useref-만들어-보기">직접 useRef() 만들어 보기</h2>
<p>useRef의 역할을 알았으니 useRef의 역할을 할 수 있는 커스텀 훅을 만들어보자!</p>
<p>그럼 음 일단 내가 만들 useMyRef는 해야할 역할이</p>
<ol>
<li>값을 할당 할 수 있어야함</li>
<li>값이 변해도 리랜더링이 되면 안됨</li>
<li>dom을 조작할 수 있어야함</li>
<li>원하는 대로 값 변경은 할 수 있어야함</li>
</ol>
<pre><code class="language-jsx">import { useState } from &#39;react&#39;;

export function useMyRef&lt;T&gt;(initValue: T | null) {
  // ref를 저장할 state를 생성. { current: initValue}객체를 통해 current값이 변경되더라도 리랜더링 되지 않게 함
  const [ref, setRef] = useState&lt;{ current: T | null }&gt;(() =&gt; ({ current: initValue }));

  // setRef를 통해 ref의 값을 변경.
  const setRefValue = (value: T | null) =&gt; {
    setRef({ current: value });
  };

  return [ref, setRefValue];
}</code></pre>
<p>위의 코드를 보면 위에서 만족해야 하는 역할중 값의 할당은 useState를 통해서 처음 initialValue를 설정해주고 state값을 객체로 설정하여 current의 값이 바뀌더라도 리랜더링이 일어나지 않게 설정하였으며 useRef 와 마찬가지로 dom제어 또한 가능하다. 추가로 setRef를 통해 ref값의 변경 또한 가능하게 해 두었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript 간단 정리]]></title>
            <link>https://velog.io/@horang-e/TypeScript-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@horang-e/TypeScript-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 01 Jun 2024 08:56:13 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>해당 글은 스파르타 코딩클럽의 TypeScript 문법 종합반 강의를 바탕으로 작성되었습니다.</p>
</blockquote>
<h3 id="동적-타입-언어-vs-정적-타입-언어">동적 타입 언어 VS 정적 타입 언어</h3>
<ul>
<li>동적 타입 언어 → JavaScript<ul>
<li>동적 타입 언어는 프로그램 실행 시 변수 타입을 결정한다.<ul>
<li>즉, 오류가 있더라도 실행을 해봐야만 오류 확인이 가능하다 → 문제 야기 가능성이 큼</li>
</ul>
</li>
<li>객체의 성질을 수시로 변경할 수 있다.<ul>
<li>ex) <code>let a = &#39;사람&#39; ; a = 4</code> string → number</li>
</ul>
</li>
<li>=인터프리터 언어 → 엔진(V8, SpiderMonkey)이 코드를 한줄 씩 실행 하면서 동적으로 해석</li>
</ul>
</li>
<li>정적 타입 언어 → TypeScript<ul>
<li>정적 타입 언어는 컴파일 시에 변수 타입을 체크하고 오류를 발견한다. (VScode의 경우 입력과 동시에 오류 체크)<ul>
<li>즉, 실행 전 오류를 체크해준다.</li>
</ul>
</li>
<li>=컴파일 언어 → 기계어로 변환이 필요 (ex) tsc)</li>
</ul>
</li>
</ul>
<h3 id="tsccompiler">TSC(Compiler)</h3>
<ul>
<li>tsconfig.json<ol>
<li>target : 컴파일 옵션을 설정<ol>
<li>javascript 버전 변환 설정</li>
</ol>
</li>
<li>module : js 모듈 형식 지정</li>
<li>outDir : js 저장 dir 설정</li>
<li>sourceMap : 에러 위치 찾기 용이</li>
</ol>
</li>
</ul>
<h3 id="readonly">ReadOnly</h3>
<ul>
<li><p>객체의 속성을 불변으로 지정</p>
<ul>
<li><p>const랑 다른점? readonly 는 class 속성에서 지정할때 사용가능 const 는 class 속성에 없어</p>
<pre><code class="language-jsx">class Person { 
readonly name: string;
readonly age: number;

constructor(name: string, age: number) {
  this.name = name;
  this.age = age;
}
}

const person = new Person(&#39;Spartan&#39;, 30);

console.log(person.name);  // 출력: &#39;Spartan&#39;
console.log(person.age);   // 출력: 30

person.name = &#39;Jane&#39;;  // 에러: &#39;name&#39;은 readonly 속성이므로 다시 할당할 수 없어요!
person.age = 25;       // 에러: &#39;age&#39;은 readonly 속성이므로 다시 할당할 수 없어요!</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="any-unknown-union">any, unknown, union</h3>
<aside>
💡 어쩔 수 없이 가변적인 타입의 데이터를 저장하고 싶다면 any를 쓰기보다는 unknown을 사용! 그리고,가변적인 타입을 일일이 정의할 수 있다면 union 사용!

</aside>

<ul>
<li>any 는 타입을 쓰는 이유가 사라지는 큰 원인… 왠만하면 사용하지 맛!</li>
<li>unknown<ul>
<li>타입 단언(Type Assertion)을 통해 타입 보장하여 사용가능<ul>
<li>ex)<code>as string</code></li>
</ul>
</li>
</ul>
</li>
<li>union<ul>
<li>여러 타입중 한가지를 가질 수 있을 때 사용<ul>
<li><code>type StringOrNumber = string | number;</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="유틸리티-타입">유틸리티 타입</h3>
<ul>
<li><p>Partial<T></p>
<ul>
<li><p>Person interface 안에있는 속성값 중 일부만 가져올 때 사용</p>
<pre><code class="language-jsx">interface Person {
name: string;
age: number;
}

const updatePerson = (person: Person, fields: Partial&lt;Person&gt;): Person =&gt; {
return { ...person, ...fields };
};

const person: Person = { name: &quot;Spartan&quot;, age: 30 };
const changedPerson = updatePerson(person, { age: 31 });</code></pre>
</li>
</ul>
</li>
<li><p>Required<T></p>
<ul>
<li><p>필수로 있어야함.</p>
<pre><code class="language-jsx">interface Person {
name: string;
age: number;
address?: string; 
}
type RequiredPerson = Required&lt;Person&gt;; // address 또한 필수로 있어야함.</code></pre>
</li>
</ul>
</li>
<li><p>ReadOnly<T></p>
<ul>
<li>읽기온리 = 완전한 불변 객체 취급</li>
</ul>
</li>
<li><p>Pick&lt;T,K&gt;</p>
<ul>
<li><p>Person interface 에서 name, age속성만 선택해서 새로운 타입 생성</p>
<pre><code class="language-jsx">  interface Person {
    name: string;
    age: number;
    address: string;
  }

  type SubsetPerson = Pick&lt;Person, &quot;name&quot; | &quot;age&quot;&gt;;

  const person: SubsetPerson = { name: &quot;Spartan&quot;, age: 30 };</code></pre>
</li>
</ul>
</li>
<li><p>Omit&lt;T,K&gt;</p>
<ul>
<li><p>타입 T에서 K 속성들만 제외한 새로운 타입 생성</p>
<pre><code class="language-jsx">  interface Person {
    name: string;
    age: number;
    address: string;
  }

  type SubsetPerson = Omit&lt;Person, &quot;address&quot;&gt;;

  const person: SubsetPerson = { name: &quot;Alice&quot;, age: 30 };</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="객체-지향형-프로그래밍">객체 지향형 프로그래밍</h3>
<ul>
<li>클래스 , 객체 ⇒ 붕어빵틀 , 붕어빵</li>
</ul>
<pre><code class="language-jsx">class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) { //생성자, 온리원,초기화
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log(`안녕하세요! 제 이름은 ${this.name}이고, 나이는 ${this.age}살입니다.`);
  }
}

const person = new Person(&#39;Spartan&#39;, 30);
person.sayHello();</code></pre>
<ul>
<li>접근제한자<ul>
<li><code>public</code></li>
<li><code>private</code><ul>
<li>클래스 내부에서만</li>
</ul>
</li>
<li><code>protected</code></li>
</ul>
</li>
</ul>
<h3 id="객체-지향-설계-원칙solid">객체 지향 설계 원칙(SOLID)</h3>
<ul>
<li>SRP(단일 책임 원칙) ⭐<ul>
<li>클래스는 하나의 책임만 가져야 한다.</li>
<li>ex) 유저 클래스를 정의 했다고 하면 해당 서비스 하위에는 유저와 관련된 액션만 해야한다.</li>
</ul>
</li>
<li>OCP(개방 폐쇄 원칙)<ul>
<li>확장엔 열려있고 수정엔 닫혀있고</li>
<li>기존 코드 변경안하고 해당 코드 가져다가 확장해서 쓰라~</li>
</ul>
</li>
<li>LSP(리스코프 치환원칙)<ul>
<li>서브타입은 기반이되는 슈퍼타입을 대체할 수 있다.</li>
<li>즉, 부모 클래스는 모든 자식클래스를 아우르는 클래스로 구성이 되어야 한다~</li>
</ul>
</li>
<li>ISP(인터페이스 분리 원칙)<ul>
<li>너무 넓은 범위의 인터페이스는 지양하자</li>
<li>다른 인터페이스에 영향이 갈 수있으므로</li>
</ul>
</li>
<li>DIP(의존성 역전 원칙)<ul>
<li>상위 인터페이스에 의존해야한다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Arr.map 과 key🔑 ]]></title>
            <link>https://velog.io/@horang-e/Arr.map-%EA%B3%BC-key</link>
            <guid>https://velog.io/@horang-e/Arr.map-%EA%B3%BC-key</guid>
            <pubDate>Mon, 27 May 2024 03:23:01 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/horang-e/post/b2d0ebe3-5419-4003-bc72-aa20d6018aaf/image.png" alt=""></p>
<pre><code>Warning : Each Child in a list should have a unique &quot;key&quot; prop.</code></pre><p>프론트엔드 개발자라면 누구나 한번씩은 보는 콘솔의 빨간 에러... 처음에는 콘솔에 빨간 글씨만 보여도 수정할려고 애를 쓰던 내가 어느순간 없어도 <code>돌아 간다</code> 라는 오만하고 도라이 같은 생각에 안주되어 해당 에러를 무시한지 오래되었다. 그런데 며칠전... 오랫만의 기술면접에</p>
<blockquote>
<p> key값을 index로 주셨는데 왜 index 값으로 주셨는지 DOM의 개념과 함께 설명해 주실 수 있을까요?</p>
</blockquote>
<p>라는 질문에 머리가 띵해져서 대답을 절고 난 후에 서칭을 해보기 시작했다.</p>
<p><a href="https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key">공식문서</a></p>
<h4 id="리액트-공식문서-설명">리액트 공식문서 설명</h4>
<p><em>키는 각 배열 항목이 어떤 컴포넌트에 해당하는지를 React에게 알려줍니다. 이렇게 하면 React가 나중에 이를 맞춰볼 수 있습니다. 이는 배열 항목이 이동하거나(예: 정렬 때문에), 삽입되거나, 삭제될 수 있는 경우 중요해집니다. 잘 선택된 키는 React가 정확히 무슨 일이 일어났는지를 추론하고, DOM 트리에 올바른 업데이트를 할 수 있도록 도와줍니다.</em></p>
<p>해당 설명을 쉽게 풀어보면 key의 역할은 <strong>배열의 정렬, 삽입, 삭제, 업데이트</strong>등의 일을 수행할 때 React가 이러한 변경 사항을 정확하게 추론할 수 있게 하여, 효율적이고 올바르게 DOM 업데이트를 할 수 있게 해준다고 나와있는것을 확인 할 수 있다. </p>
<p>하지만 이 때 map 메쏘드자체에 있는 index 값을 키로 지정하는것이 옳은가? 하면 그건 또 리액트에서 key 값을 사용하는 이유에 반하는 일이 된다.
이유는 간단하다. <strong>React가 변경 사항을 정확하게 추론하지 못하기 때문이다!</strong> </p>
<p>만약 삽입, 삭제등의 동작이 발생했다고 생각해보자. map함수 자체의 index를 넣은 경우 arr의 길이가 변경되면 데이터의 index 값 또한 변화하게 되고 모든 item 들은 새로운 index 값을 부여받게 될 것이다. 그렇게 되면 arr 내의 모든 값들이 새로운 key값을 부여받아 모두 새로운 항목으로 보일것이고 그럼 모든 값들이 새로 랜더링이 되게 된다. 하지만 만약 항목 고유의 값을 부여하게 된다면 삽입, 삭제등의 동작이 발생하더라도 기존의(변경되지 않은) 데이터는 새로 랜더링 되지 않는다. </p>
<p>정리해보자면</p>
<blockquote>
<p>key값은 해당 아이템을 나타내는 고유값이며 배열의 변경(삽입, 삭제 등) 시 어떤 값이 변경되었는지 React가 추론할 수 있는 키이다. 그러므로! map 함수의 index를 key값으로 사용 하는 것은 바람직하지 않다.!</p>
</blockquote>
<p>이제 알았으니까 면접 다시보게해주세요... 완벽하게 대답할 수 있어요ㅠㅠㅠㅠㅠㅠㅠㅠㅠ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[충격과 공포의 NextJS와 UseState ]]></title>
            <link>https://velog.io/@horang-e/%EC%B6%A9%EA%B2%A9%EA%B3%BC-%EA%B3%B5%ED%8F%AC%EC%9D%98-NextJS%EC%99%80-UseState</link>
            <guid>https://velog.io/@horang-e/%EC%B6%A9%EA%B2%A9%EA%B3%BC-%EA%B3%B5%ED%8F%AC%EC%9D%98-NextJS%EC%99%80-UseState</guid>
            <pubDate>Tue, 02 Apr 2024 08:40:13 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/horang-e/post/d65c700a-07b3-4665-87d0-965fd91300e0/image.png" alt=""></p>
<p>이 글의 발단은 이전에 써놨던 노션을 정리하던 도중 왜 저렇게 제목을 지은지 모르겠는 글에서 시작되었다.</p>
<p><img src="https://velog.velcdn.com/images/horang-e/post/636b744c-4a14-4ee8-98ac-7013aa2c7246/image.png" alt=""></p>
<p>내가 저렇게 충격받은 이유가 뭔가 하니... NextJs 개발 초기에 이것저것 찾아보던 도중 nextjs 를 검색하면 가장 많이 나오는 SSR 즉, 서버사이드 랜더링에 대해 공부하고 적용해보다가 <strong>react의 훅을 사용하려면 컴포넌트에 무조건 &#39;use client&#39;를 사용해야한다.</strong> 는 점에 의문이 생겼다.</p>
<blockquote>
<p>&quot;...? 엥? 서버사이드 랜더링의 장점이 데이터를 미리 html위에 뿌려주고 있기 때문에 검색엔진에 노출되기 쉽다그랬는데.. use client 를 사용하면 SSR의 장점이 없어지잖아..?? &quot;</p>
</blockquote>
<p>에서 뻗어 나갔고 이것저것 검색을 해 보던중 충격적인 사실을 알게되었다. 여태껏 데이터를 받아오면 해당 데이터를 useState로 받아서 화면에 뿌려주기만 했었던 나에겐 신선한 충격이 아닐수 없었던 것이다.</p>
<pre><code class="language-js">import axios from &#39;axios&#39;;
import Head from &#39;next/head&#39;;
import { useRouter } from &#39;next/router&#39;
import { useEffect, useState } from &#39;react&#39;;
import { Loader } from &#39;semantic-ui-react&#39;;
import Item from &#39;../../src/component/Item&#39;;

const Post = ({item}) =&gt; {


    return (
        &lt;&gt;
            &lt;Head&gt;
                &lt;title&gt;{item.name}&lt;/title&gt;
                &lt;meta name=&quot;description&quot; content={item.description}&gt;&lt;/meta&gt;
            &lt;/Head&gt;
            {item &amp;&amp; &lt;Item item={item} /&gt;}
        &lt;/&gt;
    );
};

export default Post;

export async function getServerSideProps(context){
    const id=context.params.id;
    const apiUrl=`http://makeup-api.herokuapp.com/api/v1/products/${id}.json`;
    const res=await axios.get(apiUrl);
    const data=res.data;

    return{
        props:{
            item:data,
        },        
    };
}</code></pre>
<p>위 예시를 보면..! useState로 데이터를 받아 state값을 뿌려주는 것이 아닌 서버에서 내려온 데이터를 props로 그대로 뿌려주는것을 볼 수 있었다..!! 저렇게 서버데이터를 받아와야지만 서버사이드에서 랜더링 시에 검색 노출이 높아지는 거시다...!...! 0ㅇ0!!!!(나만 충격일수도..ㅜ.ㅜ) </p>
<p>나자식 어디가서 SEO 최적화를 높이기 위해서 NextJS 써봤다고 하지말어라!</p>
<p><a href="https://sw-ryu.tistory.com/70">참고자료</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Array.with 로 배열복사와 변경을 한번에!]]></title>
            <link>https://velog.io/@horang-e/Array.with-%EB%A1%9C-%EB%B0%B0%EC%97%B4%EB%B3%B5%EC%82%AC%EC%99%80-%EB%B3%80%EA%B2%BD%EC%9D%84-%ED%95%9C%EB%B2%88%EC%97%90</link>
            <guid>https://velog.io/@horang-e/Array.with-%EB%A1%9C-%EB%B0%B0%EC%97%B4%EB%B3%B5%EC%82%AC%EC%99%80-%EB%B3%80%EA%B2%BD%EC%9D%84-%ED%95%9C%EB%B2%88%EC%97%90</guid>
            <pubDate>Fri, 29 Mar 2024 06:23:08 GMT</pubDate>
            <description><![CDATA[<p><a href="https://web.dev/blog/array-with?hl=en">web.dev</a>링크</p>
<blockquote>
<p>web.dev 블로그에 올라온 Array.prototype.with 에 대해 설명한 내용을 정리한 것입니다.</p>
</blockquote>
<p>가끔 web.dev에 올라오는 기술 포스트들을 보면서 이해할 수 있는것들을 이해해 보려 하는데 올해 올라온 기술로그 중 Array.prototype.with 에 대해 기술해 둔 기술로그를 발견하여 내가 이해한 대로 정리해 보려한다.</p>
<pre><code class="language-javascript">Array.prototype.with(index, value)</code></pre>
<p>는 Array를 <strong>복사</strong>하고 복사된 복사본의 index 에 있는 값을 value로 바꿔주는 역할을 한다.</p>
<pre><code class="language-javascript">const ages = [10, 15, 20, 25];

const newAges = ages.with(1, 16);
console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 15, 20, 25] (unchanged)</code></pre>
<p>기존에 위의 과정을 수행하려면</p>
<pre><code class="language-javascript">const ages = [10, 15, 20, 25];
const newAges = [...ages];

newAges.splice(1,1,16)
console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 15, 20, 25] </code></pre>
<p>의 한 과정을 거쳤어야 했지만 with 를 사용하면서 복사, 변경의 과정을 한번에 처리 가능하게 되었다. 당장은 어떤 상황에서 써야 이득일지 모르겠지만 기억해 둔다면 언젠가 아! 이런 메쏘드가 있었지 하면서 사용 할 날이 오지 않을까 싶다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[신입 프론트 엔드 개발자, 백엔드 개발자와 소통시 이것만은 알고가자!]]></title>
            <link>https://velog.io/@horang-e/%EC%8B%A0%EC%9E%85-%ED%94%84%EB%A1%A0%ED%8A%B8-%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%99%80-%EC%86%8C%ED%86%B5%EC%8B%9C-%EC%9D%B4%EA%B2%83%EB%A7%8C%EC%9D%80-%EC%95%8C%EA%B3%A0%EA%B0%80%EC%9E%90</link>
            <guid>https://velog.io/@horang-e/%EC%8B%A0%EC%9E%85-%ED%94%84%EB%A1%A0%ED%8A%B8-%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%99%80-%EC%86%8C%ED%86%B5%EC%8B%9C-%EC%9D%B4%EA%B2%83%EB%A7%8C%EC%9D%80-%EC%95%8C%EA%B3%A0%EA%B0%80%EC%9E%90</guid>
            <pubDate>Mon, 08 Jan 2024 03:11:36 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요. 이제 갓 2년차에 접어든 프론트엔드 개발자입니다.. 이 글은 제가 부캠, 실무1년중 백엔드분들과의 소통시 항상 머리속으로 그리던 의식의 흐름 플로우를 작성해봤습니다! (제 기준) 이정도까지 체크했는데 안되면 백엔드에게 토스 가능하다고 봅니다! (물론 제 기준이에요 .. ㅜ)</p>
<h4 id="1-넘겨받은-api-문서-그대로-코드를-짠다">1. 넘겨받은 api 문서 그대로 코드를 짠다.</h4>
<h4 id="2-코드를-실행한다">2. 코드를 실행한다.</h4>
<h4 id="3-에러가-발생한다-혹은-원하는-데이터가-넘어오지-않는다">3. 에러가 발생한다. 혹은 원하는 데이터가 넘어오지 않는다.</h4>
<p><img src="https://velog.velcdn.com/images/horang-e/post/0823f5a5-59cc-4e40-8c4d-ad5fdc0391f1/image.jpeg" alt=""></p>
<h4 id="4-백엔드-개발자님을-호출한다-이거-안돼욧-봐주세여-뿌엥">4. 백엔드 개발자님을 호출한다. (&quot;이거 안돼욧! 봐주세여!! 뿌엥&quot;)</h4>
<p>이러면 안됩니다..! 그거 들어보셨죠 구조를 요청할때는 </p>
<blockquote>
<p>&quot;거기 빨간옷 입으신 여학생분! 지금당장 119에 전화해주세요!&quot; </p>
</blockquote>
<p>라고 해야 한다는 내용. 얘랑 비슷한 맥락으로 백엔드 개발자님에게 에러상황을 넘기려면 
<strong>어떤 api</strong>에서 <strong>어떤 요청</strong>을 보냈을때 <strong>어떤 에러</strong>가 떴다! 를 전달드려야 백엔드 개발자분들이 파악하고 확인이 가능합니다.</p>
<p>그럼 어떻게 에러상황을 넘기냐! 이제 세세한 시나리오로 들어가 봅시다.</p>
<h3 id="1-개발자-도구의-네트워크-탭을-킨다">1. 개발자 도구의 네트워크 탭을 킨다.</h3>
<h4 id="11-원하는-페이지에서-해당-api-요청이-넘어갔다---2로-이동">1.1 원하는 페이지에서 해당 api 요청이 넘어갔다. -&gt; 2로 이동</h4>
<h4 id="12-원하는-페이지에서-해당-api-요청이-발생하지-않았다---3로-이동">1.2 원하는 페이지에서 해당 api 요청이 발생하지 않았다. -&gt; 3로 이동</h4>
<h3 id="2-네트워크-탭의-해당-api를-클릭하여-payload-탭을-클릭한다">2. 네트워크 탭의 해당 api를 클릭하여 Payload 탭을 클릭한다.</h3>
<p>에러 status code를 확인한다.
<a href="https://www.whatap.io/ko/blog/40/">https://www.whatap.io/ko/blog/40/</a> 여기서 한번 어떤 모양의 오류인지 확인해보시면 좋을것같습니다.</p>
<p><em>일반적으로 저의 경우에는
404에러 -&gt; 엔드포인트 잘못 입력
500에러 -&gt; 백엔드쪽에서 개발 이후 문서 작성은 했지만 푸시를 안함(?)</em></p>
<h4 id="21-백엔드-api-문서를-키고-내가-올바른-endpoint-올바른-methodgetpostdeleteput-올바른-방식body에-request-값을-담는지-parameter로-넘기는지올바른-변수명중요으로-데이터를-요청하는지-다시한번-확인한다">2.1 백엔드 api 문서를 키고 내가 올바른 endpoint, 올바른 method(GET,POST,DELETE,PUT...), 올바른 방식(body에 request 값을 담는지, parameter로 넘기는지...),올바른 변수명(중요)으로 데이터를 요청하는지 다시한번 확인한다.</h4>
<pre><code>저같은 경우는 보통 2.1 에서 걸려서 수정,해결해왔습니다</code></pre><h4 id="22-그럼에도-불구하고-원하는-데이터가-넘어오지-않는다거나-에러가-발생한다">2.2 그럼에도 불구하고 원하는 데이터가 넘어오지 않는다거나 에러가 발생한다.</h4>
<p><img src="https://velog.velcdn.com/images/horang-e/post/3b992066-5c75-4af3-947d-61abb2090c89/image.gif" alt="">
위대하시고 멋지신 백엔드 개발자님... 제가 <strong>이런 api</strong>로 <strong>이런 요청</strong>을 <strong>이런 request 값</strong>으로 보냈는데 원하는 데이터가 들어오지 않아요.. 혹은 에러가 발생해요.. 시간이 나신다면 한번만 봐주시겠어요..?? (간절)</p>
<p><em>에러 발생시 response탭으로 에러 메세지가 들어오니 해당 메세지도 함께 보여드린다면 더 쉽게 찾으실거에요.</em></p>
<h3 id="3-console-탭을-켜-오류가-발생했는지-확인한다">3. Console 탭을 켜 오류가 발생했는지 확인한다.</h3>
<h4 id="31-오류가-있다---오류를-해결한다">3.1 오류가 있다. -&gt; 오류를 해결한다.</h4>
<h4 id="32-오류가-없다---코드를-킨다">3.2 오류가 없다. -&gt; 코드를 킨다.</h4>
<p>코드에서 해당 api를 호출하는 위치에서 해당 호출 함수등이 라이프사이클 내에서 정확히 작동하는지 콘솔을 찍어가면서 확인한다.!</p>
<p>내 기준 이정도만 확인해도 이거안대여!! 하고 앗 제가 잘못했네요 (머쓱) 하는 상황은 거의 없었으니까 다들 최소 이부분은 확인하고 넘기도록 합시다!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React.memo]]></title>
            <link>https://velog.io/@horang-e/React.memo</link>
            <guid>https://velog.io/@horang-e/React.memo</guid>
            <pubDate>Mon, 20 Nov 2023 03:03:54 GMT</pubDate>
            <description><![CDATA[<p>가끔 개발을 하다 보면 원치않는 리랜더링이 계속적으로 발생해 화면 상에서 문제가 있을 때가 있다. 부모 컴포넌트에 있는 state 의 변화에 의해 자식 컴포넌트의 리랜더링 이라거나 하는 경우 말이다.</p>
<p>머리 한구석에서 아! memoization 이라고 기억하고 있는 기술이 있었던것 같은데.. 하면서 찾아본 React.memo 에 대해 이해한 내용을 적어보려한다!</p>
<h3 id="memoization">Memoization</h3>
<ul>
<li>이전값을 메모리에 저장해 빠른 처리를 가능하게 하는 기술</li>
<li>결과를 캐싱하여 저장하고 있다가 다음 작업에 들어오는 결과값이 같다면 랜더링을 하지 않음</li>
</ul>
<p>React에서 메모이제이션을 가능하게 해주는 방법은 React.memo,useCallback, useMemo가 있지만 그중에 React.memo를 알아봤다.
    - 이유는 useCallback, useMemo는 찾아보니 복잡한 계산 결과 등의 처리를      할 때 쓰인다고 나와있었는데 아무리생각해도 나는 그런 이유때문이 아닌것 같다      고 생각해서..? 이다.</p>
<h3 id="reactmemo">React.memo</h3>
<p>React.memo는 리액트에서 memoizing을 위해 사용되는 React HOC(Higher-order components)이다. </p>
<blockquote>
<p>HOC(High Order Component)즉 고차 컴포넌트는 &#39;컴포넌트 로직 재사용&#39;을 위한 패턴입니다. 현재는 Hooks 를 사용한 로직 재사용이 더 일반적이지만 로직 재사용만을 아닌 컴포넌트 자체에서 조건부 랜더링을 하게 하기 위해서는 HOC가 더 적합하다.</p>
</blockquote>
<p>React.memo는 부모컴포넌트에서 넘어온 props를 기억하고 있다가 부모컴포넌트가 리랜더링 된다고 해도 이전 props의 값과 같다면 해당 React.memo로 감싸진 자식 컴포넌트의 경우 다시 랜더링을 하지 않는다. (자기자신의 state값 변화시에는 리랜더링 O) </p>
<p>여기서 알아야할 점은! 
React.memo는 props 비교시 <strong><em>얕은 비교</em></strong> 를 진행한다. 원시 값의 경우는 같은 값을 갖는지 확인하고 참조값은 같은 주소 값을 가지고 있는 지 확인한다.결론적으로 memo는 props의 값이 원시값일 때만 유효하고 참조값일 때는 유효하지 않는다.</p>
<blockquote>
<p><em>원시값</em> : 원시값은 문자열, 숫자, 불리언 등과 같이 값 자체가 비교 가능한 데이터. 예를 들어, string, number, boolean 등의 데이터</p>
</blockquote>
<blockquote>
<p><em>참조값</em> : 참조값은 객체나 배열과 같이 메모리 상에서 독립적인 객체로 존재하는 데이터. 예를 들어, object, array 등의 데이터</p>
</blockquote>
<p>이는 리액트에서 객체를 비교할 때는 &quot;얕은 비교&quot;를 하기 때문이다</p>
<pre><code class="language-js">function sumFactory() {
  return (a, b) =&gt; a + b;
}

const sum1 = sumFactory();
const sum2 = sumFactory();

console.log(sum1 === sum2); // =&gt; false</code></pre>
<p>위는 얕은 비교의 예시다. 주소(sum1, sum2)에 의한 비교지 각각의 내용물은 비교하지 않는다.</p>
<h4 id="비교함수">비교함수</h4>
<p>보통 서버와 통신해서 axios 등을 통해 서버에서 가져온 값 랜더링 하는 경우 response로 들어오는 값은 보통 객체나 배열형태이다. 즉 참조값인 셈이다. 이럴때는 사용을 못하는걸까? 대답은 아니다! 가능하다! </p>
<p>React.memo의 두번째 인자로 비교함수를 싣어서 사용하면 해당 HOC 가 리랜더링 될 때마다 해당 비교함수를 통해서 이전 props 값과 비교해준다.</p>
<pre><code class="language-js">const areEqual = (prevProp, nextProp) =&gt; {
  return prevProp.obj.count === nextProp.obj.count;
};

const MyComponent = React.memo(({ obj }) =&gt; {
  // 렌더링 로직
}, areEqual);</code></pre>
<p>React.memo에 대한 내용을 찾아보면서 항상 모든 블로그 등에 나오는 마지막 말이 있다. React.memo는 오직 성능 최적화를위해서만 사용된다. 랜더링 &#39;방지&#39;를 위해서 사용은 위험하다.는 말이였다. 사실 이 말은 아직 체감하거나 경험해본 바가 없어서 이해도 되지 않을 뿐더러 그럼 어떤상황에 써야 최적인가? 라는 의문이 들긴 한다만 너무 많이 쓰지 말라는 말이겠거니와.. 생각해본다!</p>
]]></description>
        </item>
    </channel>
</rss>