<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>h22chan_dev.log</title>
        <link>https://velog.io/</link>
        <description>디발자겸 개자이너</description>
        <lastBuildDate>Sun, 24 Nov 2024 19:17:41 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>h22chan_dev.log</title>
            <url>https://velog.velcdn.com/images/h22chan_dev/profile/506899f4-8a50-48cd-a885-d3a0c3923ca7/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. h22chan_dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/h22chan_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[리액트 18의 주요 변화 : 자동 배치]]></title>
            <link>https://velog.io/@h22chan_dev/React18-AutomaticBatching</link>
            <guid>https://velog.io/@h22chan_dev/React18-AutomaticBatching</guid>
            <pubDate>Sun, 24 Nov 2024 19:17:41 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 모던 리액트 Deep Dive를 기반으로 작성되었습니다.</p>
</blockquote>
<hr>
<br>

<h2 id="💎react-버전-변화">💎React 버전 변화</h2>
<p>조만간 19버전이 나온다는 소식을 들었는데 19버전이 나오기전에 17버전과 18버전의 주요 변화를 보면서, 미리 변화를 감지해보자 :)!
<img src="https://velog.velcdn.com/images/h22chan_dev/post/f7bd4cda-5de5-4553-af87-be0b2b8ee6f1/image.png" alt=""></p>
<hr>
<br>

<h2 id="💎자동-배치란">💎자동 배치란?</h2>
<p>자동 배치란 React 18에서 도입된 기능으로 React 18 이전에는 이벤트 핸들러 내부의 상태 업데이트만 배치 처리되었고, 다른 비동기 작업(예: setTimeout, fetch)에서는 배치가 자동으로 이루어지지 않았다. React 18에서는 모든 상태 업데이트를 자동 배치하여, 모든 상황에서 성능 최적화를 지원한다.</p>
<blockquote>
<p>여러 상태 업데이트를 한 번의 렌더링으로 처리하는 것을 의미한다.</p>
</blockquote>
<hr>
<br>

<h2 id="💎react-18-이전에는">💎React 18 이전에는?</h2>
<p>그렇다면, React 18 이전에는 어땠고 무슨 문제가 있었길래 React 18에서 새롭게 추가가 되었을까?</p>
<h3 id="⚡️react-17-이하에서-배치는">⚡️React 17 이하에서 배치는?</h3>
<p>React 17까지는 동기적 상태 업데이트를 기본으로 했다. 이벤트 핸들러 내부에서는 상태 업데이트가 자동으로 배치 처리되었지만, 비동기 작업에서는 각 상태 업데이트가 개별적으로 처리되었다.</p>
<blockquote>
<p>이벤트 핸들러 내부에는 자동 배치 처리, 그러나 비동기 작업에서는 개별적 처리</p>
</blockquote>
<h3 id="⚡️무슨-문제가-있었지">⚡️무슨 문제가 있었지?</h3>
<p>비동기 작업에서는 자동 배치 처리가 불가능하기에 개별적 처리가 일어났고, 그에 따라 상태 업데이트마다 렌더링이 발생</p>
<blockquote>
<p>상태 업데이트마다 렌더링이 발생된다는 건 성능상에 문제점</p>
</blockquote>
<h3 id="⚡️코드-예제">⚡️코드 예제</h3>
<p>버튼 클릭 시 로딩 UI가 뜨며 데이터 로드 코드</p>
<pre><code class="language-javascript">import React, { useState } from &quot;react&quot;;

function FetchDataExample() {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  const fetchData = async () =&gt; {
    setIsLoading(true); // 로딩 시작
    const response = await fetch(&quot;https://jsonplaceholder.typicode.com/posts/1&quot;);
    const result = await response.json();
    setData(result); // 데이터 업데이트
    setIsLoading(false); // 로딩 종료
  };

  return (
    &lt;div&gt;
      &lt;button onClick={fetchData}&gt;Fetch Data&lt;/button&gt;
      {isLoading &amp;&amp; &lt;p&gt;Loading...&lt;/p&gt;}
      {data &amp;&amp; &lt;p&gt;{data.title}&lt;/p&gt;}
    &lt;/div&gt;
  );
}

export default FetchDataExample;
</code></pre>
<p>이 코드의 렌더링을 분석해보면</p>
<ul>
<li><p>🌸첫 번째 상태 업데이트 (setIsLoading(true)):
  isLoading 상태가 true로 업데이트되면서 첫 번째 렌더링 발생.
화면에 &quot;Loading...&quot; 메시지가 표시</p>
</li>
<li><p>🌸두 번째 상태 업데이트 (setData(result)):
  data 상태가 업데이트되면서 두 번째 렌더링 발생.
로드된 데이터가 화면에 표시</p>
</li>
<li><p>🌸세 번째 상태 업데이트 (setIsLoading(false)):
  isLoading 상태가 false로 업데이트되면서 세 번째 렌더링 발생.
&quot;Loading...&quot; 메시지가 사라짐</p>
<blockquote>
<p>총 3번의 렌더링</p>
</blockquote>
</li>
</ul>
<hr>
<br>

<h2 id="💎react-18-이후에는">💎React 18 이후에는?</h2>
<p>위의 코드 예제와 같이 비동기함수에도 자동배치가 가능하여 단 1번의 렌더링만 일어난다.</p>
<h3 id="⚡️동작원리">⚡️동작원리</h3>
<p>React 18에서는 상태 업데이트를 React 내부 큐에 저장하고, 이것들을 한 번의 렌더링으로 묶어서 처리한다. 그러나 17에서는 이 동작이 제한적으로 특정 조건에서만 이루어졌음. 즉, React에서 제어하는 이벤트 핸들러에서만 배치</p>
<p>setTimeout이나 Fetch, Axios 등 브라우저에서 동작하거나 React 내부에서 발생하는 비동기 작업에는 제한적이었음.</p>
<p><img src="https://velog.velcdn.com/images/h22chan_dev/post/689c911c-df0f-414a-9c35-9a437e501a6e/image.png" alt=""></p>
<hr>
<br>

<h2 id="💎과연-항상-좋을까">💎과연 항상 좋을까?</h2>
<p>과연 비동기 함수도 자동 배치되어 하나의 렌더링으로 처리하는 것이 항상 좋지 않을 수도 있다. 결국 즉각적인 렌더링이 필요할 수도 있다. 이럴 땐 flushSync를 사용하여 배치를 강제 중단하고 즉시 렌더링을 수행할 수 있다.</p>
<h3 id="⚡️flushsync-사용-o">⚡️flushSync 사용 O</h3>
<pre><code class="language-javascript">import React, { useState } from &quot;react&quot;;
import { flushSync } from &quot;react-dom&quot;;

function ScrollSyncExample() {
  const [items, setItems] = useState([1, 2, 3]);

  const addItem = () =&gt; {
    flushSync(() =&gt; {
      setItems((prevItems) =&gt; [...prevItems, prevItems.length + 1]);
    });

    const container = document.getElementById(&quot;container&quot;);
    container.scrollTop = container.scrollHeight;
  };

  return (
    &lt;div&gt;
      &lt;button onClick={addItem}&gt;Add Item&lt;/button&gt;
      &lt;div
        id=&quot;container&quot;
        style={{
          maxHeight: &quot;100px&quot;,
          overflowY: &quot;auto&quot;,
          border: &quot;1px solid black&quot;,
        }}
      &gt;
        &lt;ul&gt;
          {items.map((item) =&gt; (
            &lt;li key={item}&gt;{Item ${item}}&lt;/li&gt;
          ))}
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

export default ScrollSyncExample; </code></pre>
<blockquote>
<p>즉각적인 아이템 추가 렌더링으로 스크롤 위치의 조정이 정확해진다.</p>
</blockquote>
<h3 id="⚡️flushsync-사용-x">⚡️flushSync 사용 X</h3>
<pre><code class="language-javascript">const addItem = () =&gt; {
  setItems((prevItems) =&gt; [...prevItems, prevItems.length + 1]);

  const container = document.getElementById(&quot;container&quot;);
  container.scrollTop = container.scrollHeight;
};</code></pre>
<blockquote>
<p>스크롤 위치가 새로 추가된 항목을 고려하지 않은 상태로 계산될 가능성이 있다.</p>
</blockquote>
<hr>
<br>

<h2 id="💎결론">💎결론</h2>
<p>만약 그냥 자동배치에 대해 공부했다면 React 18에 대해서만 공부했을텐데, 17에서 18의 변화과정을 보니 양쪽 버전을 공부할 수 있어 좋은 것 같다.</p>
<p>벌써 React19라니 너무 빨라잉~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[디자이너가 Git으로 이미지 관리하기]]></title>
            <link>https://velog.io/@h22chan_dev/DesignerGitImageCompress</link>
            <guid>https://velog.io/@h22chan_dev/DesignerGitImageCompress</guid>
            <pubDate>Sun, 17 Nov 2024 17:51:07 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 모던 리액트 Deep Dive를 기반으로 작성되었습니다.</p>
</blockquote>
<h1 id="디자이너와-이미지">디자이너와 이미지</h1>
<hr>
<h2 id="📌문제">📌문제</h2>
<p>디자이너와 이미지는 뗄 수 없는 관계이다. 아이콘부터 배경, 배너이미지 등 웹사이트를 디자인하는데 많은 이미지들을 사용한다. 실제로 퍼블리싱 외주를 받고 작업을 하다보면, 클라이언트가 쇼핑몰일 경우는 미리 스튜디오에서 찍은 제품 이미지나 디자이너에게는 고화질의 풍경 이미지 등을 전달 받는다. </p>
<p><strong>이런 이미지들은 대게 5~10mb정도의 용량을 차지하고 있으며, 해당 이미지들을 그대로 웹사이트로 가져간다면 아마 사용자의 사이트 이탈률은 100%에 달할 것이다.</strong></p>
<p>실제로 Lighthouse를 실행해보면 퍼포먼스가 보통 이미지로 인해 안좋음을 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/h22chan_dev/post/36a0586e-640b-434e-acce-75ba9a8cee99/image.PNG" alt=""></p>
<p>따라서, 우리는 작업을 진행할 때 따로 Webp확장자로 변경하여 이미지를 압축하거나 Lazy Loading을 사용하여 최적화를 진행하곤 한다.</p>
<blockquote>
<p>하지만, 이미지 양이 많을수록 매번 모든 이미지를 압축할 수 없고 이는 비효율로 이어질 수 있다.</p>
</blockquote>
<br>

<hr>
<h2 id="📌해결방안-가설">📌해결방안 가설</h2>
<p>리액트 딥다이브를 공부하며 <strong>Git Action인 calibreapp/image-actions</strong>를 통해 번거로운 압축작업없이 PR되는 이미지들에게만 압축을 자동화한다면 효율적으로 관리할 수 있지 않을까하는 생각으로 시도해보고자 한다.</p>
<p><strong><em>더 비효율적이거나 안됨말구~</em></strong>
<img src="https://velog.velcdn.com/images/h22chan_dev/post/fbbae9be-3b24-48a4-b5a6-46f5b8d5a18f/image.png" alt=""></p>
<br>

<hr>
<h2 id="📌cicd">📌CI/CD</h2>
<p>GitHub Action에 대해 알아보기전에 CI/CD부터 알아보자
<img src="https://velog.velcdn.com/images/h22chan_dev/post/f5968157-c2a1-4fbe-8302-62dcbfdc3ffc/image.png" alt=""></p>
<h3 id="💎ci란">💎CI란</h3>
<p>CI란 간단하게 어플리케이션의 &quot;빌드/테스트 자동화&quot; 과정이다. 개발자들은 코딩을 이슈별, 기능별 브랜치를 파거나 따로 작업한 후 최종적으로 제일 상단의 마스터 브랜치에 합병을 통해 기능을 통합한다. </p>
<p>이때, 여러 명의 개발자가 동시에 코드 작업을 할 경우에 충돌할 가능성이 있고 이를 방지하기 위해, 자동적으로 빌드 및 테스트되어 통합할 수 있다.</p>
<h3 id="💎cd란">💎CD란</h3>
<p>CD란 &quot;배포 자동화&quot; 과정이다. CI를 통해 문제가 없이 통과된다면 자동적으로 배포가 된다. </p>
<h3 id="💎cicd-적용-전과-후">💎CI/CD 적용 전과 후</h3>
<h4 id="⚡️적용-전-통합-과정">⚡️적용 전 통합 과정</h4>
<blockquote>
<ol>
<li>코드 수정</li>
<li>각 브랜드치에 코드 push</li>
<li>git 통합</li>
<li>오류 발견 -&gt; 디버깅 -&gt; 반복</li>
</ol>
</blockquote>
<h4 id="⚡️적용-후-통합-과정">⚡️적용 후 통합 과정</h4>
<blockquote>
<ol>
<li>코드 수정</li>
<li>각 브랜드치에 코드 push</li>
<li>push를 통해 알아서 Build, Test, Lint</li>
<li>에러 결과 확인 및 수정 후 git 통합 </li>
<li>CI서버에서 자동 배포</li>
</ol>
</blockquote>
<p>크게 달라진 것이나 필요한가 싶은 생각도 있겠지만, 푸쉬간 컨플릭트나 하나하나 빌드 및 테스트를 해본 개발자라면 CI/CD의 중요성에 대해서 알 것이다.</p>
<h3 id="💎jenkins">💎Jenkins</h3>
<p>대표적인 CI/CD 환경 구축을 위해 많이 쓰인 솔루션이지만 문제점이 많았다. 어떤 기능이 있고 어떤 불편함이 있는지는 다루지 않겠다.
<br></p>
<hr>
<h2 id="📌git-action">📌Git Action</h2>
<p>그렇다면 Git Action은 무엇인가?</p>
<h3 id="💎또-다른-cicd-솔루션">💎또 다른 CI/CD 솔루션</h3>
<p>사실 Git Action은 CI/CD를 목적으로 만들어진 것이 아닌, 깃허브 저장소를 기반으로 깃허브에서 발생하는 다양한 이벤트를 트리거 삼아 다양한 작업을 할 수 있게 도와주는 것이다.</p>
<p>이러한 특징은 Git Action을 통해 CI/CD 솔루션을 대체 할 수 있음에 널리 퍼지기 시작했다.</p>
<h3 id="💎유용한-액션-끌어쓰기">💎유용한 액션 끌어쓰기</h3>
<p>물론 직접 액션을 작성해도 좋지만, 라이브러리와 같이 미리 만들어져있는 액션들을 가져다 쓸 수 있다. 그 중 하나가 이번 글에서 시도하고자하는 calibreapp의 image-actions이다.
<img src="https://velog.velcdn.com/images/h22chan_dev/post/8101e7a1-8e4a-4ca3-846a-d3f0fab8bae4/image.png" alt=""></p>
<br>

<hr>
<h2 id="📌calibreappimage-actions">📌calibreapp/image-actions</h2>
<p>초반에 말했듯이 이미지들은 사용자에게 불편함을 주지 않는 선에서 가장 작은 파일로 관리될 필요가 있는데, 이 이미지를 압축해 관리하는 게 여간 귀찮은 일이 아니다. image-actions는 PR로 올라온 이미지를 sharp 패키지를 통해 거의 무손실로 압축하여 커밋해준다.</p>
<h3 id="💎사용법">💎사용법</h3>
<h4 id="⚡️-1-파일-생성">⚡️ 1. 파일 생성</h4>
<p>다음과 같이 프로젝트 파일 안에 꼭 .github/workflows/calibreapp-image-actions.yml이라는 파일을 생성해준다.</p>
<pre><code>Project/
│
├── .github/
│   └── workflows/
│       └── calibreapp-image-actions.yml
├── public/
├── src/
├── .DS_Store
├── .gitignore
├── README.md
├── db.json
├── package-lock.json
└── package.json</code></pre><br>

<h4 id="⚡️-2-코드-추가">⚡️ 2. 코드 추가</h4>
<p>그 뒤 아래와 같은 코드를 입력한다.</p>
<pre><code>// calibreapp-image-actions.yml

name: Compress images
on: pull_request
jobs:
  build:
    name: calibreapp/image-actions
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@master
      - name: Compress Images
        uses: calibreapp/image-actions@master
        with:
          githubToken: ${{ secrets.GITHUB_TOKEN }}</code></pre><blockquote>
<p><strong>on : pull_reqest</strong>
PR이 발생하면 액션을 실행시킨다. 만약 push를 입력하면 push시에 acition이 일어난다.</p>
</blockquote>
<blockquote>
<p><strong>githubToken: ${{ secrets.GITHUB_TOKEN }}</strong>
GITHUB_TOKEN을 만들고 .env 등에 등록해놔야할 것 같지만, 아무것도 할 것 없다. 자동적으로 레포 생성 시 토큰이 발행된다고 한다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/h22chan_dev/post/1a9ef530-1909-49be-a18b-f2df075e237d/image.PNG" alt=""></p>
<h4 id="⚡️-3-브랜치-생성">⚡️ 3. 브랜치 생성</h4>
<p>이후 아무 이름으로 브랜치를 생성한다.</p>
<hr>
<h5 id="🤬브랜치-생성-시-주의사항🤬">🤬브랜치 생성 시 주의사항🤬</h5>
<p>여기서 &quot;아무 이름&quot;이라고 해서 절대 아무 이름으로는 하지말자..
<img src="https://velog.velcdn.com/images/h22chan_dev/post/b6f57301-d7f1-445b-b1a2-3593041fb5d1/image.PNG" alt=""></p>
<p>다음과 같이 브랜치 이름에 #을 붙혔다가 2시간동안 작동이 안되어서 고생했다.</p>
<p>로그를 살펴보니 아래와 같은 오류가 떴고, 설마 브랜치를 못찾아서 그런것 같길래 찾아보니.. 브랜치 네이밍시에 #을 넣으면 주석처리로 이해한다고 한다...</p>
<pre><code>HttpError: Reference does not exist</code></pre><br>

<h4 id="⚡️-4-이미지-추가-후-pr">⚡️ 4. 이미지 추가 후 PR</h4>
<p>이후에 이미지를 추가한 후에 PR을 날리면 자동으로 압축이 진행된다. 압축을 진행하면 액션봇이 얼마나 줄여졌는지 친절하게 알려준다.
<img src="https://velog.velcdn.com/images/h22chan_dev/post/737f059a-e9ca-434b-9b26-4a6218ce164e/image.png" alt=""></p>
<h5 id="🤬에러🤬">🤬에러🤬</h5>
<p><strong>HttpError: Resource not accessible by integration 에러</strong></p>
<ul>
<li>Action창에서 아래와 같이 설정해줘야 한다
<img src="https://velog.velcdn.com/images/h22chan_dev/post/75f5514e-fd49-48d3-8a77-1f5ab77e627b/image.png" alt=""></li>
</ul>
<br>

<h3 id="💎추가사항">💎추가사항</h3>
<p>다양하게 시도해본 결과 압축할 필요가 없는 이미지에 대해서는 압축을 진행하지 않는다. 만약 모든 이미지를 압축하기를 원하거나, 이미지만 압축을 원한다면 yml파일에서 수정하면 된다. 어떻게 수정해야하는지는 공식문서에 잘 나와있다.</p>
<p><a href="https://github.com/calibreapp/image-actions?tab=readme-ov-file#configuration">image-actions 공식문서</a>
<br></p>
<h2 id="📌결론">📌결론</h2>
<p>실제 이미지가 12.8MB임에도 불구하고 압축없이 해당 이미지를 그대로 홈페이지에 불러왔다. 이후 PR을 날렸을 뿐인데 알아서 1.4MB까지 압축해서 업로드되었다.</p>
<p><img src="https://velog.velcdn.com/images/h22chan_dev/post/56ca80e6-8dad-4dd8-ba21-032d5ae23635/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/h22chan_dev/post/8e7e13d2-a3dc-4450-85aa-446f36de1123/image.png" alt=""></p>
<p>기존의 방식이였으면 ILoveIMG같은 곳에서 압축을 진행하고 업로드를 진행했을텐데 정말 편했다. 중간과정이 사라져 버리고 자동화가 되었으니</p>
<p>생각보다 많이 해메이긴했는데 Action 자체에 대한 어려움은 아니라, 되게 쉽다고 볼 수 있을 것 같다. 앞으로는 action을 통해서 이미지를 압축하는 방법을 택할 것 같다.
<img src="https://velog.velcdn.com/images/h22chan_dev/post/f8d87b5f-84f9-4e8e-8d5c-d3524964f4aa/image.png" alt="">
<br></p>
<hr>
<h2 id="📌참고문헌">📌참고문헌</h2>
<p><a href="https://medium.com/@besoftyoon/github-actions-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%9A%A9%EB%9F%89%EC%9D%B4-%ED%81%B4-%EB%95%8C-%EC%95%95%EC%B6%95%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-e03a6443efad">[Github Image Actions] 이미지 용량 압축해주는 액션</a>
<a href="https://velog.io/@seorim6417/%EC%9E%90%EB%8F%99%EC%9C%BC%EB%A1%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%95%95%EC%B6%95%ED%95%98%EA%B8%B0">자동으로 이미지 압축해보실래요?</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 개발 도구로 최적화하기]]></title>
            <link>https://velog.io/@h22chan_dev/ReactDevTools</link>
            <guid>https://velog.io/@h22chan_dev/ReactDevTools</guid>
            <pubDate>Sun, 10 Nov 2024 19:44:47 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 모던 리액트 Deep Dive를 기반으로 작성되었습니다.</p>
</blockquote>
<h1 id="리액트-개발-도구">리액트 개발 도구</h1>
<p>리액트 팀에서 제공하고 있는 react-dev-tools를 알아보자. 리액트로 만들어진 다양한 사이트를 디버깅하기 위해 만들어졌으며, 리액트뿐만 아니라 네이비티브 등 다양한 플랫폼에서 사용할 수 있다. </p>
<p><strong>크롬과 파이어폭스 엣지 브라우저에서 제공하지만, 대부분의 사용자가 크롬을 사용하기때문에 크롬을 기준으로 설명하겠다.</strong></p>
<h2 id="📌설치">📌설치</h2>
<p>개발 도구를 설치해야하는데 어렵지 않다. 크롬의 경우 확장 프로그램을 설치하면 된다. 설치를 완료하면 우측 상단에서 확인할 수 있다!
<img src="https://velog.velcdn.com/images/h22chan_dev/post/6d1a785a-1eee-4527-8c7d-2b82cfd231ae/image.PNG" alt=""></p>
<p><img src="https://velog.velcdn.com/images/h22chan_dev/post/54f87878-1f1f-433b-8127-826f0728d03c/image.PNG" alt=""></p>
<blockquote>
<p>일반적인 로고 모양 : 현재 페이지가 리액트로 배포되어있다.
빨간 로고 모양 : 리액트가 개발자 모드로 실행되고있다.</p>
</blockquote>
<br>

<h2 id="📌활용">📌활용</h2>
<h3 id="💎컴포넌트components">💎컴포넌트(Components)</h3>
<p>Compontents 탭에서는 리액트 어플리케이션의 컴포넌트 트리를 확인할 수 있다. 단순히 구조만 확인하는게 아니라, props나 내부 hooks 등 다양한 정보를 확인할 수 있다!
<img src="https://velog.velcdn.com/images/h22chan_dev/post/475e1091-6766-43e8-a192-a21a0578a841/image.PNG" alt=""></p>
<h4 id="⚡️기명함수와-익명함수">⚡️기명함수와 익명함수</h4>
<p>정상정인 함수 선언식과 함수 표현식을 통해 생성된 컴포넌트는 모두 정상적으로 함수명을 표시하지만, 그렇지 않은 컴포넌트는 Anonymous나 _default로 보인다.</p>
<pre><code class="language-Javascript">//App.tsx
import DefaultComponent from &#39;./DefaultComponent&#39;

export default function App() {
    return (
        &lt;DefaultComponent /&gt;
    )
}

// DefaultComponent.tsx
export default () =&gt; {
    return &lt;&gt;DefaultComponent&lt;/&gt;
}</code></pre>
<p>위의 코드는 컴포넌트 트리를 보면 DefaultComponent의 함수명을 확인할 수 없어 함수명을 제대로 확인할 수 없다. 그 외에도 memo 또는 고차 컴포넌트 예시가 있는데 이런 부분은 모두 함수명을 제대로 정의 하지 않는 경우와 동일하다.</p>
<h4 id="⚡️displayname">⚡️displayName</h4>
<p>만약 함수로 기명함수로 변경하기 어렵다면 displayName을 사용하면 좋다. 다만, 빌드 시에 사용하지 않는 코드로 인식할 가능성도 있기에 개발 모드에서만 제한적으로 참고하는 것이 좋다.</p>
<pre><code>const MemoizedComponent = memo(function () {
    return &lt;&gt;MemoizedComponent&lt;/&gt;
})

MemoizedComponent.displayName = &quot;메모 컴포넌트입니다.&#39;</code></pre><p><img src="https://velog.velcdn.com/images/h22chan_dev/post/0aa3150d-4fe9-4a20-8f81-cafaaf6093e4/image.PNG" alt=""><img src="https://velog.velcdn.com/images/h22chan_dev/post/e1276d9b-85b0-499b-b6ba-a66c6120c85f/image.png" alt=""></p>
<h4 id="⚡️컴포넌트-props--컴포넌트-hooks">⚡️컴포넌트 props &amp; 컴포넌트 hooks</h4>
<p>우측 패널에 props정보와 hooks과 같은 정보가 나온다. 훅도 마찬가지로, 익명함수냐 기명함수냐에 따라 보여지는 이름이 다르다.
<img src="https://velog.velcdn.com/images/h22chan_dev/post/da5be77b-9295-46fe-944c-29e5bbb223e5/image.PNG" alt=""></p>
<pre><code>// 익명함수
useEffect(() =&gt; {
    console.log(&#39;useEffect&#39;)
})

// 기명함수
useEffect(function effectOnlyMount() {
    console.log(&#39;useEffect&#39;)
})</code></pre><br>

<h3 id="💎프로파일러">💎프로파일러</h3>
<p>컴포넌트와 다르게 프로파일러는 렌더링하는 과정에서 발생하는 상황을 확인하기 위한 도구이다. 프로파일러는 렌더링 과정에 개입하여 기록하기에 프로덕션 빌드로 실행된 리액트 애플리케이션에는 사용이 불가능하다.</p>
<h4 id="⚡️프로파일러로-input-렌더링-살펴보기">⚡️프로파일러로 Input 렌더링 살펴보기</h4>
<p>프로파일러를 통해 input에 텍스트를 입력하는 렌더링 과정을 살펴보면 매번 입력할 때 마다 전체 input이 아닌 DailyWrite 전체가 렌더링된다.
<img src="https://velog.velcdn.com/images/h22chan_dev/post/df0445b5-d2ea-4ef8-9c8c-b6726fbeb6c1/image.PNG" alt=""><img src="https://velog.velcdn.com/images/h22chan_dev/post/20d9c4d8-0758-4813-9f7b-43fbd9dd9dc5/image.PNG" alt=""></p>
<p>이유는, input의 value값을 저장하는 데이터가 DailyWrite에 선언되어있기때문에 state가 변경되면 전체가 렌더링 된다.</p>
<p><img src="https://velog.velcdn.com/images/h22chan_dev/post/4f80c0f6-2359-46b4-b3a0-0c2b5917a9a1/image.PNG" alt=""></p>
<p>이 input 컴포넌트를 따로 분리하여 사용한다면, input의 상태 값이 변경할 때마다 DailyWrite가 변경되는 것이 아닌, input컴포넌트만 리렌더링되어 성능에 최적화가 가능하다.</p>
<ul>
<li><p>하단의 코드는 대략적인 느낌만을 보기 위한 코드로, 완전하지 못함을 양해바란다.</p>
<pre><code class="language-Javascript">function InputText(PH) {
  const [text, setText] = useState(&#39;&#39;)

  const handleTextChange = (e) =&gt; setText(e.target.value);

  return (
      &lt;&gt;
          &lt;input onChange={handleTextChange} placeholder={PH} /&gt;
      &lt;/&gt;
  )
}
</code></pre>
</li>
</ul>
<p>export default function App() {</p>
<pre><code>return (
    &lt;InputText PH=&quot;placeholder&quot; /&gt;
)</code></pre><p>}</p>
<pre><code>&gt; 사실 실제 졸업작품 코드를 리팩토링 해보고싶었는데 ㅎㅎ.. 꽤나 답이없다..
역시 미리미리 생각하고 코딩해야한다..

&lt;br&gt;

#### ⚡️프로파일러로 고정된 Props 렌더링 살펴보기
아래 이미지척럼 Title 컴포넌트에는 text라는 props이 고정되어있다.
![](https://velog.velcdn.com/images/h22chan_dev/post/5b4ded39-16a8-4359-9c0d-3e9279fb1747/image.PNG)
```Javascript
// Title Components
import React from &quot;react&quot;;
import styled from &quot;styled-components&quot;;

const TitleText = styled.p`
    font-size: 32px;
    font-weight:600;
    color:white;
`

function Title(props) {

    const { text } = props;

    return (
        &lt;TitleText&gt;{text}&lt;/TitleText&gt;
    )   

}

export default Title;
</code></pre><br>

<p>그러나 동일하게 input 컴포넌트에 입력하는 과정을 렌더링해보면 dispalyName으로 등록해둔 &quot;이 멍충이들아&quot;가 계속해서 리렌더링 되고있다.<img src="https://velog.velcdn.com/images/h22chan_dev/post/85710f0f-9790-4c4a-9a13-5f4c7e249e9d/image.PNG" alt=""><img src="https://velog.velcdn.com/images/h22chan_dev/post/c18726b3-9e31-4043-a644-cccf60eab08c/image.PNG" alt=""></p>
<p>만약 아래와 같이 memo를 통해 코드를 수정한다면, 이전 값을 저장하기때문에 고정된 props이라면 다시 렌더링 될 이유가 없다. 실제로 확인해보면 더 이상 렌더링 되지 않는걸 볼 수 있다.</p>
<pre><code class="language-Javascript">// After
import { memo } from &quot;react&quot;;
import styled from &quot;styled-components&quot;;

const TitleText = styled.p`
    font-size: 32px;
    font-weight:600;
    color:white;
`

const Title = memo(function Title(props) {

    const { text } = props;

    return (
        &lt;TitleText&gt;{text}&lt;/TitleText&gt;
    )  
})

export default Title;</code></pre>
<p><img src="https://velog.velcdn.com/images/h22chan_dev/post/a1faa909-b0db-409f-a75c-80181021f8cf/image.PNG" alt=""> <img src="https://velog.velcdn.com/images/h22chan_dev/post/352c5884-6428-4530-82a9-47574a44cb82/image.PNG" alt=""></p>
<br>

<h2 id="📌정리--느낀-점">📌정리 &amp; 느낀 점</h2>
<p>처음에 메모이제이션이나, 컴포넌트 관리 등에 대해서 학습했을땐 막연하게 이론적인 부분으로만 습득을 했었지 실제로 적용해볼 기회가 없었고, 딥다이브 자체가 예제코드를 어느정도의  &quot;리액트&quot;가 아닌 &quot;코딩&quot;에 대한 지식을 많이 요구하기에 내가 이해하기는 어려웠던 한계점이 있었다.</p>
<p>그러나, 리액트 개발도구를 통해서 실제 내 졸업작품의 렌더링 과정들을 살펴보니 조금 더 수월하게 이해가 갔다.</p>
<blockquote>
<p>또한, 어느정도 서비스의 규모가 커지고 복잡해지니 문제를 발견하고 수습하기에는 너무 많이 손봐야했다. 따라서 틈틈이 원하는 방향으로 렌더링이 되고 있는지, 메모이제이션을 통한 최적화를 잘 하고 있는지 확인해 볼 필요가 있을 것 같다.</p>
</blockquote>
<p>&quot;디버깅과 최적화는 틈틈이!&quot;</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVC vs FLUX]]></title>
            <link>https://velog.io/@h22chan_dev/MVCvsFLUX</link>
            <guid>https://velog.io/@h22chan_dev/MVCvsFLUX</guid>
            <pubDate>Sun, 03 Nov 2024 19:52:23 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 모던 리액트 Deep Dive를 기반으로 작성되었습니다.</p>
</blockquote>
<h1 id="리액트의-상태관리">리액트의 상태관리</h1>
<p>나 김희찬.. 이번주도 결국 벽에 부딪혔다. 껄껄.. 리액트 딥다이브 6장 [리액트와 라이브러리 상태관리].. 아니? 6장의 문제가 아니다. [리액트 딥다이브].. 넌 뭐니? 왜 이렇게 날 힘들게하는거야..</p>
<h2 id="📌상태관리">📌상태관리</h2>
<h3 id="💎상태란">💎상태란?</h3>
<p>React에서 컴포넌트 내에 관리되는 변수를 의미합니다. 다들 알고 있듯이 useState로 선언되는 것이 상태라고 볼 수가 있겠지요? 이런 상태를 잘 사용하면 좋기야 하겠지만, 문제는 각 컴포넌트간의 데이터 전달은 Props으로 전달이 되지만 이는 부모 컴포넌트를 통해서만 공유가 가능하다는 문제가 있습니다.</p>
<pre><code>const [state, setState] = useState(init);</code></pre><h3 id="💎props-drilling">💎Props Drilling</h3>
<p>부모 컴포넌트를 통해 공유가 가능하다는 이유로 인해, 중간에 있는 컴포넌트는 필요하지 않은 Props을 가져가야할 수도 있기때문에 우리가 가장 싫어하는 비효율적이며 관리가 어려워지죠. 그래서 우리는 &quot;상태 관리&quot;를 해줄 필요가 있습니다.
<img src="https://velog.velcdn.com/images/h22chan_dev/post/c77743e7-945e-4866-a946-9a89aaf164e3/image.png" alt=""></p>
<h3 id="💎상태-관리하는-방법">💎상태 관리하는 방법</h3>
<p>그렇다면 상태를 어떻게 전역적으로 관리할 수 있을까? 배운 것중엔 대표적으로 2개가 있다.</p>
<blockquote>
<ol>
<li>Context API</li>
<li>상태 관리 라이브러리</li>
</ol>
</blockquote>
<h3 id="💎context-api의-단점">💎Context API의 단점</h3>
<p>React에서 제공하는 API로 전역적으로 상태를 관리할 수 있다. 오잉 그렇다면, 굳이 상태 관리 라이브러리를 사용할 이유가 있을까? Context API는 앱 최상단에 Provider를 써야한다.</p>
<pre><code>&lt;MyContext.Provider value={/* 어떤 값 */}&gt;</code></pre><p>하지만 context가 변경되면 하위에 사용한 useContext() 녀석들은 모두 리렌더링된다는 점.. 물론, 이를 해결하는 방법이 더 있겠지만 관리할 녀석들이 많으면 많아질수록 두통을 야기할 뿐이다.</p>
<blockquote>
<p>나야.. 비효율</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/h22chan_dev/post/389fdcf7-a4a0-4174-9975-502a016d5f87/image.png" alt=""></p>
<h3 id="💎상태관리-라이브러리">💎상태관리 라이브러리</h3>
<p>그렇다면 상태 관리 라이브러리 무엇이 있을까.. 대표적으로는 아래와 같이 4가지가 있다. 앞서서 주절주절 떠들긴했는데 사실 이 글의 내용은 상태관리 라이브러리를 뭘 써야할지 뭐가 다른지에 대해 다루지 않는다. 상태관리 라이브러리를 통해 디자인 패턴을 학습하고자 한다.</p>
<blockquote>
<ol>
<li>Redux</li>
<li>Recoil</li>
<li>Jotai</li>
<li>Zustand
.
.</li>
</ol>
</blockquote>
<br>

<h2 id="📌디자인-패턴">📌디자인 패턴</h2>
<h3 id="💎디자인-패턴이란">💎디자인 패턴이란?</h3>
<p>디자인 패턴이란, 디자이너들이 사용하는 디자인이 아니다. 물론 디자인이 설계라는 의미에서 비슷하지만 대중적으로 사용되는 의미와는 다르다. 바닐라 JS에서 jQuery를 통해 간편하게 적는 것처럼 반복된 행동이나 문제를 간편하게 해결할 수 있도록 하는 솔루션의 느낌.. </p>
<h3 id="💎디자인-패턴의-종류">💎디자인 패턴의 종류</h3>
<p>1900년 후반대부터 등장해서 현재까지 수천여개의 패턴이 존재한다고 한다. 그 중 가장 유명한 Gof 디자인 패턴은 23개의 패턴을 3개의 유형으로 분류한다고 하는데 아래와 같다. 또한 자세한 내용은 찾아보면 좋을 듯하다 :). 서치해서 정리하기에는 주제랑 살짝 엇나가는 느낌이기에 스스로 찾아보시길 권장합니다.</p>
<blockquote>
<ol>
<li>생성(Creational) 패턴</li>
<li>구조(Structural) 패턴</li>
<li>행위(Behavioral) 패턴</li>
</ol>
</blockquote>
<h3 id="💎디자인-패턴은-필요한가">💎디자인 패턴은 필요한가</h3>
<p>물론 당연하다. 이전에 했던 작업이나 반복적인 작업을 매번 하고싶어하는 사람은 없을거고 작업의 효율성을 올리기위해 우리는 모두 헤매이고 있으니 꼭 알아두어야하는 지식이다. 우리 디자이너 세계에서도 구글머터리얼 디자인과같이 암묵적인 규칙이 정해져있으니
<img src="https://velog.velcdn.com/images/h22chan_dev/post/2c07cda8-3afd-4893-97da-188d8e247f34/image.png" alt="">
<br></p>
<h2 id="📌flux-패턴">📌Flux 패턴</h2>
<h3 id="💎react의-추구-패턴">💎React의 추구 패턴</h3>
<p>React의 Props에서 알 수 있듯이 React의 데이터 흐름은 단방향으로 흐르며 이는 Flux라는 디자인 패턴에 기반하여 적용된 방식이다.</p>
<h3 id="💎redux-상태관리-라이브러리">💎Redux 상태관리 라이브러리</h3>
<p>Redux는 가장 대표적으로 사용되었던 상태관리 라이브러리로서 Flux라는 디자인패턴을 기반으로 구현된 라이브러리이다. 하지만 현재는 앞서 소개했던 다양한 상태관리 라이브러리가 생겨나면서 점차 사용하지 않는 오래된 라이브러리로 취급받고 있다.</p>
<h3 id="💎flux-디자인-패턴이란">💎Flux 디자인 패턴이란?</h3>
<p>아래의 그림과 같이 데이터의 흐름 구조를 한방향으로 흐르도록 설계한 것.
<img src="https://velog.velcdn.com/images/h22chan_dev/post/a52cbcd3-c5c7-49ca-a59e-71f95cc756ad/image.png" alt=""></p>
<h3 id="💎flux-요소">💎Flux 요소</h3>
<p>Flux는 Action, Dispatcher, Store, View로 구성되며 이는 Action부터 흐르게 구성되어있다.</p>
<h4 id="action">Action</h4>
<p>Action은 단어 그자체로 사용자의 행동을 의미한다. 사용자에 의해 데이터가 변경되면 이를 Dispatcher에게 전달한다.</p>
<h4 id="dispatcher">Dispatcher</h4>
<p>Dispatcher은 모든 데이터를 관리하는 중앙 허브로 Action이 감지되면 다음 단계인 Action 타입에 따라, 접근할 수 있는 콜백함수를 이용할 수 있도록 한다.</p>
<h4 id="store">Store</h4>
<p>Store는 상태 저장소로 상태와 상태를 변경할 수 있는 메서드를 가지고 있다. Dispatcher를 통해 콜백함수가 실행되면 변경된 내용을 View에게 전달한다.</p>
<h4 id="view">View</h4>
<p>View는 단어 그대로 사용자가 보고 있는 화면이라고 생각하면 편하다. Store에서 변경된 데이터가 View를 통해 사용자에게 보여지게 된다. 이 View에서 Action이 발생되면 다시 처음 로직과 같이 Dispatcher로 접근하게 되고, 해당 타입에 따라 Store의 콜백함수가 실행되는 등 반복한다.
<br></p>
<h2 id="📌mvc-패턴">📌MVC 패턴</h2>
<h3 id="💎mvc-패턴이란">💎MVC 패턴이란?</h3>
<p>Flux패턴을 공부하면 자연스럽게 MVC 패턴을 알게 된다. 그 이유는 Flux 패턴의 존재자체가 MVC 패턴의 단점을 보완하고자 설계되었기때문에.. 그렇다면 MVC모델은 무엇인가?</p>
<p>Flux 패턴이 데이터의 흐름을 단방향으로 만들기위해 설계했다면, MVC는 Model과 Controller간의 양방향 데이터 흐름을 보여준다.<img src="https://velog.velcdn.com/images/h22chan_dev/post/c610b97f-1cf8-4916-90f3-3832db608dc8/image.png" alt=""></p>
<p>이러한 형태에서 만약 Controller와 Model의 관계가 많아진다면 양방향적인 데이터의 흐름으로 인해서, 상태관리가 굉장히 어려워진다. 그래서 이러한 MVC 패턴의 단점을 보완하고자 단방향적인 Flux패턴이 나오게 된 것이다.
<br></p>
<h2 id="📌그래서">📌그래서?</h2>
<p>결국 React 상태관리를 공부하다 보면, 자연스레 Redux 라이브러리를 접하게 되고 Flux패턴을 학습하게 된다. 이후 Flux패턴을 공부하다보면, 자연스레 MVC 패턴도 학습하게 된다. 지피지기면 백전백승. 시대가 변해 많이 쓰이지 않는 기술일지라도, 현재 사용되는 기술의 근간이 되는 경우가 많으니 알아두면 좋다.</p>
<p>MVC가 React에 적합하지 않은 디자인 패턴일지라도, 프론트는 빠르게 변화하며 MVC 패턴만의 장점이 있다. 따라서, 자세하게는 몰라도 대충은 알아두면 좋지 않을까?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[useState로 React가 JS임을 다시 깨닫기]]></title>
            <link>https://velog.io/@h22chan_dev/useStatebasedJS</link>
            <guid>https://velog.io/@h22chan_dev/useStatebasedJS</guid>
            <pubDate>Sat, 26 Oct 2024 18:41:25 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 모던 리액트 Deep Dive를 기반으로 작성되었습니다.</p>
</blockquote>
<h1 id="리액트-usestate">리액트 useState</h1>
<p>리액트에서 가장 많이 사용하는 함수를 꼽으라하면 useState를 선택할 것이다. 리액트 딥다이브 3장인 &#39;리액트 훅 깊게 살펴보기&#39;에서 useState를 공부를 하다 한가지 의문점이 생겼었다.</p>
<blockquote>
<p>useState 훅의 반환 값은 배열이다. (p.190)</p>
</blockquote>
<p>이 말이 무슨 말인지 전혀 이해가 안갔다. 디자인과를 전공하여 라이브러리나 언어에 대해서 조금 더 딥하게 알아가면 알아갈수록 자료구조와 같은 지식을 선수한 적이 없기때문에 정말 어렵다..ㅠ</p>
<p>왜 배열 값을 반환하는지 너무나 궁금해서 React의 공식문서에서 useState부분을 확인했었다. 보자마자 이해가 갔다. 아래의 글은 나의 의문에대한 해답이 맞길바란다.
<br></p>
<h2 id="📌usestate-사용법">📌useState 사용법</h2>
<p>useState 훅을 사용하는 방법은 useState의 인수로 state의 초기 값을 넘겨주고, 아무런 값을 넘겨주지 않으면 초깃값은 undefined를 반환한다. useState 훅의 반환 값은 배열이고 useState의 첫 원소로 state 값 자체를 사용할 수 있고, 두 번째 원소인 setState를 사용하여 첫 원소인 state를 변경할 수 있다. 사용 문법은 아래와 같다.</p>
<pre><code>function Compontent() {

        const [state, setState] = useState(initialState)
}</code></pre><br>

<h2 id="📌js-구조-분해-할당">📌JS 구조 분해 할당</h2>
<img src="https://velog.velcdn.com/images/h22chan_dev/post/22fa9314-689e-43b2-aa3d-72cb4d0bf653/image.png" style="display:block;">
엥? useState를 하다가 갑자기 자바스크립트의 구조분해? 뜬금이 없을수도 있고, 당연하게도 아는 사람도 있을 것이다. 정말 아무생각없이 useState를 쓰던사람으로서 과장해서 소름까지 돋았다.

<p>useState의 초기값이 없으면 왜 undefined을 반환하는지, 왜 배열을 반환하는지 알기위해서는 JS 구조분해할당을 알아야한다. 수업시간에 배웠는데 여기서 볼 줄은 상상도못했다.</p>
<blockquote>
<p>JS는 객체나 배열을 변수로 &#39;분해’할 수 있게 해주는 특별한 문법인 구조 분해 할당(destructuring assignment)을 사용할 수 있다. 이 외에도 함수의 매개변수가 많거나 매개변수 기본값이 필요한 경우 등에서 구조 분해(destructuring)는 그 진가를 발휘한다.</p>
</blockquote>
<h3 id="💎배열-분해하기">💎배열 분해하기</h3>
<p>아래의 Array의 배열은 다음과 같이 분리가 가능하다.</p>
<pre><code>let Array = [itemA, itemB];

let [A, B] = Array;

console.log(A); //itemA
console.log(B); //itemB</code></pre><p>아래와 같이 배열에 대해 사용자가 명시적으로 지정을 하지 않으면, JS는 비어있는 요소에 접근했을 때 undefined를 반환한다.</p>
<pre><code>let Array = [];

let [A, B] = Array;

console.log(A); // undefined
console.log(B); // undefined</code></pre><br>

<h2 id="📌구조-분해-할당과-usestate의-관계">📌구조 분해 할당과 useState의 관계</h2>
<p>useState에는 구조 분해할당이 사용되었다고 리액트 공식문서에 나와있다. 둘의 관계를 생각해보니 처음에 가졌던 의문이 해결되었다.</p>
<h3 id="💎usestate의-변수-이름-지정">💎useState의 변수 이름 지정</h3>
<pre><code>function Compontent() {

        const [state, setState] = useState(initialState)
}</code></pre><p>useState의 선언 모습을 보면 배열 구조 분해와 동일하다. 따라서 useState()를 사용하게되면 [dataA, dataB] 와 같은 array가 남는다. dataA에는 변수의 값과 같은 데이터가 들어있고, dataB에는 데이터를 변경할 수 있는 함수가 들어있다. 결국 Hook도 함수이다.</p>
<h3 id="💎usestate의-undefined">💎useState의 undefined</h3>
<p>자바스크립트는 빈 배열에 대해 undefined를 반환하기때문에 사용자가 명시적으로 초기값을 지정해주지 않으면 undefined를 반환한다고 볼 수 있다.</p>
<h3 id="💎usestate의-순서">💎useState의 순서</h3>
<p>당연하게도 구조 분해 할당의 배열 분해는 배열의 인덱스를 기반하기 때문에 순서가 변경되면 오류가 나거나 함수의 의미가 변한다.</p>
<pre><code>const [state, setState] = useState(initialState); // 올바른 예제
const [setState, state] = useState(initialState); // 잘못된 예제</code></pre><br>

<h2 id="📌결론">📌결론</h2>
<p>리액트가 자바스크립트의 라이브러리임을 까먹지말자</p>
<hr>
참고자료

<p><a href="https://ko.react.dev/reference/react/useState#adding-state-to-a-component">React 공식문서</a>
<a href="https://dongwookit.tistory.com/254#state%20%EB%A7%8C%EB%93%9C%EB%8A%94%20%EB%B2%95-1">리액트 useState</a>
<a href="https://dongwookit.tistory.com/254#state%20%EB%A7%8C%EB%93%9C%EB%8A%94%20%EB%B2%95-1">TIL 50 | React : useState Hook의 구조분해할당</a>
<a href="https://velog.io/@rkio/React-useState-%EC%82%AC%EC%9A%A9-%ED%9B%84-state%EA%B0%80-undefined%EB%A1%9C-%EB%82%98%EC%98%AC-%EB%95%8C">[React] useState 사용 후 state가 undefined로 나올 때</a>
<a href="https://velog.io/@jhy979/React-%EC%9E%98%EB%AA%BB%EB%90%9C-useState-%EC%82%AC%EC%9A%A9">[React] 잘못된 useState 사용</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS 싱글스레드의 비동기처리]]></title>
            <link>https://velog.io/@h22chan_dev/JS-SingleThread</link>
            <guid>https://velog.io/@h22chan_dev/JS-SingleThread</guid>
            <pubDate>Mon, 07 Oct 2024 10:17:16 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 모던 리액트 Deep Dive를 기반으로 작성되었습니다.</p>
</blockquote>
<h1 id="자바스크립트의-비동기처리">자바스크립트의 비동기처리</h1>
<p>모던 리액트를 공부하던 중 리액트 파이버에 관한 챕터에서 의문이 생겼다. 과거의 리액트를 소개하면서 자바스크립트가 싱글스레드이기에 동기 작업이 이루어진다고 했다. 그러나 내가 아는 자바스크립트는 비동기 작업으로 진행된다고 알고있다.</p>
<p>자바스크립트를 사용하는 유저라면 자바스크립트가 보통은 요청을 비동기 방식으로 처리한다고들 알고 있을 것이다. 실제로, 코드를 구현해보면 비동기식으로 처리가 되니까, 여기서 문제는 자바스크립트가 싱글스레드 구조라는 것이다.</p>
<h2 id="📌싱글스레드의-비동기처리">📌싱글스레드의 비동기처리?</h2>
<p>모순적이다. 싱글스레드면 동기 처리가 맞지않나? 어떻게 비동기처리가 가능한거지? 아래의 글을 찾아보면 자바스크립트의 메인 엔진 외에 작동하는 요소들로 인해서 비동기 처리가 가능하다고 설명한다.</p>
<blockquote>
<p>자바스크립트 엔진 밖에서도 자바스크립트 실행에 관여하는 요소들이 존재한다. 각각 Web API와 Task Queue, Event Loop 이다.<br>
<a href="https://velog.io/@eamon3481/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%8B%B1%EA%B8%80%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%B8%EB%8D%B0-%EC%99%9C-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%A0%81-%EC%9D%BC%EA%B9%8C">자바스크립트 싱글스레드인데 왜 비동기적 일까?</a></p>
</blockquote>
<p>자바스크립트 관련 수업을 들었을 때 자바스크립트의 장점으로 Web API와 호환이 된다는 내용을 본 적이 있다. 아마 이 부분에 대한 설명이 아니었을까싶다.</p>
<h3 id="💎settimeout">💎setTimeout</h3>
<p>다음의 예시코드를 봐보자.</p>
<pre><code class="language-JavaScript">const testA = () =&gt; {
    console.log(&quot;testA&quot;)
}

const testB = () =&gt; {
    console.log(&quot;testB&quot;)
}

setTimeout(testB, 100);
testA();

&lt;!-- console 창 결과 --&gt;
testA
testB
</code></pre>
<p>위의 코드를 실행시키면 testA가 먼저 출력된다. 만약 동기 작업이였다면 setTimeout의 결과가 나올 때까지 모든 작업을 멈추고 결과가 나온 뒤에 넘어갔을 것이다. 그러나 setTimeout은 JS엔진에서 작동하는게 아닌 Web API해서 작동된다. 따라서 결과는 비동기처리처럼 나온다.
<img src="https://velog.velcdn.com/images/h22chan_dev/post/4539bd7a-e259-43ee-965f-d44a2f3e0eaf/image.png" alt=""></p>
<br>

<h3 id="💎testa가-100ms보다-오래걸리면">💎testA()가 100ms보다 오래걸리면?</h3>
<p>만약 testA가 setTimeout(testB, 100)보다 오래걸린다면, testB가 먼저 출력될 것이라고 생각할 수있지만 그렇지 않다. setTimeout는 작업이 종료되면 자바스크립트의 Call Stack으로 바로 들어가는게 아니라, Task Queue에 저장되고 Call Stack가 비워지면 Stack으로 들어가 실행된다.</p>
<blockquote>
<p>즉, 빠른 작업을 위해 다른 엔진을 사용해 비동기처리가 가능할 뿐이지 비동기처리가 된다고 즉시 반영이 되는 것이 아니라 Call Stack에 순차적으로 저장되고 실행된다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[React JSX에 깊게 파헤치기]]></title>
            <link>https://velog.io/@h22chan_dev/React-JSX</link>
            <guid>https://velog.io/@h22chan_dev/React-JSX</guid>
            <pubDate>Sun, 06 Oct 2024 16:40:11 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 모던 리액트 Deep Dive를 기반으로 작성되었습니다.</p>
</blockquote>
<h1 id="jsx란-무엇인가">JSX란 무엇인가?</h1>
<p>JSX는 페이스북에서 독자적으로 개발한 구문으로 흔히들 리액트에서 사용하는데 이는 리액트의 전유물이 아닌 XML과 유사한 내장형 구문으로, 리액트에 종속적이지 않은 독자적인 문법으로 보는것이 옳다.</p>
<p>페이스북에서 독자적으로 개발했기에 JSX는 ECMAScript로 보기는 어렵다. 따라서,다음과 같이 JSX를 포함한 코드를 실행시키면 에러가 나온다. JSX는 반드시 트랜스파일러를 거쳐 자바스크립트 코드로 변환되어야한다.</p>
<pre><code>&lt;!-- JSX가 포함된 코드--&gt;
const Component = (
    &lt;div className=&quot;hello&quot;&gt;
        &lt;input type=&quot;text&quot; value=&quot;hello&quot;&gt;
    &lt;/div&gt;
)</code></pre><hr>
<h2 id="📌jsx의-정의">📌JSX의 정의</h2>
<p>JSX는 <code>JSXElement</code>, <code>JSXAttributes</code>, <code>JSXChildren</code>, <code>JSXStrings</code>로 구성되어있다. 이상한 영어로 되어있지만, HTML 구조와 비슷하다.
<br></p>
<h4 id="💎jsxelement">💎JSXElement</h4>
<p>Element를 구성하는 방법은 대표적으로 아래와 같다.
자식요소가 없는데 Self-Closing을 하지않으면 ESlint에 잡힌다.</p>
<pre><code>&lt;!-- 자식 요소를 가질 때 --&gt;
&lt;JSXElement&gt;Child&lt;/JSXElement&gt;

&lt;!-- 자식 요소가 없을 때 : Self-Closing --&gt;
&lt;JSXElement/&gt;</code></pre><br>


<h3 id="💎jsxelement--name">💎JSXElement : Name</h3>
<p>1) 요소의 이름은 HTML 태그명과 구분짓기 위해 첫 글자는 <code>무조건 대문자</code>로 시작한다.
2) 이름을 지을 수 있는 규칙은 <code>자바스크립트 식별자 규칙과 동일</code>하다.</p>
<pre><code>&lt;!-- 가능 --&gt;
function Valid1() {
    return &lt;$&gt;&lt;/$&gt;
}

function Valid2() {
    return &lt;_&gt;&lt;/_&gt;
}

&lt;!-- 불가능 --&gt;
function InValid() {
    return &lt;1&gt;&lt;/1&gt;
}</code></pre><pre><code>&lt;!-- :를 통해서도 가능 대신, 한 번만 가능 --&gt;
function Valid() {
    return &lt;foo:bar&gt;&lt;/foo:bar&gt;
}

&lt;!-- 불가능 --&gt;
function InValid() {
    return &lt;foo:bar:baz&gt;&lt;/foo:bar:baz&gt;
}
</code></pre><pre><code>&lt;!-- .를 통해서도 가능 대신, :와 함꼐 사용 안됨 --&gt;
function Valid1() {
    return &lt;foo.bar&gt;&lt;/foo.bar&gt;
}

function Valid2() {
    return &lt;foo.bar.baz&gt;&lt;/foo.bar.baz&gt;
}

&lt;!-- 불가능 --&gt;
function InValid() {
    return &lt;foo.bar:baz&gt;&lt;/foo.bar:baz&gt;
}
</code></pre><br>

<h3 id="💎jsxattributes">💎JSXAttributes</h3>
<p>속성을 의미하며, 필수 값이 아니며 <code>자바스크립트의 표현식</code>이 들어갈 수 있다.</p>
<pre><code>&lt;Child attribute={&lt;div&gt;hello&lt;/div&gt;}/&gt; &lt;!-- Self-Closing --&gt;</code></pre><br>

<h3 id="💎jsxchildren">💎JSXChildren</h3>
<p>JSXElement의 자식 값을 나타낸다. 다른 JSX의 요소가 들어가거나 <code>자바스크립트의 표현식</code>이 들어갈 수 있다.</p>
<pre><code>export default function SampleComponent() {
  return &lt;&gt;{&#39;{} &lt;&gt;&#39;}&lt;/&gt;
}</code></pre><br>

<h3 id="💎jsxstrings">💎JSXStrings</h3>
<p>HTML에서 사용 가능한 문자열은 모두 JSXStrings에서도 사용 가능하다. 자바스크립트와의 차이점은 <code>\</code>의 경우 자바스크립트에서는 특수 문자를 위해 사용되기에 <code>\\</code>로 사용하여야 한다는 것</p>
<pre><code>export default function SampleComponent() {
  return &lt;&gt;{&#39;{} &lt;&gt;&#39;}&lt;/&gt;
}</code></pre><br>

<hr>
<h2 id="📌jsx는-어떻게-변환될까">📌JSX는 어떻게 변환될까?</h2>
<p>@babel/plugin-transform-react-jsx 플러그인을 통해 변환된다. </p>
<pre><code class="language-JavaScript">const ComponentA = &lt;A required={true}&gt;Hello World&lt;/A&gt;
const ComponentB = &lt;&gt;Hello World&gt;&lt;/&gt;
const ComponentC = (
    &lt;div&gt;
        &lt;span&gt;Hello World&lt;/span&gt;
    &lt;/span&gt;
)

.
.
.

&lt;!-- 변환 --&gt;
var ComponentA = React.createElement(
    A,
    {
        required: true,
    },
    &#39;Hello World&#39;,
)

var ComponentB = React.createElement(React.Fragment, null, &#39;Hello World&#39;)

var ComponentC = React.createElement(
  &#39;div&#39;,
  null,
  React.createElement(&#39;span&#39;, null,&#39;Hello World&#39;),
)</code></pre>
<br>

<h3 id="💎변환할-때-특징">💎변환할 때 특징</h3>
<p>1) JSXElement를 첫 번째 인수로 선언하여 요소를 정의함
2) 옵셔널인 JSXChildren, JSXAttributes, JSXStrings는 이후 인수로 넘김</p>
<pre><code class="language-JavaScript">&lt;!-- 코드 중복이 일어남 --&gt;
function TextOrHeading({
  isHeading,
  children,
}: PropsWithchildrend&lt;{ isHeading: boolean }&gt;) {

  return isHeading ? (
      &lt;h1 className=&quot;text&quot;&gt;{children}&lt;h1&gt;
  ) : (
    &lt;span className=&quot;text&quot;&gt;{children}&lt;span&gt;
  )

}

.
.
.

&lt;!-- 중복을 최소화하여 리팩토링 --&gt;
function TextOrHeading({
  isHeading,
  children,
}: PropsWithchildrend&lt;{ isHeading: boolean }&gt;) {

  return createElement(
    isHeading ? &#39;h1&#39; : &#39;span&#39;,
    { className: &#39;text&#39;},
    children,
  )

}</code></pre>
<p>위와 같은 코드처럼 JSX파일이 어떻게 변환되는지 알아둔다면 도움이 될 수 있다.
때에 따라서는 직접 createElment를 사용하여 컴포넌트를 구성하는게 더 효율적일 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TailwindCSS 반영 안될 때]]></title>
            <link>https://velog.io/@h22chan_dev/TailwindCSS-%EB%B0%98%EC%98%81-%EC%95%88%EB%90%A0-%EB%95%8C</link>
            <guid>https://velog.io/@h22chan_dev/TailwindCSS-%EB%B0%98%EC%98%81-%EC%95%88%EB%90%A0-%EB%95%8C</guid>
            <pubDate>Tue, 01 Oct 2024 11:31:33 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<ol>
<li>커스텀 스타일링을 위해 tailwind.config.js를 수정해도 변함이 없을 때</li>
<li>환경은 모듈을 설치한 환경에서 작동 CDN 사용 X</li>
</ol>
</blockquote>
<hr>

<h2 id="해결방법">해결방법</h2>
<p>터미널을 통해 아래 코드 입력하면 된다. 주의사항은 본인의 파일 디렉토리에 맞게 경로를 수정해야 함. </p>
<pre><code>npx tailwindcss -i ./global.css -o ./dist/output.css --watch</code></pre><p>해당 프로젝트는 tailwind.config.js와 global.css의 경로가 같은 위치에 있고 최종 output.css는 /dist 폴더 하위에 존재했다. </p>
<h3 id="과정">과정</h3>
<p>tailwind는 CSS-in-JS이기 때문에 변경사항이 CSS로 빌드되어야 한다.</p>
<blockquote>
<p><strong><em>npx tailwindcss</em></strong></p>
</blockquote>
<p> tailwindCSS를 실행하는 명령어</p>
<br>

<blockquote>
<p><strong><em>-i ./global.css</em></strong> </p>
</blockquote>
<p>-i는 입력 파일을 지정한다. global.css에서 @tailwind의 지시어를 읽고 설정파일인 tailwind.config.js에서 정의된 css를 생성한다.</p>
<br>

<blockquote>
<p><strong><em>-o ./dist/output.css --watch</em></strong> </p>
</blockquote>
<p>-o는 출력 파일 경로를 지정한다. tailwind에서 빌드된 css를 해당 경로로 저장한다.</p>
<p>--watch는 파일 변경을 감지하고 자동으로 다시 빌드한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TailwindCSS를 써본 후]]></title>
            <link>https://velog.io/@h22chan_dev/TailwindCSS%EB%A5%BC-%EC%8D%A8%EB%B3%B8-%ED%9B%84</link>
            <guid>https://velog.io/@h22chan_dev/TailwindCSS%EB%A5%BC-%EC%8D%A8%EB%B3%B8-%ED%9B%84</guid>
            <pubDate>Sun, 29 Sep 2024 17:28:53 GMT</pubDate>
            <description><![CDATA[<p>저는 기본적인 CSS나 Styled-components를 사용하는데 적응되어있는 사람입니다. 그러나, 모종의 이유로 TailwindCSS를 써봐야했고 이 글은 그에 대한 후기입니다.</p>
<p>TailwindCSS 프론트 스터디할 때 스터디원 중 1명이 하는걸 봤었습니다. 물어보니 미리 정의된 클래스 컴포넌트를 사용하는 것이라고하며 매우 직관적이라고 했어요. 실제로 보니까 진짜 직관적이긴 하더라구요.</p>
<hr>

<h2 id="tailwindcss-장단점">TailwindCSS 장단점</h2>
<p><strong>장점</strong>은 직관적이고 파일이 하나에서 관리된다는 점이며
<strong>단점</strong>으로는 HTML파일이 조금 가독성이 떨어진다는 점이었습니다.</p>
<p>사용 예제는 아래 이미지와 같아요.
<img src="https://velog.velcdn.com/images/h22chan_dev/post/1e403c01-c911-435a-9485-8f97ff46a165/image.png" style="margin:4px 0px;"></p>
<p>이미지처럼 클래스 안에다가 미리 정의되어있는 클래스들을 입력하는게 전부입니다.</p>
<hr>

<h2 id="tailwindcss-써보고-느낀-점">TailwindCSS 써보고 느낀 점</h2>
<h3 style="color:#FFA500;">첫 번째는 외워야합니다.</h3>
물론 CSS에 관한 지식을 가지고있다면 클래스 정의도 그에 맞춰서 직관적으로 해놨기에 금방외웁니다. 하지만, 많은 양의 CSS CLASS를 또 외워야한다는 부분에서 초반에는 공식문서를 좀 많이 봐야합니다.
<br>

<h3 style="color:#FFA500;">두 번째는 단위문제입니다.</h3>
저는 여기서 "아 쓰기 힘들다"라고 느꼈습니다. 그 이유는 TailwindCSS에서 제공하는 단위는 rem단위로 보통 디자이너가 작업하는 피그마에서는 px을 제공합니다.

<p>저는 항상 제가 디자인을 했기때문에 px에 많이 익숙한 편인데 단위가 rem으로 나와버리니 어떻게 해야 할 지에 대해서 애먹었습니다.</p>
<p><img src="https://velog.velcdn.com/images/h22chan_dev/post/c4a2a82a-0274-4ac4-aaa4-7d6d24a902ea/image.png" style="margin:4px 0px;"></img>
그래서 그냥 제가 디자인하면서 기본적으로 잡았던 시스템들을 재정의해서 사용했습니다.</p>
<p>문제는, 이게 괜찮으면 좋은데 이렇게 쓰는게 아닐까봐 이를 검증할 방법이 없었습니다. 실무에서 어떤 단위를 쓰는지..</p>
<h2 id="그래서">그래서?</h2>
<p>글을 작성하면서 느낀 것이지만, 반응형을 생각해 봤을 때 rem단위를 쓰는게 맞는 것 같더라구요.</p>
<p>단위에 대해서 조금 더 깊게 공부를 해봐야할 것 같네요. 우선 디자인 시안도 rem 변환이 편하도록 고려해서 해야겠습니다.</p>
<p>해상도 이슈로 인해 px단위를 2 혹은 4배수로 하라고 배웠었는데 단위 변환 문제에서도 2의 배수가 아니면 조금 복잡해질 것 같다는 생각이네요.</p>
<p>rem은 우리가 왜 2의 배수로 단위를 작성해야하는지에 대한 근거를 보충해주는 것 같습니다.</p>
<p><em>*<em>가장 큰 느낀점은 사용하려면 편하기야 하겠지만 굳이..? 싶은 느낌이 아직 듭니다. 더 공부해보고 사용하면서 이유를 찾아봐야겠네요 :)
*</em></em></p>
]]></description>
        </item>
    </channel>
</rss>