<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>55555-jyeon.log</title>
        <link>https://velog.io/</link>
        <description>🥞 Stack of Thoughts</description>
        <lastBuildDate>Sun, 08 Sep 2024 04:42:17 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>55555-jyeon.log</title>
            <url>https://velog.velcdn.com/images/55555-jyeon/profile/cba6b038-f6eb-4bb8-8aa2-84f7690bf1b6/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 55555-jyeon.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/55555-jyeon" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[움직이는 소수점에 대해서 알아?]]></title>
            <link>https://velog.io/@55555-jyeon/floating-point</link>
            <guid>https://velog.io/@55555-jyeon/floating-point</guid>
            <pubDate>Sun, 08 Sep 2024 04:42:17 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h6 id="부동소수점에-대해-글을-쓰는-이유">부동소수점에 대해 글을 쓰는 이유</h6>
<p>최근 면접을 보게 되었는데, 부동소수점으로 인한 오류에 대해 알고 있는지 질문을 받게 되었습니다. 오류가 발생한다는 사실만 기억이 나고 이유가 전혀 기억이 안 나더라구요. 그래서 다시 한 번 정리를 할 겸, 궁금하기도 해서 겸사 겸사 글로 남겨 봅니다 :)</p>
</blockquote>
<br />


<h2 id="움직이는-소수점">움직이는 소수점?</h2>
<p>프로그래밍 언어에서는 소수가 있는 수를 표현하기 위해 부동소수점이라는 것을 사용합니다.
여기서 부동은 뜰 부(浮), 움직일 동(動)을 사용해 &quot;떠서 움직이는&quot; 이라는 의미를 갖고 있어요. 영어로는 <strong>floating point</strong>라고도 합니다.</p>
<p>소수점이 움직이기 때문에 어떤 오류가 발생한다는 사실을 알고 계신가요?</p>
<br />

<h5 id="🤔-어-무슨-오류가-발생하는데">🤔 어? 무슨 오류가 발생하는데...?</h5>
<h2 id="01--02--">0.1 + 0.2 = ?</h2>
<p>위의 식을 프로그래밍 언어로 출력하면 어떤 결과값이 나올 것 같나요?</p>
<p>0.3이라고 생각하셨나요?
음... 컴퓨터는 다르게 생각할 것 같습니다.</p>
<p>엥, 무슨 소리냐고요?</p>
<p>프로그래밍 언어로 <code>0.1+0.2</code>가 <code>0.3</code>인지 확인해보면 <code>false</code>라고 출력하기 때문입니다.</p>
<pre><code class="language-js">// javascript

console.log(0.1) // 0.1
console.log(0.2) // 0.2
console.log(0.1 + 0.2 === 0.3) // false</code></pre>
<br />

<h2 id="뭐야-왜-이래">뭐야, 왜 이래?</h2>
<p>이건 비단 자바스크립트만의 문제는 아닙니다.
어떤 언어로 작성하든 프로그래밍 언어라면 모두 false가 찍히게 되거든요.</p>
<pre><code class="language-js">// java

public class App {
    System.out.println(0.1 + 0.2 === 0.3) // false
}</code></pre>
<pre><code class="language-js">// python

print(0.1 + 0.2 === 0.3) // false</code></pre>
<h5 id="🤯-프로그래밍-언어가-이래도-돼">🤯 프로그래밍 언어가 이래도 돼?</h5>
<h3 id="01--02--03">0.1 + 0.2 !== 0.3</h3>
<p>0.1과 0.2를 더한 값이 0.3이 아닌 이유는 0.1과 0.2가 0.1, 0.2가 아니기 때문입니다.</p>
<pre><code class="language-js">console.log(0.3) // 0.3
console.log(0.1 + 0.2) // 0.300..04</code></pre>
<p>콘솔에 각각 찍어보면 0.1과 0.2를 더한 값이 0.3보다 조금 큰 것을 확인할 수 있습니다. 
여기서 발생한 0.000...4가 부동소수점 때문에 생기는 오차입니다.</p>
<p>이 오차 때문에 <code>0.1+0.2 === 0.3</code>이 <code>false</code>로 나오게 됩니다.</p>
<br />

<p>프로그래밍 언어에서는 소수가 있는 수를 표현하기 위해 움직이는 소수점을 사용합니다.
즉, <strong>소수점이 움직이기 때문에 오차가 발생</strong>한다는 거죠.</p>
<br />


<h2 id="왜-떠다니는-건데">왜 떠다니는 건데?</h2>
<p>소수점이 움직이기 때문에 오류가 발생한다면 그냥 고정시키면 안 되는 걸까요?
왜 굳이 오류를 발생시키게 소수점을 움직이게 하는 걸까요?</p>
<br />


<p><strong>컴퓨터는 메모리를 가장 효율적으로 활용할 수 있는 방법으로 데이터를 저장</strong>합니다.
즉, 부동소수점이 메모리를 효율적으로 관리할 수 있는데 가장 효과적이라는 의미가 되겠죠? 
왜 부동소수점을 사용하는 것이 오차가 있음에도 가장 효율적인지 알아보기 위해 먼저 프로그래밍 언어에서 자주 사용되는 숫자와 관련된 자료형에 대해서 간단히 알아보겠습니다.</p>
<br />

<h3 id="정수를-위한-integerint">정수를 위한 integer(int)</h3>
<p>자바스크립트에는 없지만, 자바와 파이썬, c# 등에서 사용하는 int는 소수점이 없는 정수 데이터를 저장하는데 사용되는 자료형입니다.</p>
<p>int는 32개의 비트를 사용해 정수를 표현합니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/3bd8620a-863b-474f-b553-c64966af82cc/image.svg" alt=""></p>
<p>그 중 첫 번째 자리에는 정수와 음수를 구분짓는 부호가 들어가게 됩니다.
0이 들어가면 양수, 1이 들어가면 음수가 됩니다.
그리고 나머지 31개의 비트로 절대값을 표현합니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/888ffdaa-7e90-4457-b055-d107eb5ee222/image.svg" alt=""></p>
<p>양수는 0부터 2,147,483,647까지 나타낼 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/e656ba3a-2bcb-4cfe-902d-da6d56f8b330/image.svg" alt=""></p>
<p>음수로는 -1부터 -2,147,483,648까지 나타낼 수 있죠.</p>
<br />


<p>따라서 int 자료형으로 표현 가능한 정수의 범위는 -2,147,483,648부터 2,147,483,647입니다.</p>
<br />

<h6 id="엄밀히-말하면-수학적-개념의-실수는-아니지만-아무튼">엄밀히 말하면 수학적 개념의 실수는 아니지만 아무튼</h6>
<h3 id="실수를-위한-number와-float">실수를 위한 number와 float</h3>
<p>자바와 파이썬에서 사용하는 float와 자바스크립트에서 사용하는 number 자료형으로는 실수를 표현하는데 사용되며 부동소수점(floating-point) 자료형이라고도 합니다.</p>
<br />

<p>125.925와 같은 실수를 아래와 같이 32비트로 표현하고자 한다고 가정해봅시다.
정수부와 소수부를 어떻게 나눌 수 있을까요?</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/3bd8620a-863b-474f-b553-c64966af82cc/image.svg" alt=""></p>
<h4 id="고정소수점">고정소수점</h4>
<p>이때 int와 마찬가지로 양수와 음수를 구분하는 첫 번째 자리를 제외한 나머지 31개의 비트를 대략 반으로 나눠 15비트는 정수부를, 16비트는 소수부를 표현하는데 사용하는 것을 고정소수점이라고 합니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/908ce901-b5a4-4c80-a01a-af26cc5feac7/image.svg" alt=""></p>
<p>고정소수점은 소수점의 위치가 고정된 형태로, 메모리 내에서 소수 부분과 정수 부분이 명확히 구분되어 있습니다. 이 방식은 정확도를 유지할 수 있지만, 표현할 수 있는 수의 범위가 제한적이라는 큰 단점이 있습니다.</p>
<p>소수점의 위치를 고정해버리면 위치가 어디든 수의 범위가 제한적일 수 밖에 없기 때문에 컴퓨터는 부동소수점을 사용하는 것입니다.</p>
<br />

<h4 id="부동소수점">부동소수점</h4>
<h6 id="부동소수점-이름의-의미">부동소수점, 이름의 의미</h6>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/8d56d68c-b111-4f1b-8d32-258a51f73f10/image.png" alt=""></p>
<p>마찬가지로 첫 번째 자리를 양수와 음수를 나누는데 사용합니다.
그리고 부동소수점은 이진수 숫자를 항상<code>1.xxxxx</code> 형식으로 변환하기 때문에 이진수로 변환한 값에서 소수점이 몇 칸 이동해야 될지를 다음 8비트로 나타냅니다.
나머지 23비트엔 소수점이 움직인 결과에서 소수점 뒤로 오는 부분들을 채워넣습니다.</p>
<p>이진수를 특정 형식으로 변환하는 과정을 정규화라고 하는데, 이 과정 때문에 부동소수점이라는 이름이 붙었습니다.</p>
<br />
<hr />

<h5 id="예시로-더-자세히-👀">예시로 더 자세히 👀</h5>
<p>예를 들어, 십진수 <code>9.625</code>를 컴퓨터가 저장한다고 가정해보겠습니다.</p>
<h6 id="①-10진수를-2진수로-변환">① 10진수를 2진수로 변환</h6>
<p>먼저 10진수를 2진수로 변환할 때에는 정수부와 소수부를 나눠 변환합니다.
정수부는 몫이 0이 될 때까지 2로 나누고, 소수부는 소수부가 0이 될 때까 2를 곱합니다.</p>
<p>위 예시에서 <code>9.625</code>를 2진수로 변환하면 정수부인 9는 <code>1001</code>, 소수부 <code>0.625</code>는 <code>0.101</code>이 됩니다.
따라서 <code>9.625</code>는 <code>1001.101</code>이 됩니다.</p>
<h6 id="②-정규화normalization">② 정규화(normalization)</h6>
<p>부동소수점은 항상 <code>1.xxxxx</code> 형식으로 숫자를 표현합니다.</p>
<p>따라서 위에서 변환된 이진수<code>1001.101</code>을 <code>1.001101</code>로 변환합니다.</p>
<h6 id="③-지수exponent를-구하기">③ 지수(exponent)를 구하기</h6>
<p>지수는 정규화 과정에서 소수점이 몇 칸 이동했는지를 나타내는 부분입니다.</p>
<p>소수점을 세 칸 왼쪽으로 이동했으므로, 지수는 3입니다. 
그러나 <a href="https://ko.wikipedia.org/wiki/IEEE_754">IEEE 754</a> 형식에서는 바이어스(bias)를 더해 지수를 저장합니다.</p>
<p>32비트 부동소수점의 바이어스는 127입니다.
따라서, 실제 지수는 3 + 127 = 130이 됩니다.</p>
<p>130을 이진수로 표현하면 <code>10000010</code>입니다.</p>
<blockquote>
<h5 id="💡-ieee-754">💡 IEEE 754</h5>
<p>IEEE 754는 컴퓨터에서 부동소수점(floating-point) 수를 표현하고 연산하는 표준을 정의한 규격입니다. 
이 표준은 부동소수점을 일관성 있고 효율적으로 처리하기 위해 제정되었으며, 대부분의 프로그래밍 언어와 하드웨어에서 사용됩니다.</p>
</blockquote>
<blockquote>
<h5 id="💡-바이어스가-왜-127인가요">💡 바이어스가 왜 127인가요?</h5>
<p>바이어스(bias)는 지수를 저장할 때 기준이 되는 값입니다. 
지수에 바이어스를 더해 양의 정수 형태로 저장되며 바이어스는 지수부의 비트 수에 따라 결정됩니다. <br /></p>
</blockquote>
<ul>
<li>단정밀도(32비트) : 지수부가 8비트, 바이어스 값은 127 ($2^{7} - 1 = 127$)</li>
<li>배정밀도(64비트) : 지수부가 11비트,바이어스 값은 1023 ($2^{10} - 1 = 1023$)</li>
</ul>
<h6 id="④-가수significand-mantissa">④ 가수(significand, mantissa)</h6>
<p>정규화 과정에서 변환된 <code>1.001101</code>에서 소수점 뒤의 숫자들(001101)이 가수 부분이 됩니다. 
가수는 23비트로 표현되며, 남는 부분은 0으로 채워집니다.</p>
<p>즉, 위의 예시의 경우 <code>00110100000000000000000</code>이 가수 부분이 됩니다.</p>
<h6 id="⑤-부호sign">⑤ 부호(sign)</h6>
<p>부호는 위에서도 설명한대로 양수면 0, 음수면 1이 표시됩니다.</p>
<p>예시의 숫자는 양수이므로 부호 비트는 <code>0</code>입니다.</p>
<h6 id="⑥-최종-부동소수점-표현">⑥ 최종 부동소수점 표현</h6>
<p>부호 비트(1비트) + 지수(8비트) + 가수(23비트)를 결합해 32비트 부동소수점으로 표현한 값이 완성됩니다.</p>
<p>예를 들어, 위 <code>9.625</code>의 경우는 아래와 같습니다 :</p>
<pre><code class="language-js">0 | 10000010 | 00110100000000000000000</code></pre>
<hr />
<br />

<p>부동소수점은 소수점의 위치가 고정되지 않기 때문에 고정소수점보다 더 넓은 수의 범위를 표현할 수 있습니다. 특히, 자바스크립트에서 숫자는 모두 부동소수점으로 처리됩니다.
하지만 이로 인해 위에서 대략적으로 알아본 것 같이 오차가 발생할 수 있죠. 
오차 발생으로 인한 오류는 부동소수점 계산의 대표적인 한계라고 볼 수 있습니다.</p>
<br />

<h2 id="오류가-왜-생기는-건데">오류가 왜 생기는 건데?</h2>
<p>오류는 2진수로 소수를 표현할 때 발생합니다. 
십진수에서는 0.1 같은 값이 익숙하지만, 이진수에서는 이 값이 정확히 표현되지 않기 때문에 컴퓨터는 근사치로 계산하게 됩니다. </p>
<p>숫자라는 추상적인 개념을 표현하기 위해 사람은 십진수를, 컴퓨터는 이진수를 사용합니다. 
그리고 이 간극에서 발생하는 차이로 인해 오류가 발생하게 됩니다.</p>
<br />

<h4 id="decimal-십진소수점수">Decimal, 십진소수점수</h4>
<p>십진수는 소수점을 기준으로 위의 수는 10을 곱한, 아래 수들을 10으로 나눈 개념입니다.
0.1을 10개 가져다 놓으면 1.0이 되죠.
이렇게 사람은 자연스럽게 소수점 아래 부분도 십진법으로 계산하고 있습니다.</p>
<p>유한십진소수점수는 10으로 나누다보면 언젠가 나누어 떨어지는 지점이 존재합니다.
반대로 무한십진소수점수는 아무리 10으로 나누어도 근사값에 접근할 뿐 나누어 떨어지지 않습니다.</p>
<p>예를 들어, 1/3을 십진수로 나타내면 무한십진소수점수가 됩니다.</p>
<h4 id="binary-이진소수점수">Binary, 이진소수점수</h4>
<p>반대로 컴퓨터는 이진소수점수로 숫자를 표현합니다.
2를 기준으로 설명하기 때문에 위와 같은 예를 이어가자면 0.1을 2개 가져다 놓으면 1.0이 되는 겁니다.</p>
<p>따라서 이진소수점수 0.1은 십진소수점수의 0.5와 같습니다.</p>
<blockquote>
<p>❗️ 수학적인 개념으로 접근하지 말아주세요</p>
</blockquote>
<p>이진소수점수도 십진소수점수와 마찬가지로 유한소수점수와 무한소수점수가 존재합니다.
유한이진소수점수는 2로 나누다보면 언젠가 나누어 떨어지는 지점이 존재하고 이진무한소수점수는 2로 나누어 떨어지는 지점이 존재하지 않습니다.</p>
<p>대표적인 무한이진소수점수는 맨 처음 예시로도 등장했던 0.1입니다.</p>
<br />

<p>컴퓨터는 유한한 메모리로 인해 무한이진소수점수를 저장할 수 없습니다. 
그래서 위에서 알아본 것처럼 32비트의 저장공간 안에 이 무한한 수를 욱여넣습니다.</p>
<p>우겨넣는 과정에서 32비트 이하 자리수는 반올림 후 버리게 됩니다.
여기서 버려지고 반올림되는 과정에서 숫자 계산에서 미세한 오차가 생기게 되고 위와 같이 0.1과 0.2를 더한 값이 0.3이 아니라는 결과를 반환합니다. </p>
<p>0.1과 0.2를 더한 값과 0.3의 차이는 굉장히 미세하지만 이런 미세한 오차들이 누적되면 큰 차이가 발생하게 됩니다.
이진수로 정확히 표현할 수 없는 수들은 근사치로 밖에 표현이 안 되기 때문에 <strong>근차시 연산의 오류</strong>가 발생하게 되는 것입니다.</p>
<br />



<h2 id="그럼-왜-이렇게까지-하는-건데">그럼 왜 이렇게까지 하는 건데?</h2>
<p>오차 발생이라는 한계가 있음에도 왜 컴퓨터는 부동소수점을 사용할까요?</p>
<p>위에서도 언급했지만 컴퓨터는 메모리를 가장 효율적으로 활용할 수 있는 방법으로 데이터를 저장합니다. 한정된 메모리 공간에서 좀 더 넓은 범위의 소수를 표현하기 위해 부동소수점을 사용합니다.</p>
<h4 id="그냥-정수로-하지-왜">그냥 정수로 하지, 왜?</h4>
<p>기본적으로 컴퓨터의 소수점수(floating-point)는 아주 큰 수나 아주 작은 수를 <strong>효율적인 리소스를 토대로 연산하기 위해서</strong> 지원되기 시작했습니다.</p>
<p>CPU는 연산을 할 때 ALU(Arithmetic Logic Unit)에서 처리합니다.
하지만 소수점수는 ALU에 포함되어 있는 FPU(Floating Point Unit)에서 처리하게 됩니다.</p>
<p>십진연산은 하드웨어적인 측면에서 봤을 때에도 비효율적이며 소프트웨어로도 가능하기 때문에 컴퓨터는 이진연산을 합니다.</p>
<p>그래서 항상 소수점수에는 정밀도 문제가 꼬리표처럼 따라다닐 수 밖에 없고, 컴퓨터는 소수점수의 값을 대부분 근사치로 계산해 표현합니다.</p>
<br />

<h2 id="그럼-어떻게-해결해">그럼 어떻게 해결해?</h2>
<p>부동소수점 오류는 몇 가지 방법으로 해결하거나 최소화할 수 있습니다. 
아래에서 가장 자주 사용되는 몇 가지 해결책을 정리해보겠습니다.</p>
<br />

<h4 id="1️⃣-반올림하여-처리하기">1️⃣ 반올림하여 처리하기</h4>
<p>프로그래밍 언어에서 제공하는 반올림 함수로 부동소수점 연산의 미세한 오차를 줄일 수 있습니다. 
자바스크립트에서는 <code>toFixed()</code> 또는 <code>Math.round()</code> 같은 함수를 이용할 수 있습니다.</p>
<pre><code class="language-js">// javascript example
console.log((0.1 + 0.2).toFixed(1)); // 0.3
console.log(Math.round(0.1 + 0.2)); // 0</code></pre>
<p>위와 같이 원하는 자릿수에서 반올림함으로써 오차를 줄일 수 있습니다. 
하지만, 이 방법은 근본적으로 오류를 없애는 게 아니라 <strong>오차를 무시</strong>하는 것이기 때문에 아주 큰 수나 작은 수에서는 문제가 될 수 있습니다.</p>
<br />

<h4 id="2️⃣-정수로-변환하여-처리하기">2️⃣ 정수로 변환하여 처리하기</h4>
<p>소수점 연산에서 발생하는 오차를 피하기 위해, 정수 단위로 변환 후 연산을 하고 나중에 다시 소수점으로 되돌리는 방법도 많이 사용됩니다. 
이 방법은 특히 금융 분야에서 자주 사용되며, <strong>정밀도가 중요한 계산에 적합</strong>합니다.</p>
<pre><code class="language-js">// javascript example: 금액 계산
let price1 = 100; // 1.00 달러를 센트로 표현
let price2 = 200; // 2.00 달러를 센트로 표현
let total = price1 + price2; // 300 센트
console.log(total / 100); // 3.00 달러</code></pre>
<p>예를 들어, 금액 계산 같은 경우 소수점을 피하기 위해 센트 단위로 변환한 후 계산할 수 있습니다.</p>
<br />

<h4 id="3️⃣-numberepsilon-사용하여-비교하기">3️⃣ <code>Number.EPSILON</code> 사용하여 비교하기</h4>
<p>자바스크립트에서는 부동소수점의 오차를 고려하여 두 숫자가 거의 같은지를 판단할 수 있는 허용 오차를 지정해 비교하는 방법이 있습니다. 
<code>Number.EPSILON</code>은 부동소수점 비교 시 <strong>아주 작은 차이를 무시</strong>할 수 있도록 도와줍니다.</p>
<pre><code class="language-js">// 자바스크립트 예시: Number.EPSILON을 이용한 비교
function areEqual(a, b) {
  return Math.abs(a - b) &lt; Number.EPSILON;
}

console.log(areEqual(0.1 + 0.2, 0.3)); // true</code></pre>
<br />

<h4 id="4️⃣-고정소수점-라이브러리-사용하기">4️⃣ 고정소수점 라이브러리 사용하기</h4>
<p>부동소수점의 오차 문제를 근본적으로 해결하기 위해 고정소수점 연산을 지원하는 라이브러리를 사용할 수 있습니다. </p>
<p>예를 들어, 자바에서는 BigDecimal 클래스를 사용해 더 정확한 실수 연산을 할 수 있습니다.</p>
<p>이 방법은 정밀한 계산이 중요한 금융 및 과학 분야에서 많이 사용되며, 부동소수점 연산의 오류를 완전히 없앨 수 있습니다.</p>
<br />

<h6 id="자바스크립트에서-사용-가능한-라이브러리">자바스크립트에서 사용 가능한 라이브러리</h6>
<h5 id="①-bigjs">① Big.js</h5>
<p>작은 크기와 빠른 속도를 자랑하는 고정소수점 연산 라이브러리입니다. 
부동소수점 연산에서 발생하는 오류 없이 정확한 실수 연산을 수행할 수 있습니다.</p>
<pre><code class="language-js">import Big from &#39;big.js&#39;;

let a = new Big(0.1);
let b = new Big(0.2);

console.log(a.plus(b).toString()); // 0.3</code></pre>
<h5 id="②-decimaljs">② Decimal.js</h5>
<p>자바스크립트에서 <strong>매우 높은 정밀도</strong>로 소수점 연산을 수행할 수 있는 라이브러리입니다. 
수백 자리의 정밀도를 제공하며, <strong>부동소수점의 오차 문제를 완전히 해결</strong>할 수 있습니다.</p>
<pre><code class="language-js">import Decimal from &#39;decimal.js&#39;;

let a = new Decimal(0.1);
let b = new Decimal(0.2);

console.log(a.plus(b).toString()); // 0.3</code></pre>
<h5 id="③-bignumberjs">③ BigNumber.js</h5>
<p>수천 자리 이상의 정밀도를 지원하며, 부동소수점 연산에서 정확성을 보장하는 라이브러리입니다. 
암호화폐 계산이나 금융 계산과 같이 높은 정밀도가 요구되는 경우에 적합합니다.</p>
<pre><code class="language-js">import BigNumber from &#39;bignumber.js&#39;;

let a = new BigNumber(0.1);
let b = new BigNumber(0.2);

console.log(a.plus(b).toString()); // 0.3</code></pre>
<h5 id="④-mathjs">④ math.js</h5>
<p>수학 계산을 위한 강력한 라이브러리로, 고정소수점 연산, 행렬 계산, 통계 등 다양한 수학적 기능을 제공합니다. 
고정소수점 연산에서도 사용 가능하며, 복잡한 계산에 적합합니다.</p>
<pre><code class="language-js">import { bignumber, add } from &#39;mathjs&#39;;

let a = bignumber(0.1);
let b = bignumber(0.2);

console.log(add(a, b).toString()); // 0.3</code></pre>
<br />

<h4 id="5️⃣-다중-정밀도-라이브러리-사용하기">5️⃣ 다중 정밀도 라이브러리 사용하기</h4>
<p>부동소수점 문제를 해결하기 위해 decimal.js 같은 다중 정밀도 라이브러리를 사용하면 소수점 연산의 정밀도를 높일 수 있습니다. 
이 방법은 <strong>계산의 정확성을 극대화</strong>하지만, <strong>성능상의 비용이 발생</strong>할 수 있습니다.</p>
<p>이 방법은 매우 정밀한 계산이 필요한 경우에 유용하며, 자바스크립트뿐만 아니라 다양한 언어에서 사용할 수 있는 라이브러리들이 존재합니다.</p>
<br />
<br />
<hr />

<p><em>References.</em></p>
<p>[👩🏻‍💻 Blogs]</p>
<ul>
<li><a href="https://steemit.com/kr/@modolee/floating-point">부동 소수점(Floating Point)란 무엇인가?</a></li>
<li><a href="https://medium.com/@devjohnpark/%EC%BB%B4%ED%93%A8%ED%84%B0%EC%97%90%EC%84%9C-%EC%8B%A4%EC%88%98%ED%98%95-%ED%91%9C%ED%98%84-e5f0d2acafb4">자바의 실수형 표현</a></li>
<li><a href="https://velog.io/@probsno/Big-decimal%EC%9D%80-%EC%99%9C-%EC%93%B0%EB%8A%94-%EA%B1%B0%EC%A5%AC">Big decimal은 왜 쓰는 거쥬?</a></li>
</ul>
<p>[🎥 Videos]</p>
<ul>
<li>코딩맥스의 <a href="https://www.youtube.com/watch?v=Q0IDol-XoOE">부동소수점은 왜 오차가 발생할까?</a></li>
<li>코딩애플의 <a href="https://www.youtube.com/watch?v=-GsrYvZoAdA">위 수식이 틀린 이유는? (개발자 면접 타임)</a></li>
<li>얄팍한 코딩사전의 <a href="https://www.youtube.com/watch?v=ZQDsWySjY6g">부동소수점 (+ 실수계산 오차가 생기는 이유)</a></li>
<li>개발자 라라의 <a href="https://www.youtube.com/watch?v=vOO-oLS0H68">컴퓨터에서는 0.1 × 0.1 이 0.01 이 아닙니다</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[상태 관리,  왜 그리고 어떻게 하고 있나요?]]></title>
            <link>https://velog.io/@55555-jyeon/state-menage-libraries</link>
            <guid>https://velog.io/@55555-jyeon/state-menage-libraries</guid>
            <pubDate>Sun, 25 Aug 2024 07:49:19 GMT</pubDate>
            <description><![CDATA[<p>프로젝트를 진행하면 초반에 어떤 상태 관리 라이브러리를 사용할지에 대해 얘기를 나눠보게 됩니다. 아직 배우고 있는 입장에서 새로운 것을 사용해보고 싶은 마음 반, 익숙한 것을 사용하고 싶은 마음이 반 드는 것 같습니다.
그러던 중 이런 식으로 새로운 라이브러리들을 어느 정도 찍먹해보고 나면 어떤 걸 사용하게 될까하는 생각이 들었습니다. </p>
<p>내 프로젝트의 성격과 라이브러리의 특징이 잘 맞아떨어지는 것이 최선의 선택일테니 이번 기회에 라이브러리들의 특징을 간단하게 살펴보면 좋을 것 같아 끄적이게 되었습니다...👀</p>
<hr />
<br />

<h1 id="💡-상태">💡 상태</h1>
<h4 id="상태state의-사전적-의미">상태(State)의 사전적 의미</h4>
<p>사전에 상태(state)에 대해서 검색을 해보면 아래와 같이 나옵니다 :</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/008e9b7e-db50-49d4-add9-87c0fa4968bf/image.png" alt=""></p>
<br />

<h4 id="cs의-상태state">CS의 상태(State)</h4>
<p>일반적으로 CS(컴퓨터 공학)에서 말하는 상태(state)는 어떤 시스템이나 프로그램이 특정 시점에 가지고 있는 <strong>모든 정보나 조건</strong>을 말하며 시스템의 동작은 이 상태에 따라 결정됩니다. </p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/b971b1c0-3a8a-4116-aca8-d64a20776ea8/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/d687a2a9-86a9-4697-9606-f68d53d89970/image.png" alt=""></p>
<blockquote>
<p>🔎 <a href="https://en.wikipedia.org/wiki/State_(computer_science)#:~:text=In%20information%20technology%20and%20computer,known%20as%20its%20state%20space.">wikipedia</a>에서 더 자세한 내용 읽어보기</p>
</blockquote>
<br />

<h4 id="리액트의-상태state">리액트의 상태(State)</h4>
<p>리액트에서의 상태(State)는 컴퓨터 과학의 기본 개념에서 유래되었으며 <strong>특정 시점에 컴포넌트가 가지고 있는 데이터나 정보를 의미</strong>합니다. 
이 상태는 <strong>컴포넌트의 렌더링 결과를 결정</strong>하며, 사용자 입력, 이벤트에 따라 값이 변할 수 있습니다.</p>
<blockquote>
<p>💡 기본적으로 웹 애플리케이션에서 상태는 <strong>상호 작용이 가능한 모든 요소의 현재 값</strong>을 의미</p>
</blockquote>
<br />



<h2 id="상태의-종류">상태의 종류</h2>
<h4 id="①-전역상태-global-state">① 전역상태 (Global State)</h4>
<ul>
<li>프로젝트 전체에 영향을 끼치는 상태</li>
<li>여러 컴포넌트에서 쉽게 접근 O</li>
<li>ex) 사용자 인증 정보, 테마 설정 등</li>
</ul>
<h4 id="②-컴포넌트-간-상태-cross-component-state">② 컴포넌트 간 상태 (Cross Component State)</h4>
<ul>
<li>여러 컴포넌트에서 공유되지만, 전역 상태로 관리될 필요는 없는 상태</li>
<li>주로 부모-자식 간 또는 형제 컴포넌트 간에 공유</li>
<li>Props로 전달되기 때문에 props drilling 주의 필요</li>
<li>ex) 모달의 열림/닫힘 여부 등</li>
</ul>
<h4 id="③-지역상태-local-state">③ 지역상태 (Local State)</h4>
<ul>
<li>특정 컴포넌트 안에서만 관리되는 상태</li>
<li>다른 컴포넌트들과 데이터를 공유 X</li>
<li>ex) 사용자가 입력한 텍스트, form field의 값 등</li>
</ul>
<br />


<h2 id="상태의-분류">상태의 분류</h2>
<p>웹 애플리케이션에서 상태로 분류가 가능한 것들은 크게 아래 네 가지 항목으로 분류할 수 있습니다.</p>
<h4 id="①-ui">① UI</h4>
<ul>
<li>사용자 인터페이스(UI)의 시각적 요소와 관련된 상태</li>
<li>UI 요소의 가시성, 활성화 상태, 스타일 등과 관련된 데이터</li>
</ul>
<h4 id="②-url">② URL</h4>
<ul>
<li>브라우저에서 관리되고 있는 상태 값</li>
<li>사용자의 라우팅에 따라 변경되며, URL의 쿼리 파라미터나 해시가 이 상태를 포함 가능</li>
<li>ex) 페이지의 경로, 검색 쿼리, 필터 조건 등</li>
</ul>
<h4 id="③-form">③ form</h4>
<ul>
<li>폼과 관련된 상태 값</li>
<li>ex) 로딩 중인지(loading), 현재 제출됐는지(submitted), 접근이 불가능한지(disabled), 값이 유효한지(validity), 필드의 값 등</li>
</ul>
<h4 id="④-server-data">④ server data</h4>
<ul>
<li>클라이언트에서 서버로 요청해 가져온 값/데이터</li>
<li>ex) API 요청</li>
</ul>
<br />
<br />

<h1 id="🤷🏻♀️-상태-관리의-필요성">🤷🏻‍♀️ 상태 관리의 필요성</h1>
<p>상태 관리는 리액트 애플리케이션에서 중요한 개념으로, 
애플리케이션의 동작과 사용자 인터페이스를 동적으로 업데이트하는 데 필수적입니다. 
또한 복잡한 상태 관리 요구 사항을 충족하기 위해 적절한 상태 관리 전략을 선택하는 것이 중요합니다.</p>
<br />


<h5 id="1️⃣-일관된-데이터-공유">1️⃣ 일관된 데이터 공유</h5>
<p>상태 관리를 통해 애플리케이션의 컴포넌트들이 일관된/동일한 데이터를 공유할 수 있습니다. 이를 통해 사용자의 상호작용에 즉시 반응할 수 있으며, 전체 애플리케이션의 일관성을 유지할 수 있습니다.</p>
<h5 id="2️⃣-애플리케이션-동작-결정">2️⃣ 애플리케이션 동작 결정</h5>
<p>상태는 애플리케이션의 동작을 결정하는 핵심 요소입니다. 컴포넌트의 상태가 변경될 때, 리액트는 해당 컴포넌트를 리렌더링하여 사용자에게 최신 정보를 제공하고, 애플리케이션의 동작을 최신 상태로 유지합니다.</p>
<h5 id="3️⃣-성능과-유지보수성-향상">3️⃣ 성능과 유지보수성 향상</h5>
<p>효과적인 상태 관리는 애플리케이션의 성능과 유지보수성을 향상시킬 수 있습니다. 잘 설계된 상태 관리 시스템은 코드의 복잡성을 줄여주기 때문에 오류의 예방 및 상태의 쉬운 추적과 관리를 용이하게 해줍니다.</p>
<h5 id="4️⃣-규모-확장에-대응">4️⃣ 규모 확장에 대응</h5>
<p>애플리케이션의 규모가 커지면서 여러 컴포넌트 간에 상태를 공유하고 관리해야 할 필요가 커집니다. 기본적인 상태 관리 방법만으로는 이러한 복잡한 상황을 처리하기 어려울 수 있으며, 이를 해결하기 위해 아래에 설명할 상태 관리 라이브러리와 패턴이 추가적으로 필요할 수 있습니다.</p>
<br />
<br />

<h1 id="🗂️-상태-관리">🗂️ 상태 관리</h1>
<p>리액트에서 상태 관리는 컴포넌트의 <strong>state와 props</strong>를 통해 이루어집니다.</p>
<p>state는 컴포넌트 내부에서 관리되는 데이터이며, props는 부모 컴포넌트로부터 전달받은 데이터입니다. </p>
<p>state는 setState 함수를 통해 업데이트되며, 이 과정에서 리액트는 컴포넌트를 자동으로 리렌더링하여 변경된 데이터를 사용자에게 보여줍니다.</p>
<p>효율적인 상태 관리를 위해서는 다음과 같은 사항을 고려해야 합니다:</p>
<br />

<h2 id="고려-사항-및-방법">고려 사항 및 방법</h2>
<br />


<h5 id="q1-상태를-어디에-두는-것이-좋을까">Q1. 상태를 어디에 두는 것이 좋을까?</h5>
<pre><code>A1. 로컬 상태
상태가 특정 컴포넌트에만 필요한 경우, 해당 컴포넌트 내부에서 로컬 상태로 관리


A2. 전역 상태
여러 컴포넌트에서 접근하거나 수정해야 하는 상태는 전역 상태로 관리 

A3. URL 상태
라우팅에 따라 변경되는 상태는 URL 쿼리 파라미터나 해시를 통해 관리 가능
사용자의 페이지 탐색 상태를 저장하고 복원하는 데 유용</code></pre><br />

<h5 id="q2-상태가-유효한-범위를-어떻게-제한할까">Q2. 상태가 유효한 범위를 어떻게 제한할까?</h5>
<pre><code>A1. 컴포넌트의 책임 분리
각 컴포넌트는 자신의 상태와 관련된 데이터만 관리하도록 설계
컴포넌트 간의 의존성 ↓ 
상태가 필요한 컴포넌트에서만 상태를 관리

A2. 상태 분할
큰 상태 객체를 여러 개의 작은 상태로 나누어 관리
상태의 범위 ↓, 상태 변경의 영향을 최소화

A3. 상위 컴포넌트에서 상태 관리
상태가 여러 하위 컴포넌트에서 필요할 경우 상위 컴포넌트에서 상태를 관리
하위 컴포넌트에 필요한 데이터만 전달하는 방식으로 유효 범위 제한 </code></pre><br />

<h5 id="q3-상태의-변화에-따라-변경돼야-하는-자식-요소들은-어떻게-이-상태의-변화를-감지할-수-있을까">Q3. 상태의 변화에 따라 변경돼야 하는 자식 요소들은 어떻게 이 상태의 변화를 감지할 수 있을까?</h5>
<pre><code>A1. Props 전달
상위 컴포넌트에서 상태를 관리, 자식 컴포넌트에 props를 통해 상태 값을 전달
자식 컴포넌트는 전달받은 props가 변경될 때마다 리렌더링

A2. Context API
전역 상태를 Context API를 사용하여 제공
하위 컴포넌트는 Context를 구독하여 상태 변화에 반응

A3. 상태 관리 라이브러리
상태 변화가 발생할 때 자동으로 관련 컴포넌트를 업데이트</code></pre><br />

<h5 id="q4-상태-변화가-일어남에-따라-즉각적으로-모든-요소들이-변경되는-현상은-어떻게-방지할-수-있을까">Q4. 상태 변화가 일어남에 따라 즉각적으로 모든 요소들이 변경되는 현상은 어떻게 방지할 수 있을까?</h5>
<pre><code>A1. 메모이제이션
React.memo, useMemo, useCallback 훅으로 컴포넌트와 함수의 결과를 메모이제이션
상태가 변경될 때만 렌더링 발생 → 불필요한 리렌더링 방지

A2. 상태 분리
컴포넌트의 상태를 세분화
상태가 변경될 때 관련된 컴포넌트만 리렌더링하도록 관리

A3. 성능 최적화
컴포넌트의 shouldComponentUpdate 메서드로 특정 조건에서만 리렌더링되도록 설정
useEffect 훅의 의존성 배열을 설정</code></pre><br />
<br />

<h1 id="📚-전역-상태-관리-라이브러리">📚 전역 상태 관리 라이브러리</h1>
<p>효율적인 상태 관리는 애플리케이션의 다양한 레벨에서 상태를 쉽게 접근하고 업데이트할 수 있도록 하는 데 필수적입니다. 리액트 애플리케이션이 커지고 복잡해짐에 따라, 기본적인 state와 props만으로는 상태 관리가 어려울 수 있습니다.</p>
<p>이러한 문제를 해결하기 위해 리액트 생태계에서는 여러 가지 상태 관리 라이브러리와 패턴이 제안되었습니다. 이들 라이브러리는 복잡한 상태를 효율적으로 관리하고, 애플리케이션의 상태를 쉽게 유지보수할 수 있도록 도와줍니다.</p>
<blockquote>
<h5 id="✌🏻-상태-관리-라이브러리의-조건-2가지">✌🏻 상태 관리 라이브러리의 조건 2가지</h5>
<p>① 어떠한 상태를 기반으로 다른 상태를 만들어낼 수 있는가
② 필요에 따라 이런 상태 변화를 최적화할 수 있는가</p>
</blockquote>
<p>아래에는 리액트에서 널리 사용되는 상태 관리 라이브러리들을 소개합니다 :</p>
<h2 id="redux">Redux</h2>
<p>리덕스(redux)는 flux 구조를 구현하기 위해 만들어진 라이브러리 중 하나로 Elm 아키텍처를 도입했다는 특징이 있습니다.</p>
<h4 id="flux">Flux</h4>
<p>2014년 즈음 리액트의 등장과 비슷한 시기에 Flux 패턴과 함께 이를 기반으로 한 Flux 라이브러리가 등장하게 됩니다.</p>
<p>리액트는 단방향 데이터 바인딩을 기반으로 한 라이브러리입니다.
flux 패턴 역시 리액트와 마찬가지로 단방향 데이터 흐름을 정의하기 때문에 잘 맞았습니다.</p>
<br />

<blockquote>
<h5 id="단방향-데이터-바인딩">단방향 데이터 바인딩</h5>
<pre><code>🟢 PROS
- 데이터의 추적이 쉬움
- 코드의 가독성 용이
🔴 CONS
- 코드의 양이 많아짐</code></pre></blockquote>
<br />

<blockquote>
<h5 id="elm-아키텍처"><a href="https://kyunooh.gitbooks.io/elm/content/architecture/">Elm 아키텍처</a></h5>
<p>Elm는 flux와 마찬가지로 데이터 흐름을 세 가지로 분류하고 단방향으로 강제해 웹 애플리케이션의 상태를 안정적으로 관리하고자 한 아키텍처입니다.</p>
</blockquote>
<br />

<h4 id="기본-원리">기본 원리</h4>
<p>1️⃣ 하나의 상태 객체를 스토어에 저장</p>
<pre><code>리덕스는 애플리케이션의 모든 상태를 하나의 중앙 저장소(Store)에 보관</code></pre><p>2️⃣ 디스패치(dispatch)로 reducer 함수 호출    </p>
<pre><code>상태를 변경하려면, 액션(action)을 디스패치하여 리듀서(reducer) 함수를 호출
리듀서는 현재 상태와 액션을 받아 새로운 상태 객체를 반환</code></pre><p>3️⃣ 새로운 상태를 전파</p>
<pre><code>리듀서에서 반환된 새로운 상태 객체는 스토어에 저장
애플리케이션의 모든 구독된 컴포넌트에 전파</code></pre><br />

<h6 id="사용해보자">사용해보자</h6>
<p>먼저 액션(action)은 상태를 변경하는 요청을 정의합니다. 
setName이라는 액션을 사용하여 이름을 변경할 겁니다.</p>
<pre><code class="language-js">// actions.js
export const SET_NAME = &quot;SET_NAME&quot;;

export const setName = (name) =&gt; ({
  type: SET_NAME,
  payload: name,
});</code></pre>
<p>리듀서(reducer)는 액션을 처리하고 상태를 업데이트하는 함수입니다.
SET_NAME 액션이 호출되면 이름이 변경된 새로운 상태를 반환할 겁니다.</p>
<pre><code class="language-js">// reducer.js
import { SET_NAME } from &quot;./actions&quot;;

const initialState = {
  name: &quot;Jane Doe&quot;,
  age: 20,
};

export const userReducer = (state = initialState, action) =&gt; {
  switch (action.type) {
    case SET_NAME:
      return {
        ...state,
        name: action.payload,
      };
    default:
      return state;
  }
};</code></pre>
<p>스토어(store)에서는 애플리케이션의 전역 상태를 관리합니다. 
createStore 함수를 사용하여 리듀서를 기반으로 스토어를 생성합니다.</p>
<pre><code class="language-js">// store.js
import { createStore } from &quot;redux&quot;;
import { userReducer } from &quot;./reducer&quot;;

const store = createStore(userReducer);

export default store;</code></pre>
<p>상위 컴포넌트에서 Provider를 통해 리덕스 스토어를 하위 컴포넌트에 제공합니다.</p>
<pre><code class="language-js">function App() {
  return (
    &lt;div className=&quot;container&quot;&gt;
      &lt;Provider store={store}&gt; ✔
        &lt;UserProfile /&gt;
      &lt;/Provider&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>현재 사용자 이름과 나이를 화면에 표시해주고 아래 버튼 클릭 시 각각 &quot;Jane Doe&quot; 또는 &quot;John Doe&quot;로 이름을 변경되도록 합니다.</p>
<p>useSelector를 통해 전역 상태에서 현재 이름과 나이를 가져오고,
useDispatch를 사용해 이름을 변경하는 액션을 디스패치하고 있습니다.</p>
<pre><code class="language-js">const UserProfile = () =&gt; {
  const user = useSelector((state) =&gt; state);
  const dispatch = useDispatch();

  return (
    &lt;div className=&quot;user-profile&quot;&gt;
      &lt;h1&gt;User Profile&lt;/h1&gt;
      &lt;p&gt;Name: {user.name}&lt;/p&gt;
      &lt;p&gt;Age: {user.age}&lt;/p&gt;
      &lt;button onClick={() =&gt; dispatch(setName(&quot;Jane Doe&quot;))}&gt;
        Set Female name
      &lt;/button&gt;
      &lt;button onClick={() =&gt; dispatch(setName(&quot;John Doe&quot;))}&gt;
        Set Male name
      &lt;/button&gt;
    &lt;/div&gt;
  );
};

export default UserProfile;</code></pre>
<p>위 코드의 실행 결과는 아래에서 확인 가능합니다 :</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/834b7f65-09f1-4e74-aa1f-f557e53afb54/image.gif" alt=""></p>
<br />


<h5 id="🟢-pros">🟢 pros</h5>
<ul>
<li>하나의 전역 상태로 props drilling 문제를 해결 가능</li>
<li>스토어(store)가 필요한 컴포넌트는 connect만으로 접근 가능</li>
</ul>
<h5 id="🔴-cons">🔴 cons</h5>
<ul>
<li>하나의 상태를 바꾸는데 많은 로직 필요 (투머치 보일러플레이트)</li>
</ul>
<br />

<blockquote>
<h5 id="🤔-provider가-여러-개라면">🤔 provider가 여러 개라면?</h5>
<p>가장 가까운 Provider의 값을 가져오게 됩니다.</p>
</blockquote>
<blockquote>
<p>Redux를 더욱 쉽게 사용하기 위한 <a href="https://velog.io/@55555-jyeon/redux-toolkit">RTK에 대한 게시글 </a>보러 가기</p>
</blockquote>
<br />

<h6 id="적절한-상태-주입에-대한-고민">적절한 상태 주입에 대한 고민</h6>
<h2 id="context-api-usecontext">context API, useContext</h2>
<p>props drilling 및 too much boilerplate 두 가지 단점을 잡기 위해 등장한 것이 바로 리액트의 context API 입니다.</p>
<p align="center">
<img width="30%" src="https://velog.velcdn.com/images/55555-jyeon/post/abd60bb5-aa37-40b5-9665-f9d04428b70d/image.png" />
</p>

<p>props drilling을 해결하는데에는 리덕스(redux)도 있지만 리덕스의 투머치 보일러플레이트는 부담이 될 뿐만 아니라 컴포넌트 설계 시에도 큰 제약이 있기 때문입니다.</p>
<blockquote>
<h5 id="🤷🏻♀️-어떤-제약">🤷🏻‍♀️ 어떤 제약?</h5>
<p> ① 작은 컴포넌트 및 간단한 상태 관리에도 과도한 구조적 복잡함
② 애플리케이션이 커질수록 유지보수가 어려움
③ 컴포넌트가 리덕스 스토어에 의존하게 되어 재사용성과 독립성이 저하
④ 상태를 전부 전역으로 관리하므로 특정 컴포넌트 테스트가 어려움</p>
</blockquote>
<br />

<h6 id="조금-더-자세히-알아보자">조금 더 자세히 알아보자</h6>
<h4 id="context">context</h4>
<p>컨텍스트(context)는 props drilling을 극복하기 위해 등장한 개념입니다.</p>
<p>컨텍스트를 사용할 경우, props를 명시적으로 사용하지 않아도 선언한 모든 하위 컴포넌트에서 값을 사용할 수 있다는 특징이 있습니다.</p>
<h4 id="usecontext">useContext</h4>
<p>useContext는 상위 컴포넌트에서 만들어진 컨텍스트를 함수 컴포넌트에서 사용할 수 있도록 만들어진 훅입니다.</p>
<br />

<h6 id="사용해보자-1">사용해보자</h6>
<pre><code class="language-js">// 01. create context
export const UserContext = createContext();

function App() {
  const [sampleUser, setSampleUser] = useState({ name: &quot;Jane Doe&quot;, age: 20 });

  return (
    // 02. provide state to child components by Provider
    &lt;div className=&quot;container&quot;&gt;
      &lt;UserContext.Provider value={{ sampleUser, setSampleUser }}&gt; ✔
        &lt;UserProfile /&gt;
        &lt;UpdateName /&gt;
      &lt;/UserContext.Provider&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<p>UserContext의 Provider 안에 포함되는 자식 컴포넌트들은 value 안의 상태를 useContext 훅으로 가져다 쓸 수 있습니다.</p>
<pre><code class="language-js">// component 1
const UserProfile = () =&gt; {
  const { sampleUser } = useContext(UserContext);

  return (
    &lt;div&gt;
      &lt;h1&gt;User List&lt;/h1&gt;
      &lt;p&gt;Name : {sampleUser.name}&lt;/p&gt;
      &lt;p&gt;Age : {sampleUser.age}&lt;/p&gt;
    &lt;/div&gt;
  );
};

export default UserProfile;

// component 2
const UpdateName = () =&gt; {
  const { sampleUser, setSampleUser } = useContext(UserContext);

  const updateName = () =&gt; {
    setSampleUser({ ...sampleUser, name: &quot;John Doe&quot; });
  };

  return (
    &lt;div&gt;
      &lt;button onClick={updateName}&gt;Change Name&lt;/button&gt;
    &lt;/div&gt;
  );
};
export default UpdateName;
</code></pre>
<p>위 코드의 실행 결과는 아래에서 확인 가능합니다 :</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/e9aa2a31-ccbb-466f-a79d-acc27fbe1210/image.gif" alt=""></p>
<br />


<h5 id="🟢-pros-1">🟢 pros</h5>
<ul>
<li>전역 상태를 손쉽게 관리 가능 </li>
<li>깊이 있는 컴포넌트 트리에서도 직접적으로 상태 사용이 가능</li>
<li>리덕스와 달리 간단한 API를 통해 상태를 관리하므로 설정 및 유지보수의 복잡성 ↓</li>
</ul>
<h5 id="🔴-cons-1">🔴 cons</h5>
<ul>
<li>컴포넌트의 구조가 복잡해질수록 컨텍스트 사용도 복잡해질 가능성 높음</li>
<li>컴포넌트 내부에서 useContext 사용 시 재사용 불가</li>
<li>해당 컨텍스트 사용 시 모든 컴포넌트가 리렌더링 될 수 있음 (성능 이슈)</li>
</ul>
<br />


<blockquote>
<h5 id="🤔-context-사용-시-주의해야할-점이-있다면">🤔 context 사용 시 주의해야할 점이 있다면?</h5>
<p>① context API는 상태 관리가 아닌 <strong>주입을 도와주는 기능</strong>이란 점
② <strong>렌더링을 막아주는 기능이 없다</strong>는 점</p>
</blockquote>
<br />


<h6 id="2020-created-by-facebook-company">2020, created by facebook company</h6>
<h2 id="recoil">recoil</h2>
<p>리코일(recoil)은 페이스북에서 만든 리액트를 위한 상태 관리 라이브러리입니다.
훅의 개념으로 상태 관리를 시작한 라이브러리 중 하나이기도 합니다.</p>
<p>2020년에 처음 만들어졌으며, github 주소로 가보면 아직 정식으로 출시가 되지 않은 것을 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/c86e3085-31fb-4f88-b755-290e8e156268/image.png" alt=""></p>
<p>리코일 팀에서는 리액트 18에서 제공될 기능들이 지원되기 전까지는 1.0.0을 릴리즈(release)하지 않을 것이라고 밝혔습니다.</p>
<p>따라서 실제 프로젝트에 리코일을 채택해 사용하기엔 안정성, 성능, 사용성 등이 보장되지 않을 수 있습니다.</p>
<br />

<h6 id="조금-더-자세히-알아보자-1">조금 더 자세히 알아보자</h6>
<h4 id="recoilroot">RecoilRoot</h4>
<p>리코일을 사용하기 위해 RecoilRoot를 애플리케이션의 최상단에 선언해야 합니다.</p>
<p>RecoilRoot는 리코일에서 생성되는 상태값을 저장하기 위한 스토어를 생성하기 때문에 최상단에 선언을 해야 합니다.</p>
<pre><code class="language-js">function App() {
    return &lt;RecoilRoot&gt;
      {/*other components*/}
      &lt;/RecoilRoot&gt;
}
export default App;</code></pre>
<p>리코일의 상태값은 RecoilRoot로 생성된 context의 스토어에 저장됩니다.
스토어의 상태값에 접근할 수 있는 함수들을 활용해 상태값을 변경할 수 있으며
값의 변경될 경우 해당 상태를 참조하고 있는 모든 하위 컴포넌트에게 알려줍니다.</p>
<h4 id="atom">atom</h4>
<p>atom은 리코일에서 최소 상태 단위를 나타내는 개념입니다.
key와 default 값을 필수로 가지며 이 key 값은 다른 atom과 구별되는 식별자가 됩니다.</p>
<h4 id="selector">selector</h4>
<p>selector(선택자)는 파생 상태(derived state)를 만들기 위한 도구입니다. 이는 여러 개의 atom을 조합하거나, 하나의 atom에서 특정 데이터를 가공하여 새로운 상태를 계산하는 데 사용됩니다.</p>
<p>즉, selector는 기존 상태를 기반으로 계산된 값을 반환하는 함수입니다. 
이를 통해 컴포넌트에서 필요한 데이터만 선택적으로 사용할 수 있게 됩니다.</p>
<br />

<h6 id="사용해보자-2">사용해보자</h6>
<p>atom을 만들어 줍니다.
저는 파일을 분리했기 때문에 export를 했지만 한 파일에 전부 작성할 예정이라면 그냥 선언만 해주어도 무방합니다.</p>
<pre><code class="language-js">export const sampleNameState = atom({
  key: &quot;nameState&quot;,
  default: &quot;John&quot;,
});</code></pre>
<p>리액트의 useState 대신 useRecoilState를 사용하면 됩니다.
안에는 atom을 생성했을 때 작성했던 식별자 key의 값을 넣어주면 됩니다.</p>
<pre><code class="language-js">const UserProfile = () =&gt; {
  const [name, setName] = useRecoilState(sampleNameState);
  const toggleName = () =&gt; {
    setName(name === &quot;John&quot; ? &quot;Jane&quot; : &quot;John&quot;);
  };

  return (
    &lt;div&gt;
      &lt;h1&gt;{name}&lt;/h1&gt;
      &lt;button onClick={toggleName}&gt;Toggle Name&lt;/button&gt;
    &lt;/div&gt;
  );
};
export default UserProfile;</code></pre>
<p>최상단 컴포넌트에서 RecoilRoot로 recoil이 사용될 컴포넌트들을 감싸주면 됩니다.</p>
<pre><code class="language-js">function App() {
  return (
    &lt;div className=&quot;container&quot;&gt;
      &lt;RecoilRoot&gt;
        &lt;UserProfile /&gt;
      &lt;/RecoilRoot&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<p>위 코드의 실행 결과는 아래에서 확인 가능합니다 :</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/97019fd1-5f21-4b51-8071-26af0fcdf7d4/image.gif" alt=""></p>
<br />

<h5 id="🟢-pros-2">🟢 pros</h5>
<ul>
<li>selector를 통해 복잡한 상태 구조를 쉽게 관리 가능</li>
<li>각 atom이 독립적으로 동작하므로 성능 최적화에 유리</li>
<li>리액트의 개념과 매우 잘 통합되어 있어 쉽게 사용 가능</li>
</ul>
<h5 id="🔴-cons-2">🔴 cons</h5>
<ul>
<li>정식 버전 미출시로 인한 안정성 확보의 어려움</li>
</ul>
<br />

<blockquote>
<p><a href="https://recoiljs.org/">recoil 공식 홈페이지</a>에서 더 자세한 내용 보기</p>
</blockquote>
<br />

<h6 id="recoil보다-유연한">recoil보다 유연한</h6>
<h2 id="jotai">jotai</h2>
<p>조타이(jotai)는 리코일의 atom 모델에 영감을 받아 만들어진 라이브러리입니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/8209d8c1-bf04-4314-aa6a-3dbfc4d98e2f/image.png" alt=""></p>
<p>공식 문서에도 언급되어 있지만,
Jotai는 리액트의 Context API에서 발생하는 불필요한 리렌더링 문제를 해결하기 위해 개발되었으며, 메모이제이션이나 추가적인 최적화 없이도 불필요한 리렌더링을 방지하도록 설계되었습니다.</p>
<p>조타이는 상향식(bottom-up) 접근법을 취하고 있기 때문에 작은 단위의 상태(atom)를 상위로 전파할 수 있는 구조를 갖고 있습니다.</p>
<br />

<h6 id="더-자세히-알아보자">더 자세히 알아보자</h6>
<h4 id="atom-1">atom</h4>
<p>리코일에서 atom 모델에 영감을 받았기 때문에 조타이에도 동일하게 atom이 존재합니다.
차이가 있다면 조타이에서는 atom 하나로 파생된 상태도 만들 수 있다는 것입니다.</p>
<p>또한 조타이에서는 atom을 생성할 때 고유한 key 값을 전달해주지 않아도 됩니다.</p>
<pre><code class="language-js">const counterAtom = atom(0)

console.log(&quot;atom&quot;, counterAtom); 
/* 
&quot;atom&quot;,
{
    init: 0,
    read: (get) =&gt; get(config),
    write: (get, set, update) =&gt;
        set(config, typeof update === &quot;function&quot; ? update(get(config)) : update
}
*/</code></pre>
<p>조타이의 useAtomValue 함수에는 rerenderIfChanged라는 로직이 있습니다.
이 로직으로 인해 조타이에서는 atom의 값이 어디서 변경되든지 useAtomValue로 값을 사용하는 쪽에서는 항상 최신의 atom을 사용해 렌더링할 수 있습니다.</p>
<p>rerenderIfChanged가 일어나는 경우는 크게 두 가지가 있습니다 :</p>
<p>① 넘겨받은 atom이 reducer를 통해 스토어에 있는 atom과 달라졌을 때
② subscribe를 수행하고 있던 중 어디서 값이 변경되었을 때</p>
<br />

<h6 id="사용해보자-3">사용해보자</h6>
<p>atom으로 상태를 만들 수 있으며 리코일과 다르게 key 값을 넘겨주지 않아도 됩니다.</p>
<pre><code class="language-js">export const sampleNameAtom = atom(&quot;John&quot;);</code></pre>
<p>생성된 상태는 useAtom으로 불러와 사용 가능합니다.</p>
<pre><code class="language-js">const UserProfile = () =&gt; {
  const [name, setName] = useAtom(sampleNameAtom);

  const toggleName = () =&gt; {
    setName(name === &quot;John&quot; ? &quot;Jane&quot; : &quot;John&quot;);
  };

  return (
    &lt;div&gt;
      &lt;h1&gt;{name}&lt;/h1&gt;
      &lt;button onClick={toggleName}&gt;Jotai Test&lt;/button&gt;
    &lt;/div&gt;
  );
};
export default UserProfile;</code></pre>
<p>다른 라이브러리들과 달리 최상단을 provider라던가 context로 감쌀 필요가 없습니다.</p>
<pre><code class="language-js">function App() {
  return (
    &lt;div className=&quot;container&quot;&gt;
      &lt;UserProfile /&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<p>위 코드가 실행된 결과는 아래와 같습니다 :</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/ef6085a3-7ff4-4792-a00a-2bf50add34cc/image.gif" alt=""></p>
<br />

<h5 id="🟢-pros-3">🟢 pros</h5>
<ul>
<li>간결한 API 및 사용</li>
<li>타입 지원이 잘 되어 있음 (d.ts 제공)</li>
<li>리액트 18의 변경된 API를 원활히 지원하며 현재 v2 버전 출시</li>
<li>recoil의 대안으로 많은 개발자들의 선택을 받음</li>
</ul>
<h5 id="🔴-cons-3">🔴 cons</h5>
<ul>
<li>상태 관리가 복잡해질 경우 추가적인 도구나 패턴이 필요할 수 있음</li>
<li>상대적으로 작은 커뮤니티와 생태계</li>
</ul>
<br />

<blockquote>
<p><a href="https://jotai.org/">jotai 공식 홈페이지</a>에서 더 자세한 내용 보기</p>
</blockquote>
<br />

<h6 id="redux보다-유연한">redux보다 유연한</h6>
<h2 id="zustand">zustand</h2>
<p>zustand는 리덕스(redux)에 영감을 받아 만들어진 라이브러리입니다.
따라서 zustand는 하나의 스토어(store)를 중앙 집중형으로 활용해 스토어 내부에서 상태를 관리하는 방식입니다.</p>
<br />

<h6 id="더-자세히-알아보자-1">더 자세히 알아보자</h6>
<h4 id="store">store</h4>
<p>zustand의 깃허브를 살짝 훔쳐보면 관련된 코드를 볼 수 있습니다.</p>
<p>zustand의 store와 관련된 코드는 <code>./src/vanilla.ts</code>에서, store를 리액트에서 사용할 수 있도록 도와주는 함수들은 <code>./src/react.ts</code>에서 관리되고 있습니다.</p>
<p>바닐라 자바스크립트의 함수와 객체를 사용하여 상태를 관리하기 때문에 리덕스의 복잡한 구조를 갖추지 않아도 된다는 점에서 리덕스보다 유연하다고 볼 수 있습니다. 
이러한 구조 덕분에 zustand는 리덕스에 비해 상태 관리 로직이 더욱 간단하고 직관적으로 작성됩니다.</p>
<p>또한 리액트의 useState와 유사한 setState 메커니즘을 사용하여 상태를 업데이트합니다. 이러한 구조는 상태 업데이트가 매우 직관적이며, 부분적인 상태 변경(partial state update)도 쉽게 수행할 수 있도록 도와줍니다.</p>
<pre><code class="language-js">// 64번째 줄 ~
  const setState: StoreApi&lt;TState&gt;[&#39;setState&#39;] = (partial, replace) =&gt; {
    const nextState =
      typeof partial === &#39;function&#39; 
        ? (partial as (state: TState) =&gt; TState)(state)
        : partial
    if (!Object.is(nextState, state)) {
      const previousState = state
      state =
        (replace ?? (typeof nextState !== &#39;object&#39; || nextState === null))
          ? (nextState as TState)
          : Object.assign({}, state, nextState)
      listeners.forEach((listener) =&gt; listener(state, previousState))
    }
  }</code></pre>
<p>partial은 state의 일부를 변경할 때, replace는 state를 완전히 새로운 값으로 대체할 때 사용됩니다. 이를 통해 state가 객체일 때 필요에 따라 유연하게 사용할 수 있습니다.</p>
<blockquote>
<p><a href="https://github.com/pmndrs/zustand">zustand github</a> 방문하기</p>
</blockquote>
<br />

<h6 id="사용해보자-4">사용해보자</h6>
<p>Zustand의 create 함수를 사용해 스토어를 생성합니다.</p>
<pre><code class="language-js">export const sampleUserStore = create((set) =&gt; ({
  name: &quot;John&quot;,
  toggleName: () =&gt;
    set((state) =&gt; ({
      name: state.name === &quot;John&quot; ? &quot;Jane&quot; : &quot;John&quot;,
    })),
}));</code></pre>
<p>생성한 스토어의 상태와 함수를 그대로 가져와 사용할 수 있습니다.</p>
<pre><code class="language-js">const UserProfile = () =&gt; {
  const { name, toggleName } = sampleUserStore();

  return (
    &lt;div&gt;
      &lt;h1&gt;{name}&lt;/h1&gt;
      &lt;button onClick={toggleName}&gt;zustand sample&lt;/button&gt;
    &lt;/div&gt;
  );
};
export default UserProfile;</code></pre>
<p>마찬가지로 별도의 provider나 context로 감쌀 필요가 없습니다.</p>
<pre><code class="language-js">function App() {
  return (
    &lt;div className=&quot;container&quot;&gt;
      &lt;UserProfile /&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>위 코드의 실행 결과는 아래와 같습니다:</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/4a6a5eee-dd12-4248-be82-7e22040070da/image.gif" alt=""></p>
<br />

<h5 id="🟢-pros-4">🟢 pros</h5>
<ul>
<li>간결하고 사용하기 쉬운 API</li>
<li>불필요한 리렌더링 방지</li>
<li>작은 크기와 가벼운 라이브러리</li>
<li>React와의 원활한 통합 및 유연성</li>
</ul>
<h5 id="🔴-cons-4">🔴 cons</h5>
<ul>
<li>상대적으로 작은 생태계와 커뮤니티 지원</li>
<li>대규모 프로젝트에서 상태 관리의 구조화 부족 가능성 존재</li>
</ul>
<br />

<blockquote>
<p><a href="https://zustand.docs.pmnd.rs/getting-started/introduction">zustand 공식 홈페이지</a>에서 더 자세한 내용 보기</p>
</blockquote>
<br />
<br />

<h6 id="전체적인-내용-요약">전체적인 내용 요약</h6>
<h1 id="🤔-언제-무엇을-사용할까">🤔 언제 무엇을 사용할까</h1>
<h5 id="①-context-api">① Context API</h5>
<ul>
<li><strong>특징</strong>
상태를 공유하기 위해 별도의 상태 관리 라이브러리를 사용하지 않아도 됨</li>
<li><strong>한계</strong>
상태 변화가 자주 발생할 경우, Context를 사용하는 컴포넌트들이 과도하게 렌더링될 수 있음</li>
<li><strong>추천 상황</strong><ul>
<li>전역 상태를 컴포넌트 트리 전체에 전달할 때</li>
<li>작고 단순한 애플리케이션일 때</li>
<li>애플리케이션 전역에서 필요한 상태를 관리할 때
  ex) 테마 설정, 사용자 인증 정보 등 </li>
</ul>
</li>
</ul>
<h5 id="②-redux">② Redux</h5>
<ul>
<li><strong>특징</strong>
상태를 한 곳에서 관리하고, 액션과 리듀서를 통해 상태를 변경</li>
<li><strong>한계</strong>
보일러플레이트 코드가 많고 설정이 복잡할 수 있음</li>
<li><strong>추천 상황</strong><ul>
<li>대규모 애플리케이션일 때</li>
<li>복잡한 상태와 액션 흐름을 체계적으로 관리해야 할 때</li>
<li>데이터가 여러 컴포넌트 간에 공유될 때 </li>
<li>복잡한 비즈니스 로직이 있을 때</li>
</ul>
</li>
</ul>
<h5 id="③-recoil">③ Recoil</h5>
<ul>
<li><strong>특징</strong>
상태를 원자(atom)와 파생 상태(selector)로 나누어 관리</li>
<li><strong>한계</strong>
상태 관리가 간단하지만, 아직 상대적으로 새로운 라이브러리로 사용 사례가 제한적일 수 있음</li>
<li><strong>추천 상황</strong><ul>
<li>중간 규모의 애플리케이션일 때</li>
<li>상태 관리가 비교적 간단하면서도 유연하게 동작해야할 때</li>
</ul>
</li>
</ul>
<h5 id="④-zustand">④ Zustand</h5>
<ul>
<li><strong>특징</strong>
훅을 사용하여 상태를 관리하며, 보일러플레이트 코드가 적음</li>
<li><strong>한계</strong>
기능이 간단하여 복잡한 상태 관리에는 한계가 있을 수 있음</li>
<li><strong>추천 상황</strong><ul>
<li>애플리케이션의 규모가 작고 간단할 때</li>
<li>상태 관리가 간단할 때</li>
</ul>
</li>
</ul>
<h5 id="⑤-jotai">⑤ Jotai</h5>
<ul>
<li><strong>특징</strong>
상태를 원자(atom) 단위로 관리하며, 상태 변화에 따른 렌더링을 효율적으로 처리</li>
<li><strong>한계</strong>
다양한 기능을 제공하지만, 개발자에게 새로운 패러다임을 요구할 수 있음</li>
<li><strong>추천 상황</strong><ul>
<li>상태를 최소 단위로 관리하고 싶을 때</li>
<li>상태의 변경 사항을 세밀하게 제어하고 싶을 때</li>
<li>높은 성능을 요구할 때</li>
</ul>
</li>
</ul>
<br />

<h4 id="표로-보기">표로 보기</h4>
<table align="center">
  <thead>
    <tr>
      <th>라이브러리</th>
      <th>복잡도</th>
      <th>사용성</th>
      <th>커뮤니티 크기</th>
      <th>애플리케이션 규모</th>
      <th>러닝 커브</th>
      <th>타입스크립트 지원</th>
      <th>미들웨어 지원</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Context API</td>
      <td>낮음</td>
      <td>간편</td>
      <td>O</td>
      <td>작음</td>
      <td>낮음</td>
      <td>O</td>
      <td>X</td>
    </tr>
    <tr>
      <td>Redux</td>
      <td>높음</td>
      <td>복잡</td>
      <td>O</td>
      <td>대규모</td>
      <td>높음</td>
      <td>O</td>
      <td>O</td>
    </tr>
    <tr>
      <td>Recoil</td>
      <td>중간</td>
      <td>간편</td>
      <td>△</td>
      <td>중간</td>
      <td>중간</td>
      <td>O</td>
      <td>X</td>
    </tr>
    <tr>
      <td>Zustand</td>
      <td>낮음</td>
      <td>간편</td>
      <td>△</td>
      <td>작음</td>
      <td>낮음</td>
      <td>O</td>
      <td>X</td>
    </tr>
    <tr>
      <td>Jotai</td>
      <td>중간</td>
      <td>간편</td>
      <td>△</td>
      <td>중간</td>
      <td>중간</td>
      <td>O</td>
      <td>X</td>
    </tr>
  </tbody>
</table>


<br />
<br />


<h6 id="상태-관리에-대해-블로그들을-찾아보다-발견한">상태 관리에 대해 블로그들을 찾아보다 발견한</h6>
<h1 id="👍-좋은-상태-관리">👍 좋은 상태 관리</h1>
<br />

<h5 id="1️⃣-상태를-불변-객체로">1️⃣ 상태를 불변 객체로!</h5>
<p>상태를 불변 객체로 관리하면 상태 업데이트의 복잡성을 줄이고 성능 최적화에 도움이 됩니다.</p>
<h5 id="2️⃣-상태를-최소화하고-필요한-곳에서만">2️⃣ 상태를 최소화하고 필요한 곳에서만!</h5>
<p>불필요한 상태는 애플리케이션의 복잡성을 증가시키고 버그의 원인이 될 수 있습니다. 
필요한 상태만을 관리하여 코드의 간결함을 유지하는 것이 좋습니다.</p>
<h5 id="3️⃣-상태-업데이트-로직을-컴포넌트-외부에">3️⃣ 상태 업데이트 로직을 컴포넌트 외부에!</h5>
<p>상태 업데이트 로직을 컴포넌트 외부로 분리하면 코드의 재사용성을 높이고 테스트를 용이하게 할 수 있습니다. 이렇게 하면 컴포넌트는 UI를 표현하는 역할에 집중할 수 있습니다.</p>
<br />
<hr />
<br />

<p><em>References.</em></p>
<p>[🌎 Officials]</p>
<ul>
<li><a href="https://react.dev/learn/state-a-components-memory">State: A Component&#39;s Memory</a> </li>
</ul>
<p>[📚 Books]</p>
<ul>
<li>모던 리액트 Deep Dive</li>
</ul>
<p>[👩🏻‍💻 Blogs]</p>
<ul>
<li><a href="https://velog.io/@kskim625/React-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC-Redux-Mobx-Recoil">React 상태 관리 (Redux, Mobx, Recoil)</a></li>
<li><a href="https://hanamon.kr/%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%EB%8F%84%EA%B5%AC-%ED%95%84%EC%9A%94%EC%84%B1/">상태 관리 도구(State Management Tools)의 필요성</a></li>
<li><a href="https://f-lab.kr/insight/importance-of-state-management-in-react">리액트에서 상태 관리의 중요성과 방법</a></li>
<li><a href="https://velog.io/@eunbeann/%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%97%90%EC%84%9C-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0">리액트에서 상태관리가 필요한 이유</a></li>
<li><a href="https://velog.io/@yrnana/Context-API%EA%B0%80-%EC%A1%B4%EC%9E%AC%ED%95%98%EC%A7%80%EB%A7%8C-%EC%97%AC%EC%A0%84%ED%9E%88-%EC%82%AC%EB%9E%8C%EB%93%A4%EC%9D%B4-redux%EC%99%80-%EC%A0%84%EC%97%AD-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EB%A5%BC-%EC%93%B0%EB%8A%94-%EC%9D%B4%EC%9C%A0">Context API가 존재하지만 여전히 사람들이 redux와 전역 상태관리 라이브러리를 쓰는 이유</a></li>
<li><a href="https://velog.io/@beberiche/React%EC%9D%98-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EB%B0%A9%EB%B2%95%EC%97%90-%EB%8C%80%ED%95%B4-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94">React의 상태관리 방법</a></li>
<li><a href="https://velog.io/@zzangzzong/React-%EC%A0%84%EC%97%AD-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC">[React] 전역 상태 관리</a></li>
</ul>
<p>[🎥 Videos]</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MetaData의 모든 설정을 알아보자]]></title>
            <link>https://velog.io/@55555-jyeon/Metadata-options</link>
            <guid>https://velog.io/@55555-jyeon/Metadata-options</guid>
            <pubDate>Wed, 21 Aug 2024 12:40:30 GMT</pubDate>
            <description><![CDATA[<p><a href="https://velog.io/@55555-jyeon/record-your-moments">Yeogi(여기)</a> 웹사이트를 리팩터링하면서 메타데이터를 건들게 되었습니다. 
메타데이터가 무엇인지, 메타데이터를 잘 설정했을 때 어떤 이점이 있는지에 대해서는 어느 정도 알고 있었지만 <a href="https://github.com/mobi-projects/yeogi-client/pull/128">해당 PR</a>을 올리면서 제가 얼마나 메타데이터를 얕잡아보고 있었는지 깨닫는 기회가 되었습니다.</p>
<p>그래서 메타데이터에 대해 알아보려고 합니다. 
어디서부터 알아볼까 고민하다가 우선은 메타데이터에 넣을 수 있는 옵션들에는 어떤 것들이 있는지, 그리고 각각의 옵션들의 값들에 따른 결과에 대해서부터 시작하겠습니다 😊</p>
<br />

<h1 id="metadata">MetaData</h1>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/4bc54b7f-43d0-4cf4-8d50-900ee4c5343c/image.png" alt=""></p>
<h3 id="메타데이터란">메타데이터란?</h3>
<p>메타데이터는 웹페이지에 대한 추가 세부 정보를 제공합니다. 
메타데이터 정보는 페이지를 방문하는 사용자에게 보이지 않으며 페이지의 HTML, 일반적으로 <code>&lt;head&gt;</code> 요소 내에 내장되어 백그라운드에서 작동합니다. 
메타데이터는 웹페이지의 콘텐츠를 더 잘 이해해야 하는 검색 엔진 및 기타 시스템에 필수적인 정보입니다.</p>
<h3 id="메타데이터가-중요한-이유">메타데이터가 중요한 이유</h3>
<p>메타데이터는 웹페이지의 SEO를 향상하는 데 중요한 역할을 하며, 검색 엔진과 소셜 미디어 플랫폼에서 더 쉽게 접근하고 이해할 수 있게 만듭니다. 
적절한 메타데이터는 검색 엔진이 웹페이지를 효과적으로 색인화하여 검색 결과에서 순위를 높이는 데 도움이 됩니다. 또한 Open Graph와 같은 메타데이터는 소셜 미디어에서 공유된 링크의 모양을 개선하여 사용자에게 콘텐츠를 더 매력적이고 유익하게 만듭니다.</p>
<br />

<h1 id="metadata-options">MetaData Options</h1>
<br />

<h2 id="📌-기본-옵션">📌 기본 옵션</h2>
<h3 id="title">title</h3>
<p>title은 브라우저 탭에 표시되는 웹페이지의 제목을 의미합니다.
검색 엔진이 웹페이지의 내용을 이해하는 데 도움이 되므로 SEO에 중요하며 설정한 제목이 브라우저 탭에 보여지게 됩니다.</p>
<pre><code class="language-js">// head output
&lt;title&gt;Page Title&lt;/title&gt;

// sample
export const metadata: Metadata = {
  title: &#39;...&#39;,
}

// example
export const metadata: Metadata = {
    title: &quot;Record Your Trip&quot;
}  </code></pre>
<h3 id="description">description</h3>
<p>설명 항목에 내용을 작성하게 되면 웹페이지 콘텐츠에 대한 간략한 개요를 제공할 수 있으며 검색 엔진 결과에 표시됩니다.</p>
<pre><code class="language-js">// head output
&lt;meta name=&quot;description&quot; content=&quot;A brief description of the page content.&quot; /&gt;

// sample
export const metadata: Metadata = {
  title: &#39;...&#39;,
  description: &#39;...&#39;,
}

// example
export const metadata: Metadata = {
    title: &quot;Record Your Trip&quot;,
    description: &quot;여기에 여행을 기록하세요&quot;
}  </code></pre>
<h3 id="keyword">keyword</h3>
<p>키워드 설정 시 웹페이지 콘텐츠와 관련된 키워드가 포함되어 있어 검색 엔진이 페이지를 색인하는 데 도움이 됩니다.</p>
<pre><code class="language-js">// head output
&lt;meta name=&quot;keywords&quot; content=&quot;keyword1, keyword2, keyword3&quot; /&gt;

// sample
export const metadata: Metadata = {
  title: &#39;...&#39;,
  description: &#39;...&#39;,
  keywords: []
}

// example
export const metadata: Metadata = {
    title: &quot;Record Your Trip&quot;,
    description: &quot;여기에 여행을 기록하세요&quot;,
    keywords: [&quot;여기&quot;, &quot;yeogi&quot;, &quot;여행&quot;, &quot;기록&quot;, &quot;여행 기록&quot;, &quot;trip&quot;, &quot;vacation&quot;, &quot;travel&quot;, &quot;travel logs&quot;]
}</code></pre>
<p>과거에는 검색 엔진 최적화(SEO)에서 중요한 역할을 했지만, 현재는 대부분의 주요 검색 엔진(특히 Google)에서 더 이상 keywords 메타태그를 사용하지 않거나 그 중요성을 거의 부여하지 않는다고 합니다.</p>
<p>여전히 포함하는 것이 해롭지는 않으며, 특히 페이지의 주제를 명시적으로 나타내고자 할 때 사용할 수 있지만 title, description, 그리고 페이지의 실제 콘텐츠가 검색 엔진 최적화에 더 중요한 요소입니다.</p>
<br />


<h3 id="favicon">favicon</h3>
<p>파비콘(작은 아이콘)을 설정하게 되면 브라우저의 주소창이나 탭에 표시되는 웹 페이지 제목 옆에 설정한 아이콘을 보여줄 수 있습니다.</p>
<pre><code class="language-js">// head output
&lt;link rel=&quot;icon&quot; href=&quot;path/to/favicon.ico&quot; /&gt;

// sample
export const metadata: Metadata = {
  title: &#39;...&#39;,
  description: &#39;...&#39;,
  keywords: [],
  icons: {
  icon: &quot;favicon image src&quot;
  }
}  

// example
export const metadata: Metadata = {
    title: &quot;Record Your Trip&quot;,
    description: &quot;여기에 여행을 기록하세요&quot;,
    keywords: [&quot;여기&quot;, &quot;yeogi&quot;, &quot;여행&quot;, &quot;기록&quot;, &quot;여행 기록&quot;, &quot;trip&quot;, &quot;vacation&quot;, &quot;travel&quot;, &quot;travel logs&quot;],
      icons: {
        icon: &quot;/your_logo_img.svg&quot;,
    },
}</code></pre>
<pre><code class="language-js">export const metadata = {
  icons: {
    icon: [
      { url: &#39;/icon.png&#39; },
      new URL(&#39;/icon.png&#39;, &#39;https://example.com&#39;),
      { url: &#39;/icon-dark.png&#39;, media: &#39;(prefers-color-scheme: dark)&#39; },
    ],
    shortcut: [&#39;/shortcut-icon.png&#39;],
    apple: [
      { url: &#39;/apple-icon.png&#39; },
      { url: &#39;/apple-icon-x3.png&#39;, sizes: &#39;180x180&#39;, type: &#39;image/png&#39; },
    ],
    other: [
      {
        rel: &#39;apple-touch-icon-precomposed&#39;,
        url: &#39;/apple-touch-icon-precomposed.png&#39;,
      },
    ],
  },
}</code></pre>
<br />


<p>기본적인 메타데이터 설정을 전부 작성한 다음 링크를 공유하면 아래와 같이 보여지게 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/5077a29b-8cfb-49eb-bca9-95b83a38115e/image.png" alt=""></p>
<br />

<h3 id="others">others</h3>
<pre><code class="language-js">// head output
&lt;meta name=&quot;application-name&quot; content=&quot;Next.js&quot; /&gt;
&lt;meta name=&quot;author&quot; content=&quot;Seb&quot; /&gt;
&lt;link rel=&quot;author&quot; href=&quot;https://nextjs.org&quot; /&gt;
&lt;meta name=&quot;author&quot; content=&quot;Josh&quot; /&gt;
&lt;meta name=&quot;generator&quot; content=&quot;Next.js&quot; /&gt;
&lt;meta name=&quot;referrer&quot; content=&quot;origin-when-cross-origin&quot; /&gt;
&lt;meta name=&quot;color-scheme&quot; content=&quot;dark&quot; /&gt;
&lt;meta name=&quot;creator&quot; content=&quot;Jiachi Liu&quot; /&gt;
&lt;meta name=&quot;publisher&quot; content=&quot;Sebastian Markbåge&quot; /&gt;
&lt;meta name=&quot;format-detection&quot; content=&quot;telephone=no, address=no, email=no&quot; /&gt;


// sample
export const metadata = {
  generator: &#39;Next.js&#39;,
  applicationName: &#39;Next.js&#39;,
  referrer: &#39;origin-when-cross-origin&#39;,
  authors: [{ name: &#39;Seb&#39; }, { name: &#39;Josh&#39;, url: &#39;https://nextjs.org&#39; }],
  creator: &#39;Jiachi Liu&#39;,
  publisher: &#39;Sebastian Markbåge&#39;,
  formatDetection: {
    email: false,
    address: false,
    telephone: false,
  },
}</code></pre>
<br />


<h2 id="🎨-open-graphog-옵션">🎨 open-graph(OG) 옵션</h2>
<p>오픈 그래프(OG) 메타데이터는 제목, 설명, 미리보기 이미지와 같은 정보를 제공하여 소셜 미디어 플랫폼에서 공유될 때 웹페이지가 표현되는 방식을 향상시킵니다.</p>
<pre><code class="language-js">// head output
&lt;meta property=&quot;og:title&quot; content=&quot;Title Here&quot; /&gt;
&lt;meta property=&quot;og:description&quot; content=&quot;Description Here&quot; /&gt;
&lt;meta property=&quot;og:image&quot; content=&quot;image_url_here&quot; /&gt;

// sample
export const metadata: Metadata = {
    // .... 생략
    openGraph: {
      title: &quot;Record Your Trip&quot;,
      description: &quot;여기에 여행을 기록하세요&quot;,
      siteName: &quot;Yeogi&quot;,
      locale: &#39;ko_KR&#39;,
      type: &#39;website&#39;,
      url: &quot;https://yeogi-client.vercel.app/&quot;,
      images: {
        url: &quot;OG image&#39;s absolute src&quot;,
      },
    },
}

// example</code></pre>
<p>오픈그래프에서 작성한 내용은 미리보기 카드에서 확인이 가능한 내용이고 SEO와 직접적으로 연관이 있는 건 일반적인 메타데이터 설정입니다 :)</p>
<p>두 메타데이터의 역할이 다르기 때문에 각각 설정해주는 것이 좋을 것 같아요.</p>
<p>하지만 두 메타데이터에 들어가는 내용 중 공통되는 것이 있다면, 예를 들면 title과 description 같이, 변수로 만들어 넣어줄 수도 있습니다.</p>
<br />

<h3 id="others-1">others</h3>
<pre><code class="language-js">// head output
&lt;meta property=&quot;og:title&quot; content=&quot;Next.js&quot; /&gt;
&lt;meta property=&quot;og:description&quot; content=&quot;The React Framework for the Web&quot; /&gt;
&lt;meta property=&quot;og:url&quot; content=&quot;https://nextjs.org/&quot; /&gt;
&lt;meta property=&quot;og:site_name&quot; content=&quot;Next.js&quot; /&gt;
&lt;meta property=&quot;og:locale&quot; content=&quot;en_US&quot; /&gt;
&lt;meta property=&quot;og:image:url&quot; content=&quot;https://nextjs.org/og.png&quot; /&gt;
&lt;meta property=&quot;og:image:width&quot; content=&quot;800&quot; /&gt;
&lt;meta property=&quot;og:image:height&quot; content=&quot;600&quot; /&gt;
&lt;meta property=&quot;og:image:alt&quot; content=&quot;My custom alt&quot; /&gt;
&lt;meta property=&quot;og:type&quot; content=&quot;website&quot; /&gt;

// sample
export const metadata = {
  openGraph: {
    images: [
      {
        url: &#39;https://nextjs.org/og.png&#39;, // Must be an absolute URL
        width: 800,
        height: 600,
      }
    ],
    videos: [
      {
        url: &#39;https://nextjs.org/video.mp4&#39;, // Must be an absolute URL
        width: 800,
        height: 600,
      },
    ],
    locale: &#39;en_US&#39;,
    type: &#39;website&#39;,
  },
}
</code></pre>
<br />

<h2 id="🤖-robots">🤖 robots</h2>
<p><code>robots.txt</code>를 통해 검색엔진 크롤링에 대한 지침을 제공할 수 있습니다.</p>
<p>robots는 웹 페이지의 로봇 메타 태그에 해당하는 내용을 설정하는 옵션으로 검색 엔진 크롤러나 웹 로봇에게 해당 페이지를 <strong>어떻게 다루어야 하는지 지시</strong>할 수 있습니다.</p>
<p>robots 메타 태그의 주요 역할은 아래 두 가지가 대표적입니다.</p>
<pre><code>① 검색 엔진 인덱싱 제어
    페이지가 검색 엔진의 인덱스에 포함될지 여부를 결정

② 링크 팔로우 제어
    페이지 내의 링크를 따라갈지 여부를 결정</code></pre><p>대부분의 웹 페이지에서 인덱싱(index)과 팔로우(follow)는 기본적으로 활성화된 상태, 즉 <strong>둘 다 기본값이 true로 설정</strong>되어 있기 때문에 robots 메타 태그를 따로 설정하지 않으면 검색 엔진은 웹 페이지를 인덱싱하고, 그 페이지 내의 링크를 따라가 다른 페이지를 탐색하게 됩니다.</p>
<h4 id="그럼-굳이-명시적으로-설정할-필요가-있는가">그럼 굳이 명시적으로 설정할 필요가 있는가?</h4>
<p>기본적으로 제공되는 값이 true이기 때문에 따로 설정할 필요는 없습니다.
하지만 명시적으로 한 번 더 설정할 경우, 코드를 명확히 하거나 다른 페이지에서 noindex 또는 nofollow를 사용한 후 기본 설정으로 돌아가고자 할 때 유용할 수 있습니다.</p>
<p>명시적으로 한 번 더 설정했을 때의 장단점을 간단히 정리하자면 아래와 같습니다 :</p>
<pre><code>👍🏻 장점
    - 검색 가시성
    - SEO 강화
    - 사이트 탐색성 증가

👎🏻 단점
    - 원치 않는 페이지 인덱싱
    - SEO 노이즈
    - 중복 콘텐츠 문제</code></pre><br />


<h3 id="index">index</h3>
<p>인덱싱(indexing, 색인 작업)은 검색 엔진이 웹 페이지의 내용을 분석하여 데이터베이스에 저장하는 과정을 의미합니다. 이 데이터베이스는 검색 엔진이 사용자에게 검색 결과를 제공할 때 사용하는 곳을 말합니다.</p>
<pre><code>🟢 index: true
해당 웹 페이지는 검색 엔진의 데이터베이스에 포함 O → 관련된 키워드로 검색시 검색 결과 O

🔴 index: false
해당 웹 페이지는 검색 엔진의 데이터베이스에 포함 X → 검색 결과 X</code></pre><p>예를 들어, 아래와 같이 <code>robots: &#39;noindex&#39;</code>라고 설정할 경우 검색 엔진은 그 페이지를 인덱싱하지 않으며, 사용자가 검색할 때 그 페이지가 검색 결과에 나타나지 않게 됩니다.</p>
<pre><code class="language-js">// head output
&lt;meta name=&quot;robots&quot; content=&quot;noindex&quot; /&gt;

// sample
  export const metadata: Metadata = {
  robots: {
    index: false,
  },
}</code></pre>
<br />

<h3 id="follow">follow</h3>
<p>링크를 따라가기는 검색 엔진의 웹 크롤러가 해당 페이지에 있는 링크를 따라가서 그 링크로 연결된 다른 페이지를 방문하는 것을 의미합니다.</p>
<pre><code>🟢 follow: true
크롤러는 페이지의 모든 링크를 따라가면서 다른 페이지들을 방문하고 인덱싱할 수 있습니다. 
이를 통해 웹 전체를 탐색하며 페이지 간의 연결을 분석합니다.

🔴 follow: false
크롤러는 해당 페이지에서 다른 페이지로 연결된 링크를 무시합니다. 
따라서 해당 페이지에 있는 링크를 따라가 다른 페이지를 방문하거나 인덱싱하지 않습니다.</code></pre><p>예를 들어, robots: &#39;nofollow&#39;라고 설정하면, 검색 엔진은 그 페이지에 있는 링크를 따라가지 않으며, 그 링크로 연결된 페이지를 방문하거나 인덱싱하지 않습니다.</p>
<pre><code class="language-js">// head output
&lt;meta name=&quot;robots&quot; content=&quot;noindex, follow&quot; /&gt;

// sample
export const metadata: Metadata = {
  robots: {
    index: false,
    follow: true
  },
}</code></pre>
<br />

<h3 id="others-2">others</h3>
<pre><code class="language-js">// head output
&lt;meta name=&quot;robots&quot; content=&quot;noindex, follow, nocache&quot; /&gt;
&lt;meta
  name=&quot;googlebot&quot;
  content=&quot;index, nofollow, noimageindex, max-video-preview:-1, max-image-preview:large, max-snippet:-1&quot;
/&gt;

// sample
export const metadata: Metadata = {
  robots: {
    index: false,
    follow: true,
    nocache: true,
    googleBot: {
      index: true,
      follow: false,
      noimageindex: true,
      &#39;max-video-preview&#39;: -1,
      &#39;max-image-preview&#39;: &#39;large&#39;,
      &#39;max-snippet&#39;: -1,
    },
  },
}</code></pre>
<br />

<h3 id="nocache">nocache</h3>
<p>검색 엔진이 이 페이지를 캐시하게 할 것인지에 대한 여부를 설정하는 옵션으로 검색 엔진에게 이 페이지의 콘텐츠를 캐시하지 않도록 지시하는 역할을 합니다.</p>
<pre><code>🟢 nocache: true
검색 엔진이 이 페이지를 캐시하지 않도록 설정 → 이 페이지의 복사본 저장 X
사용자가 이 페이지를 검색할 때 항상 최신 버전을 보게 됨

🔴 nocache: false
검색 엔진이 이 페이지를 캐시할 수 있도록 허용 → 페이지의 복사본 저장 O
사용자가 검색 결과에서 페이지를 클릭할 때 캐시된 버전을 봄</code></pre><p>이 설정은 특정 페이지의 내용이 자주 변경되거나, 캐시로 인해 사용자에게 잘못된 정보가 표시될 위험이 있는 경우 유용합니다.</p>
<p>따라서 <strong>정적(static) 메타데이터</strong>를 사용하는 페이지는 내용이 자주 변경되지 않으므로 <strong>캐시를 허용</strong>하는 것이 일반적으로 더 효율적입니다.
따라서 이런 페이지의 경우는 캐시를 허용함으로써 페이지 로딩 속도를 빠르게 하는 것이 유리할 수 있습니다.</p>
<p>반대로 다이나믹(dynamic) 메타데이터를 사용하는 페이지는 내용이 자주 변경될 수 있기 때문에 nocache를 true로 설정하여 사용자에게 항ㅅ아 최신 데이터를 보여줄 수 있도록 하는 것이 유리할 수 있습니다.</p>
<br />
<br />


<h1 id="상수화로-관리하기">상수화로 관리하기</h1>
<p>메타데이터에 많은 내용을 적다보면 굉장히 길어집니다.
그러면 코드의 길이도 길어지고 덩달아 가독성이 떨어질 수 밖에 없습니다.</p>
<p>개인적으로 저는 한 파일의 코드 길이가 최대 100줄, 가능하다면 50 ~ 70줄 사이를 유지하길 선호하기 때문에 상수화해 관리하도록 했습니다.</p>
<br />

<p>들어가야 하는 내용을 전부 적은 후 이를 <code>constants/metadata.ts</code> 파일을 만들어 분리했습니다.</p>
<p>정적인 메타데이터(static meta-data)의 경우에는 아래와 같이 한 줄로 줄일 수 있습니다.</p>
<pre><code class="language-js">// 최상위 layout.tsx
export const metadata = DEFAULT_METADATA

// app/survey/page.tsx
export const metadata = SURVEY_METADATA</code></pre>
<br />

<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/639b0280-8810-4461-a2b2-986421cb8c36/image.png" alt=""></p>
<br />
<hr />
<br />

<p><em>References.</em></p>
<p>[🌍 officials]</p>
<ul>
<li><a href="https://nextjs.org/docs/app/building-your-application/optimizing/metadata">NextJS의 MetaData</a></li>
<li><a href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata">NextJS의 generateMetadata</a> ⭐️</li>
<li><a href="https://nextjs.org/docs/app/api-reference/file-conventions/metadata/opengraph-image#generate-images-using-code-js-ts-tsx">NextJS의 opengraph-image and twitter-image</a></li>
<li><a href="https://nextjs.org/learn/dashboard-app/adding-metadata">Learn NextJS - Chapter 16. Adding Metadata</a></li>
</ul>
<p>[👩🏻‍💻 blogs]</p>
<ul>
<li><a href="https://velog.io/@doeunnkimm_/%EB%8F%99%EC%A0%81%EC%9C%BC%EB%A1%9C-mete%EC%99%80-og%ED%83%9C%EA%B7%B8-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0-opengraph-image%EA%B9%8C%EC%A7%80">Next.js에서 동적으로 메타데이터와 오픈그래프 적용하기</a></li>
<li><a href="https://reactnext-central.xyz/blog/nextjs/metadata#google_vignette">Next.js에서 메타데이터 설정과 최적화 기법</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[사용자를 생각한 한 걸음, LCP ]]></title>
            <link>https://velog.io/@55555-jyeon/lcp</link>
            <guid>https://velog.io/@55555-jyeon/lcp</guid>
            <pubDate>Sun, 18 Aug 2024 05:13:45 GMT</pubDate>
            <description><![CDATA[<p>이전 게시글 <a href="https://velog.io/@55555-jyeon/React-optimise">&lt;React, 성능 최적화(feat. DevTools)&gt;</a>에서 성능 최적화에 대해 간략하게 포트폴리오의 lighthouse 점수를 올리며 다뤄본 적이 있습니다.</p>
<p>해당 게시글에서는 프로젝트를 진행하면서 가장 이미지가 많아 최적화가 시급했던 LCP에 대해서 자세히 다뤄보려고 합니다.</p>
<br />

<h5 id="✓-본격적인-내용-시작-전-간단히-짚고-넘어가기">✓ 본격적인 내용 시작 전 간단히 짚고 넘어가기</h5>
<h3 id="🤷🏻♀️-왜-최적화를-해야-하는가">🤷🏻‍♀️ 왜 최적화를 해야 하는가</h3>
<p>프로젝트를 해봤다면 &#39;최적화를 처음부터 신경써야지&#39;하고 초반에 마음을 먹었더라도 금방 뒷전으로 밀리게 되는 경험을 해본 적이 있을 겁니다.</p>
<p>버그나 에러를 해결하고 쌓인 일을 처리하다보면 자연스레 뒷전으로 밀려버리게 되기도 하고 성능 개선 자체도 한두 개를 고친다고 해결되는 문제가 아니기도 합니다.
또한 사용하고 있는 기기가 일반적인 사용자들에 비해 좋아 성능 이슈를 체감하지 못하는 경우가 있을 수도 있습니다.</p>
<br />

<p>하지만 사용자는 웹 페이지를 방문했을 때 빠르게 정보를 볼 수 있기를 기대합니다.
그리고 해당 웹 페이지를 방문한 목적을 달성하는데 문제가 없어야 하며 보안이 철저해 개인정보 유출과 같은 사고가 발생하지 않아야 합니다.</p>
<br />

<p>이렇게 개발자와 사용자가 서로 중요하게 생각하는 부분이 다를 수 있습니다.
사용자는 최신 기술로 만들어진 웹사이트인지 오래된 기술로 만들어진 웹사이트인지보다 사용하는데 불편함을 초래하는지가 더 중요하게 느껴질 것입니다.</p>
<p>예를 들면 리액트나 넥스트와 같은 최신 프레임워크 기반의 초기 렌더링 시간이 약 6초 정도 걸리는 웹 사이트보단 LAMP 스택 기반의 초기 렌더링 시간이 1초인 웹 사이트가 더 이용하기 편하게 느껴질 것이라는 겁니다.</p>
<p>특히 국내 사용자들은 외국에 비해 더욱 속도에 민감할 것이라 생각됩니다.</p>
<br />

<h3 id="🩺-핵심-웹-지표">🩺 핵심 웹 지표</h3>
<p>Core Web Vital, 핵심 웹 지표는 구글에서 만든 것으로 웹 사이트에서 뛰어난 사용자 경험을 제공하는 데 필수적인 지표를 말합니다.</p>
<br />

<h3 id="lcp">LCP</h3>
<p>그 중에서도 이번에 자세히 알아볼 내용은 Largest Contentful Paint(LCP)로 FID, CLS와 함께 세 가지 핵심 웹 지표로 꼽히는 항목입니다.</p>
<p>LCP는 페이지가 처음으로 로드(load)되는 시점부터 뷰 포트(view port) 내부에서 가장 큰 컨텐츠를 렌더링하는데 걸리는 시간을 뜻합니다.</p>
<br />

<p>뷰 포트 내부에서 가장 큰 컨텐트란 아래와 같은 항목들로 정의되어 있습니다. 
아래 5가지 항목들을 기준으로 측정되며 뷰 포트를 넘어가는 요소는 고려되지 않는다는 특징이 있습니다.</p>
<pre><code>① &lt;img /&gt;

② &lt;svg /&gt; 내부의 &lt;img /&gt;

③ &lt;video poster=&quot;&quot; /&gt;
    poster 속성을 가진 video 태그

④ url()을 통해 불러온 배경 이미지가 있는 요소

⑤ &lt;p&gt;, &lt;div /&gt;와 같이 inline text 요소를 포함하고 있는 block-level 요소</code></pre><br />
<br />


<h1 id="👩🏻💻-lcp-점수-올리기">👩🏻‍💻 LCP 점수 올리기</h1>
<h3 id="1️⃣-웬만하면-텍스트로">1️⃣ 웬만하면 텍스트로</h3>
<p>좋은 점수를 얻기 위한 가장 확실하고 간단한 방법은 뷰 포트 영역에 이미지가 아닌 문자열을 넣는 것입니다.</p>
<p>최적화가 된 이미지보단 아무래도 추가적인 리소스가 필요없는 텍스트가 더 빠르게 노출되기 때문입니다.
따라서 텍스트로 대체가 가능한 부분은 웬만하면 전부 텍스트를 사용하는 것이 좋습니다.</p>
<br />


<h3 id="2️⃣-이미지-최적화하기">2️⃣ 이미지 최적화하기</h3>
<p>이미지가 텍스트보다 직관적이고 강한 인상을 주기 때문에 첫 렌딩 페이지에 이미지가 없긴 힘들 겁니다. 따라서 전부 텍스트로 대체하기는 어렵겠죠.</p>
<p>그럼 이미지는 어떻게 처리하면 좋을까요?</p>
<br />

<h5 id="🟢-do">🟢 DO</h5>
<h4 id="🔖-img와-picture-태그-사용하기">🔖 img와 picture 태그 사용하기</h4>
<p>이미지는 브라우저의 preload scanner에 의해 먼저 발견되어 빠르게 요청이 일어납니다. 따라서 이미지 태그 내부의 리소스는 HTML 파싱이 미처 완료되지 않았더라도 스캐너가 병렬적으로 리소스를 다운로드하기 때문에 LCP 요소를 불러오는 좋은 방법 중 하나입니다.</p>
<br />

<blockquote>
<p>🧐 <strong>preload scanner</strong> ? <br />
preload scanner란 <strong>HTML을 파싱하는 단계</strong>를 멈추지 않고 
빠르게 미리 로딩하면 좋을 리소스를 찾아 <strong>함께 로딩하는 브라우저의 기능</strong>입니다.</p>
</blockquote>
<br />


<h4 id="🎥--video-태그-사용-시-poster-넣어주기">🎥  video 태그 사용 시 poster 넣어주기</h4>
<p>포스터는 사용자가 비디오 태그 요소를 재생 및 탐색하기 전에 보이게 되는 비디오 태그의 속성으로 적용 시 썸네일 이미지와 같은 역할을 합니다.
포스터는 이미지 태그와 마찬가지로 preload scanner에 의해 미리 로드되기 때문에 사용하는 것이 좋습니다.</p>
<br />
<br />


<h5 id="🔴-dont">🔴 DON&#39;T</h5>
<h4 id="🤙🏻-svg는-꼭-필요한-곳에만">🤙🏻 svg는 꼭 필요한 곳에만</h4>
<p>svg는 preload scanner에 의해 HTML을 파싱하는 단계에서 함께 로딩되지 않습니다.
따라서 LCP 점수를 깎기 때문에 꼭 사용해야 하는 경우가 아니라면 지양하는 것이 좋습니다.</p>
<br />

<h4 id="🙂↔️-url로-불러오는-이미지-지양하기">🙂‍↔️ url로 불러오는 이미지 지양하기</h4>
<p>background-image와 같이 url을 통해 이미지를 가져오는 경우도 LCP 점수를 깎는 요소 중 하나입니다.
CSS에 있는 리소스는 브라우저가 해당 리소스를 필요로 하는 DOM을 그릴 준비가 될 때까지 요청을 미루기 때문에 오래 걸립니다. 따라서 중요한 리소스에는 url을 통해 이미지를 가져오는 것은 지양하는 것이 좋습니다.</p>
<br />
<br />

<h5 id="🟡-cautions">🟡 Cautions</h5>
<h4 id="①-lazy-loading-지양">① lazy loading 지양</h4>
<p>lazy loading은 리소스를 &quot;중요하지 않음&quot;으로 표시하고 필요할 때만 로드하는 전략입니다.
lazy loading을 사용할 경우 로딩 속도를 늦추는 것이기 때문에 LCP 점수에는 영향이 없습니다.</p>
<p>다른 곳에 사용하는 것에는 큰 문제가 없지만 LCP에 적용이 될 뷰 포트 안의 이밎에 적용하는 것은 큰 의미가 없다는 것을 알아두면 좋을 것 같습니다.</p>
<blockquote>
<p>🔗 <a href="https://velog.io/@55555-jyeon/react-improve-performance">모아서 해? 나눠서 해?</a></p>
</blockquote>
<br />

<h4 id="②-csr보다는-ssr로">② CSR보다는 SSR로</h4>
<p>서버(server)에서 빌드(build)를 해서 가져온 HTML을 스캐너가 바로 읽어 LCP가 진행되는 것이 사용자가 가장 빠르게 화면을 볼 수 있는 방법입니다.</p>
<p>LCP가 클라이언트(client)에서 빌드될 경우 LCP는 HTML을 다운로드한 직후가 아닌 리액트 코드가 파싱된 다음에 진행되게 되기 때문에 늦어지게 됩니다.</p>
<p>따라서 사용자가 될 첫 뷰 포트는 서버에서 빌드할 수 있도록 하는 것이 좋습니다.</p>
<br/>

<h4 id="③-중요한-리소스는-직접-호스팅으로">③ 중요한 리소스는 직접 호스팅으로</h4>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/e3c80be1-d03b-46fa-9ac9-84f139d78f6f/image.png" alt=""></p>
<p><a href="https://cloudinary.com/">Cloudinary</a>와 같이 이미지를 최적화해주는 서비스를 이용하게 도면 이미지의 크기를 줄여주고 포맷도 변환이 가능합니다. 또한 압축해서 이미지를 관리할 수도 있습니다.</p>
<p>하지만 다른 출처(origin)에서 정제한 이미지를 가져오는 것은 최적화에 도움이 되지 않습니다. 다른 출처는 네트워크 연결부터 다시 수행해야 하기 때문에 그만큼 시간이 더 소요되기 때문입니다.</p>
<p>lazy loading과 마찬가지로 다른 출처에서 이미지를 정제하는 것은 중요한 리소스가 아닌 이미지에 적용하는 것이 좋습니다.</p>
<br />

<br />
<hr />
<br />

<p>References.</p>
<p>[📚 Books]</p>
<ul>
<li>모던 리액트 DeepDive </li>
</ul>
<p>[👩🏻‍💻 Blogs]</p>
<ul>
<li><a href="https://www.theteams.kr/teams/253107/post/71145">Cloudinary를 활용한 이미지 컨텐츠 관리</a></li>
<li><a href="https://hjk329.github.io/%EC%B5%9C%EC%A0%81%ED%99%94/improve-lcp/">[코어 웹 바이탈 최적화] LCP 최적화하기</a></li>
</ul>
<p>[🎥 Videos]</p>
<p>- </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React의 과거와 미래]]></title>
            <link>https://velog.io/@55555-jyeon/why-react</link>
            <guid>https://velog.io/@55555-jyeon/why-react</guid>
            <pubDate>Sun, 11 Aug 2024 09:07:31 GMT</pubDate>
            <description><![CDATA[<h6 id="본-게시글은-모던-리액트-deep-dive를-기반으로-작성되었습니다">본 게시글은 &lt;모던 리액트 Deep Dive&gt;를 기반으로 작성되었습니다.</h6>
<br />

<p>리액트의 동작 가이드에 관한 게시글을 작성하다가 왜 리액트에 대해서 배워야 하는지, 리액트는 어떤 흐름으로 발전해왔는지에 대해 먼저 알면 좋을 것 같아 알아보던 중 내용이 길어져 따로 분리하게 되었습니다.</p>
<p>뭔가를 공부하고 배운 내용을 정리한다기보다는 개인적으로 흥미로운 내용이라 생각해 공유하고 싶어 작성하게 되었습니다. 더욱 자세한 내용은 책을 구매하셔서 보면 좋을 것 같아요 :)</p>
<br />

<blockquote>
<p>🧐 <a href="https://velog.io/@55555-jyeon/react-render-guide">React의 동작 가이드</a> 보러 가기</p>
</blockquote>
<br />
<hr />
<br />


<h1 id="왜-react인가">왜 React인가?</h1>
<p>2011년 페이스북의 뉴스피드 페이지에서 처음 선보인 리액트는 현재 출시된 지 10년이 넘어 오랜 명맥을 이어가는 라이브러리로 자리 잡았습니다.</p>
<p>2021년, <a href="https://github.com/eGovFramework">전자정부 표준 프레임워크</a>의 프론트엔드 개발 도구로 리액트가 채택된 것으로 리액트의 안정성이 확보되었다는 사실도 다시 한 번 체감할 수 있습니다.</p>
<p>아래는 2024년 스택 오버플로우에서 제공하는 개발자들이 사용하고 있는 웹 프레임워크와 기술에 대한 응답 그래프입니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/bb821335-e900-4a92-9eb4-18ed171641bd/image.png" alt=""></p>
<p>표에 대한 스택 오버플로우의 글을 번역하자면 :</p>
<pre><code>Node.js와 React.js는 모든 응답자들이 가장 많이 사용하는 두 가지 웹 기술입니다. 
전문 개발자들은 두 기술을 거의 동일하게 사용하고 있으며, 코딩을 배우는 사람들은 React.js보다 Node.js를 더 많이 사용하고 있습니다(52% 대 48%).

jQuery와 Express는 그 다음으로 인기 있는 웹 기술이며, jQuery는 코딩을 배우는 사람들보다는 전문 개발자들이 더 많이 사용하고 있습니다(24% 대 18%). 
반면, Express는 전문 개발자들보다 코딩을 배우는 사람들이 더 많이 사용하고 있습니다(25% 대 20%).

Next.js는 2022년 11위에서 올해 6위로 상승했으며, 이는 코딩을 배우는 사람들 사이에서의 인기가 주된 원인으로 보입니다.</code></pre><br />

<p>제이쿼리(jQuery)의 인기를 2018년을 기점으로 무너뜨린 리액트의 인기는 당분간 식지 않을 것 같습니다. 일부 기사에서는 리액트의 이런 시장 점유율에 대해 &quot;프론트엔드 시장을 완전히 점령했다&quot;라고 표현하기도 합니다. 기술이나 언어의 트렌드와 선호도는 영원할 수 없지만 리액트의 독주 체제가 당장 끝날 것 같지는 않아 보입니다.</p>
<br />

<h3 id="리액트의-장점">리액트의 장점</h3>
<p>리액트는 왜 많은 개발자들이 선호하는 라이브러리가 될 수 있었을까요?</p>
<p>많은 개발자들의 사랑을 받는데에는 다양한 이유가 있겠지만 그 중 몇 개를 꼽자면 아래와 같을 것입니다.</p>
<h4 id="1️⃣-명시적인-상태-변경">1️⃣ 명시적인 상태 변경</h4>
<p>리액트는 <strong>단방향 바인딩만을 지원</strong>합니다.
단방향 바인딩이란 데이터의 흐름이 한쪽으로만 간다는 것입니다.</p>
<p>그렇다면 왜 단방향 바인딩이 장점이 될까요?</p>
<p>이는 Angular에서 지원하는 양방향 바인딩으로 설명할 수 있습니다.
양방향으로 바인딩이 되면 뷰(view)의 변화가 컴포넌트에 영향을 미칠 수 있을 뿐만 아니라 컴포넌트의 상태가 변경되면 뷰의 상태도 변할 수 있습니다.</p>
<p>양방향 바인딩은 단방향이 제공할 수 없는 편리함을 제공하는 반면 코드의 규모가 커질수록 상태의 변화의 원인을 찾기 어려워진다는 문제가 수반됩니다.</p>
<p>반면에 리액트의 상태 변화는 단방향이기 때문에 상태의 변화가 명시적으로 이뤄지는 것입니다. 상태가 변화했다면 그 상태 변화를 명시적으로 일으킨 함수만 찾으면 되기 때문입니다.</p>
<p>결국 이런 리액트의 명시적인 상태 업데이트는 많은 개발자들에게 <strong>간단함과 유연함을 제공</strong>합니다.</p>
<p>양방향 바인딩이 항상 불편하기만 한 것은 아니지만 단방향 바인딩이 양방향 바인딩에 비해 데이터 흐름의 변화가 단순하기 때문에 비교적 코드가 쉽게 읽히고 버그가 발생할 가능성이 비교적 적다는 것입니다.</p>
<br />

<h4 id="2️⃣-jsx의-사용-간편한-접근">2️⃣ JSX의 사용, 간편한 접근</h4>
<p>리액트는 HTML에 JS 문법을 더한 JSX(JavaScript XML)를 사용하는데 이는 기존에 알고 있는 JS 문법에 HTML을 약간 가미한 수준이었습니다. 따라서 고유의 몇 가지 특징만 이해한다면 손쉽게 JSX 코드를 구현할 수 있었습니다.</p>
<p>반면에 Angular는 뷰를 표현하기 위해 문자열 템플릿(string template)과 디렉티브라는 angular 전용 문법을 익혀야 합니다.</p>
<p>리액트도 배우다보면 공부할 것이 많지만 초반의 러닝 커브가 낮아 처음 접하느 사람도 손쉽게 리액트 기반 프로젝트를 할 수 있습니다.</p>
<br />

<h4 id="3️⃣-강력한-커뮤니티-그리고-메타meta">3️⃣ 강력한 커뮤니티, 그리고 메타(meta)</h4>
<p>리액트는 단순히 UI를 위한 라이브러리로만 작동함으로써 그 역할에 제한을 두고 그 외의 모든 것에 자유도를 두었습니다. 따라서 개발자들은 리액트를 기반으로 다양한 것을 시도해볼 수 있었고 그만큼 리액트는 커다란 커뮤니티를 얻게 되었습니다.</p>
<p>그리고 이런 커뮤니티는 내부에서 직접 겪은 이슈들과 문제를 공유하면서 리액트를 사용하는 사람들이 같은 어려움을 겪지 않도록 빠르게 도와주는 역할도 하게 되었습니다.</p>
<p>나아가 리액트 핵심 개발을 메타가 적극적으로 지원했기 때문에 10여 년 동안 꾸준히 발전할 수 있었습니다. </p>
<br />

<h4 id="리액트가-최선인가">리액트가 최선인가?</h4>
<p>리액트는 단순히 현재 가장 많은 개발자들이 사용하는 라이브러리일 뿐, 가장 완벽하지도, 가장 빠르지도, 가장 합리적이지도 않습니다.</p>
<p>프론트엔드 커뮤니티에는 리액트에 대해 부정적인 의견을 가진 개발자들도 다수 존재하고, Svelte나 Vue와 같은 대안도 있으니까요.</p>
<p>그럼에도 불구하고 리액트는 이미 수많은 커뮤니티에서 이미 다양한 기능을 개발했기 때문에 참고할 자료가 많으며 커뮤니티가 활발합니다. 또한 채용시장과 기업에서도 매우 호의적이기 때문에 당분간은 리액트를 공부하는 것이 탁월한 선택일 수 있습니다.</p>
<br />
<br />

<h1 id="react의-역사">React의 역사</h1>
<h3 id="2010년대-페이스북의-도전">2010년대, 페이스북의 도전</h3>
<h4 id="lamp-스택-기반-웹-개발">LAMP 스택 기반 웹 개발</h4>
<p>2010년대의 웹 생태계는 어땠을까요?
2000년대까지만 해도 웹 생태계는 LAMP 스택이라고 하는 리눅스(Linux), 아파치(Apache) 웹서버, MySQL, PHP를 활용한 웹 개발이 주를 이루고 있었습니다.</p>
<p>LAMP 스택 기반의 웹 개발은 사용하는 프레임워크에 따라 차이가 있겠지만 대부분 DB에서 필요한 데이터를 불러온 다음, 웹 서버에서 HTML 페이지를 만들어 클라이언트에게 제공하는 방식으로 작동합니다.</p>
<p>조금 더 상세히 말하자면, 콘텐츠는 사용자나 다른 환경에 따라 서버에서 동적으로 생성하고, 웹 브라우저는 이를 단순히 다운로드 받아 렌더링하며 자바스크립트는 폼 처리와 같은 부수적인 역할만 하는 방식이었습니다.</p>
<h4 id="2010년-브라우저-환경의-급변">2010년, 브라우저 환경의 급변</h4>
<p>이러한 수동적인 프론트엔드의 역할은 2010년대에 들어서면서 조금씩 변하기 시작했습니다. 자바스크립트를 좀 더 편리하게 사용하기 위해 등장한 제이쿼리(jQuery)는 수많은 프로그인과 함께 인기를 얻기 시작하면서 점차 자바스크립트의 비공식 표준으로 자리 잡았습니다.</p>
<p>이와 더불어 Internet Explorer 8에서 등장한 로컬 스토리지(local storage), 2011년 공식적으로 표준으로 등록된 웹소켓(WebSocket), 자바스크립트로 그래픽을 표현할 수 있도록 도와주는 캔버스(Canvas),  백터 그래픽을 표현할 수 있는 SVG, 사용자의 위치를 알 수 있는 지오로케이션(Geolocation) 등 브라우저에서 다양한 기능을 지원하기 시작했습니다.
또한 ECMAScript5(ES5)가 처음으로 표준 스펙으로 자리 잡았습니다.</p>
<p>이런 브라우저의 생태계의 변화에 맞춰 브라우저의 환경도 급변하기 시작했습니다.
자바스크립트는 적극적으로 DOM을 수정해 사용자에게 다양한 인터렉션을 보여주었고, Ajax를 활용해 클라이언트에서도 서버와 통신해 데이터를 불러오기 시작했습니다. 이에 따라 자바스크립트 코드가 점차 복잡해지기 시작했습니다.</p>
<h4 id="복잡해지는-js와-성능-이슈">복잡해지는 JS와 성능 이슈</h4>
<p>자바스크립트 코드가 복잡해짐에 따라 구글에서는 AngularJS를, 제레미 아쉬케나스의 Backbone.js가 등장했습니다.
두 프레임워크는 비슷한 시기에 릴리즈(release)됐고, 각각 MVVM, MVC 패턴을 기반으로 복잡해지는 자바스크립트 코드를 체계화하고자 했습니다.</p>
<h4 id="2010년대-페이스북의-상황">2010년대, 페이스북의 상황</h4>
<p>이때 페이스북은 전 세계적으로 인기 있는 소셜 네트워크 서비스(SNS)로 자리잡은 상태였습니다. 전례 없는 많은 사용자가 이용하는 서비스였던만큼, 성능이 무엇보다 중요했습니다. </p>
<p>페이스북은 이를 위해 최대한 서버에서 렌더링을 하는 기술을 사용했고 자바스크립트 번들 사이즈를 줄이는데 심혈을 기울이고 있었습니다.</p>
<p>자바스크립트의 번들 사이즈를 줄이기 위해선 자바스크립트는 반드시 필요한 곳에서만 제한적으로 사용이 돼야 했습니다. 자바스크립트 코드의 크기가 커질수록 이를 다운로드하고 파싱하고 실행해야 하는 브라우저의 부담도 덩달아 커질 수 밖에 없기 때문입니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/808b4bc6-1e03-4819-a9c0-5a5565b754d1/image.png" alt=""></p>
<p>위는 2011년, 페이스북에서 처음 선보인 타임라인 페이지입니다.</p>
<p>타임라인에서는 자신의 상태를 업로드할 수 있고, 다른 사람들의 댓글이 추가되는 것을 실시간으로 확인할 수 있습니다.</p>
<p>이런 작업을 모두 서버 렌더링으로만 작동시키면 어떤 일이 발생할까요?</p>
<p>사용자가 글을 하나 올릴 때마다 매번 새로운 페이지를 보여주기 위해 서버에서 렌더링할 것이고, 이런 작동은 브라우저 전체가 다시 로딩되며 전체 화면이 깜빡이거나 느리게 동작하는 것처럼 보여지게될 것입니다.</p>
<p>타임라인 뿐만 아니라 페이스북에는 실시간성을 강조하는 기능이 곳곳에 추가되어 있었기 때문에 자바스크립트에 대한 의존성을 피할 수 없었습니다.</p>
<h4 id="애플의-규제에-대항하는-스파르탄-프로젝트">애플의 규제에 대항하는 스파르탄 프로젝트</h4>
<p>스파르탄 프로젝트는 애플의 강력한 앱 규제에 반발해 만들어진 프로젝트로, 페이스북 iOS 앱 대신 애플의 사파리(WebKit)에서 작동할 수 있는 페이스북을 만들기 위해 추진됐습니다.</p>
<p>이 프로젝트를 통해 페이스북을 앱 스토어에 등록할 필요 없게 되면서 애플의 앱스토어 규제를 벗어나는 것이 목표였습니다. 또한 이 무렵 등장한 HTML5는 표준만 잘 지킬 경우 PC, 모바일 환경에 상관 없이 모두 동일한 서비스를 제공할 수 있는 가능성이 제시되었습니다.</p>
<p>그래서 페이스북 팀은 HTML5를 기반으로 페이스북을 완전히 재작성하는 스파르탄 프로젝트를 시작하게 됩니다. 결과만 전달하자면, 스파트란 프로젝트는 실패했음을 마크 주크버그가 공식적으로 선언한 바 있습니다.</p>
<h4 id="boltjs의-등장과-한계">BoltJS의 등장과 한계</h4>
<p>페이스북은 당시 존재하던 옵션들로는 사용자에게 만족스러운 경험을 주기 어렵다고 판단했고 BoltJS라는 새로운 프레임워크를 만들기 시작했습니다.</p>
<p>BoltJS는 <code>createClass</code>로 내부에 객체를 선언해 컴포넌트를 만드는 방식을 사용했으며 이는 리액트의 초기 버전의 <code>React.createClass</code>가 이어받게 됩니다.</p>
<p>BoltJS는 잠깐 깃허브를 통해 공개되었지만 이내 설명 없이 소스코드가 삭제됩니다. BoltJS의 개선을 위한 아이디어 중 하나인 Functional Bolt, 즉 Fbolt는 리액트의 시초가 됩니다.</p>
<h4 id="파격적인-접근법-ui의-초기화와-리렌더링">파격적인 접근법: UI의 초기화와 리렌더링</h4>
<p>이 당시 제안됐던 아이디어 중 하나는 애플리케이션에서 API의 변화에 따라 무언가 변경되면 단순히 UI를 초기화하고 새로 렌더링하자는 것이었습니다.</p>
<p>당시 이러한 접근법은 매우 파격적이었고 이러한 방식이 성능을 보장할 수 있을지 의구심을 갖는 개발자들이 많았습니다.</p>
<p>왜냐하면 DOM의 변경을 최소한으로 하는 것이 성능을 위한 최선의 방법으로 여겨졌던 시기였기 때문입니다. 당시의 대부분의 프레임워크는 양방향 바인딩 구조를 채택해 모델과 뷰가 밀접한 관계를 맺고 서로가 서로를 변경할 수 있는 구조이기도 했습니다.</p>
<p>하지만 페이스북 프론트엔드 팀들이 느끼는 가장 큰 어려움은 DOM을 업데이트하는 거였습니다. 따라서 성능을 둘째치더라도 새롭게 렌더링해 버리는 방법을 긍적적으로 검토해보게 되었고 이어 리액트 프로젝트가 시작되게 됩니다.</p>
<br />

<h4 id="페이스북의-대안-리액트">페이스북의 대안, 리액트</h4>
<p>페이스북에서 리액트와 리액트를 기반으로 하는 프로젝트가 개발되고 있을 즈음 페이스북은 인스타그램을 인수하게 됩니다. 당시 인스타그램은 iOS와 안드로이드 버전 밖에 없었지만, 페이스북의 웹 기반 개발에 맞춰 인스타그램을 웹으로 만드는 작업에 착수했습니다.</p>
<p>인스타그램 팀은 몇 가지의 선택지 중 리액트의 아이디어에 감명을 받고 리액트로 개발을 시작하게 됩니다.</p>
<p>처음부터 리액트로 만들어진 인스타그램과 페이스북의 일부가 리액트로 조금씩 대체되기 시작하면서 페이스북 개발자들은 리액트에 대한 자신을 얻기 시작합니다.
그리고 동시에 리액트를 오픈소스로 공개하고자 하는 노력이 함께 이뤄집니다.</p>
<p>과거 BoltJS와 마찬가지로 많은 프로젝트들이 오픈소스로 공개되었지만 제대로 관리되지 않아 방치되는 사례가 많았습니다. 따라서 리액트의 경우에는 인스타그램 팀에게 제공했던 것처럼 <strong>문서화에 심혈</strong>을 기울였습니다. </p>
<p>그리고 이러한 리액트를 공개할 무대로 JSConf US를 선택했고, 여기에서 리액트와 함께 embedded XML인 JSX도 함께 공개하게 됩니다.</p>
<br />

<h4 id="회의적인-반응과-비판받는-리액트">회의적인 반응과 비판받는 리액트</h4>
<p>당시에는 HTML과 JS의 분리가 관심사 분리의 원칙의 가장 기초적인 사실로 받아들여졌기 때문에 두 가지를 합치는 JSX는 말도 안 되는 것으로 보여졌습니다.</p>
<p>사실 리액트의 구조도 관심사 분리의 원칙을 따르긴 합니다.
당시의 관심사 분리는 파일의 역할별로 관심사를 분리하는 것에 초점이 맞춰져 있던 반면, 리액트의 관심사 분리는 컴포넌트의 역할에 따라 관심사가 분리돼 있을 뿐이었습니다.</p>
<p>하지만 페이스북에서 제시한 JSX라는 새로운 문법과 문법 내에서 혼재돼 있는 자바스크립트 코드에 대한 거부감 때문에 반응은 좋지 못했습니다.</p>
<p>이러한 사건으로 인해 페이스북 팀은 일반적인 웹 개발자에게 리액트를 소개하는 방법에 대해 다시 고민하기 시작했습니다.</p>
<br />

<h4 id="커뮤니티로-새로운-원동력을-얻다">커뮤니티로 새로운 원동력을 얻다</h4>
<p>일부 리액트의 접근 방식에 흥미를 느낀 개발자들은 리액트에 새로운 아이디어와 활기를 불어넣기 시작하며 새로운 원동력을 얻게 됩니다.</p>
<p>페이스북 밖의 오픈소스 기여자들로부터 많은 아이디어와 도움을 받기 시작하면서 오픈소스로 전환한 리액트는 빛을 보기 시작합니다.</p>
<p>외부의 도움을 받는 것의 장점을 깨달은 페이스북 팀은 리액트 커뮤니티를 형성하는데 노력을 기울이기 시작합니다. 커뮤니티 소식지를 올리면서 페이스북 팀 밖에서 일어나는 리액트와 관련된 글을 공유했고, 리액트 개발자들 또한 마찬가지로 번갈아가며 글을 작성하고 인터뷰에 참여했습니다.</p>
<p>리액트 커뮤니티는 리액트가 제공하지 못한 것을 채워주기 위해 다양한 라이브러리들과 프레임워크들이 등장하기 시작했고 이는 리액트가 프론트엔드 생태계에 자리 잡을 수 있도록 도와주게 됩니다.</p>
<p>그러면서 점차 리액트의 성장을 IT 기업들이 눈여겨 보기 시작했고, 채택하는 곳이 늘어났습니다.</p>
<br />

<h4 id="넷플릭스의-선택을-받은-리액트">넷플릭스의 선택을 받은 리액트</h4>
<p>넷플릭스는 원래 자바를 기반으로 만들어졌지만 여러 가지 문제점을 안고 있었습니다.</p>
<pre><code>1. 최초 상호작용에 걸리는 시간이 평균적으로 5초 정도 소요
2. 웹사이트 빌드 시간이 20분 소요
3. 기능 추가에 오랜 시간이 걸림</code></pre><p>넷플릭스 팀은 새로운 UI에 맞춰 새로운 웹사이트를 만들고자 모던 프레임워크 도입을 고민하고 있었습니다. </p>
<p>당시에는 리액트가 페이스북 외의 성공 사례가 없었으므로 넷플릭스는 확신을 얻기 위해 개발자를 두 팀으로 나눠 각각 리액트와 백본으로 프로토타입을 만들게 됩니다.</p>
<p>그리고 이러한 과정을 통해 리액트에는 몇 가지 더 확실한 장점이 있음을 깨닫게 됩니다. 위에도 언급한 부분이지만 넷플릭스 기준으로 다시 한 번 정리하자면 :</p>
<h5 id="1️⃣-간결한-자바스크립트-코드">1️⃣ 간결한 자바스크립트 코드</h5>
<p>상태를 관리하기 위한 컨트롤러(controller) 대신 리액트는 단시 상태에 따른 UI를 선언적으로 구현할 수 있었기 때문에 코드를 더 간결하게 작성할 수 있었습니다.</p>
<p>이렇게 복잡성을 줄인 것만으로도 전체 코드의 크기를 확연하게 줄일 수 있었고 그 결과 최초 상호작용에 걸리는 시간이 5초에서 1.5초로 감소하게 됩니다.</p>
<h5 id="2️⃣-상대적으로-완만한-학습-곡선">2️⃣ 상대적으로 완만한 학습 곡선</h5>
<p>자바스크립트와 HTML만 알면 손쉽게 리액트 코드를 작성할 수 있었습니다.</p>
<h5 id="3️⃣-빠른-기능-추가">3️⃣ 빠른 기능 추가</h5>
<p>과거에는 새로운 기능을 보여주기 위해서 사이트를 빌드하고 배포해야 했지만 리액트는 자바 애플리케이션에 비해 기능을 추가하고 빌드하는 시간이 훨씬 빨랐습니다.</p>
<p>이렇게 빠른 빌드는 기획자들에게 새로운 기능을 보여주고 확인받는 데 걸리는 시간을 줄여주었습니다.</p>
<br />

<p>이러한 장점들을 기반으로 넷플릭스는 리액트로 웹사이트를 만들었고, 전 세계에서 두 번째로 큰 IT 회사가 리액트의 생태계로 뛰어듦으로써 리액트는 프론트엔드 시장에서 전성기를 맞게 됩니다.</p>
<br />
<br />

<h1 id="react의-현재와-미래">React의 현재와 미래</h1>
<h3 id="react의-현재">React의 현재</h3>
<p>리액트는 현재 가장 인기 있는 프레임워크로 자리 잡고 있으며 다른 라이브러리들과 다르게 웹 개발을 위한 프레임워크를 지향하지 않기 때문에 함께 상요할 수 있는 다양한 라이브러리가 존재합니다.</p>
<pre><code>상태 관리 라이브러리
Redux, Zustand, Recoil, Jotai ...

서버 사이드 렌더링
Next.js, Remix, Hydrogen ...

애니메이션
Framer Motion, react-spring, React Move ...

차트
ReCharts, visx, mivo ...

폼
React Hook Form, Forkmik, React Final Form ...</code></pre><p>이 밖에도 많은 라이브러리가 있고 react라는 이름이나 태그를 갖고 있는 npm 패키지 또한 현재 23만여 개가 존재합니다.</p>
<p>2021년에 실시된 조사에 따르면 웹 개발자가 선호하는 프레임워크 순위에서 리액트와 리액트를 기반으로 한 서버 사이드 렌더링 프레임워크인 넥스트가 나란히 1, 2위를 차지한 것을 보면 그 인기를 실감할 수 있습니다.</p>
<p>국내 IT 업계에서도 토스와 카카오가 리액트를 사용하고 있으며, 네이버의 경우 조직별로 차이가 있겠지만 네이버 PC 메인과 지도 메인을 리액트로 변경했습니다.</p>
<br />

<h3 id="리액트의-미래">리액트의 미래</h3>
<p>과거 리액트는 클라이언트에 초점을 맞추고 있었고, 앞으로도 브라우저와 클라이언트의 작동을 개선할 예정이라고 밝힌 바 있습니다.</p>
<p>추가적으로 리액트 팀은 클라이언트에서는 할 수 없었던 서버에서의 작업과 서버 환경이 갖고 있는 가능성에 무게를 두고 앞으로도 서버에서 작동할 수 있는 당야한 기능이나 유스케이스를 추가할 것으로 보입니다.</p>
<p>따라서 앞으로도 리액트를 계속 공부할 예정인 프론트엔드 개발자들은 서버 환경을 공부하느 것이 도움이 될 것으로 보입니다.</p>
<br />
<hr />

<p><em>References.</em></p>
<p>[📖 books]</p>
<ul>
<li>modern react Deep Dive</li>
</ul>
<p>[👩🏻‍💻  blogs]</p>
<ul>
<li><a href="https://survey.stackoverflow.co/2023/#methodology">stack overflow</a></li>
<li><a href="https://yozm.wishket.com/magazine/detail/2364/">2023년 회고와 2024년 웹 개발 트렌드 전망</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[당신의 여행을 Yeogi(여기)에 ]]></title>
            <link>https://velog.io/@55555-jyeon/%EB%8B%B9%EC%8B%A0%EC%9D%98-%EC%97%AC%ED%96%89%EC%9D%84-Yeogi%EC%97%AC%EA%B8%B0%EC%97%90</link>
            <guid>https://velog.io/@55555-jyeon/%EB%8B%B9%EC%8B%A0%EC%9D%98-%EC%97%AC%ED%96%89%EC%9D%84-Yeogi%EC%97%AC%EA%B8%B0%EC%97%90</guid>
            <pubDate>Sat, 03 Aug 2024 10:01:20 GMT</pubDate>
            <description><![CDATA[<h5 id="나의-첫-번째-프로젝트--yeogi">나의 첫 번째 프로젝트 : Yeogi</h5>
<blockquote>
<p>모비 내부에서 외부 인력을 구해 진행한 Yeogi를 통해 처음으로 실제 각 파트의 담당자들과 함께 협업할 수 있었던 프로젝트였습니다. <br />
같이 공부를 하며 이미 친분이 있던 동료들(모비 2기)과 하던 이전 프로젝트들과 달리 프로젝트 제작을 위해 모인 분들과 진행한 첫 프로젝트라 첫 번째 프로젝트라고 명명했습니다. 👀</p>
</blockquote>
<br />
<br />


<h2 id="yeogi">Yeogi?</h2>
<h4 id="기획-의도">기획 의도</h4>
<h6 id="아래는-지극히-개인적인-경험에-의한-생각입니다-😮">아래는 지극히 개인적인 경험에 의한 생각입니다 😮</h6>
<p>개인적으로 여행을 좋아하기 때문에 자연스럽게 주제를 공유할 때 여행과 관련된 사항들을 떠올리게 되었습니다.</p>
<p>다양한 나라를 방문하게 될 경우, 나라마다 정보를 얻는 루트가 조금씩 달라집니다.</p>
<p>한국인들이 많이 방문하는 여행지의 경우에는 정말 다양한 플랫폼을 통해서 정보를 얻을 수 있지만, 그렇지 않은 경우에는 대부분 네이버 카페를 통해 얻어야 하는 경우가 많습니다.</p>
<p>카페를 통해 정보를 얻는 과정에서 제가 느꼈던 불편함은 크게 아래와 같았습니다 : </p>
<blockquote>
<p>1️⃣ 정보를 얻거나 댓글을 달기 위해선 등급을 유지하기 위한 조건을 주기적으로 체크해야 한다. <br />
2️⃣ 다른 나라를 방문하는 경우, 카페를 여러 군데 가입해야 한다.</p>
</blockquote>
<p>또한 개인 블로그, 인스타그램, 유튜브 등 다양한 플랫폼을 참고할수록 내용이 방대해지게 되고 덩달아 계획을 세우는 시간도 늘어나게 되는 부분이 번거롭다고 느껴졌습니다.</p>
<p>나아가 여행의 일정을 관리하는 사이트도 있었고, 예약을 관리해주는 사이트도 있었지만 각국의 모든 정보를 얻는 사이트는 찾기 어려웠습니다.</p>
<p>보통 여행과 관련된 내용을 기록하는 사람들은 여행이 취미인 경우가 대부분일 거라 생각되었고 이들을 한 군데에 모을 수 있다면 정보를 교환하는데 좀 더 편리하지 않을까 하는 생각이 들었습니다.</p>
<br />
<br />

<p>
<img src="https://github.com/mobi-projects/yeogi-client/assets/134191817/6ce60050-7ab0-44a6-b51d-f87d19485e39" 
alt="yeogi logo" />  
</p>

<h2 id="yeogi-여기에-여행을-기록하세요">Yeogi, 여기에 여행을 기록하세요</h2>
<h4 id="서비스-소개">서비스 소개</h4>
<img src="https://github.com/mobi-projects/yeogi-client/assets/134191817/2e6b2ca4-fa61-48a6-aa07-f9f2a40d25b5" alt="yeogi main page" />


<p>&#39;내&#39;가 여행을 추억하기 위해 작성한 게시글이 다른 사람들에겐 여행 정보가 됩니다. Yeogi(여기)는 여행을 좋아하는 사람들의 추억이 모여 곧 정보가 되는 웹 사이트입니다.</p>
<blockquote>
<p>🔗 <a href="https://www.figma.com/design/VoBkptzgv2kOQYvWmfO0ln/%EC%97%AC%EA%B8%B0-%EA%B8%B0%ED%9A%8D%EC%84%9C?node-id=0-1&amp;t=2FSVTDbW9uIsp8ZN-1">Yeogi(여기) 기획서</a>에서 더 자세한 내용 살펴보기</p>
</blockquote>
<br />

<h4 id="🗓️-개발-기간">🗓️ 개발 기간</h4>
<p>모비 내에서 약 두 달동안 프로젝트를 진행했습니다. 
매주 정해진 기획과 관련된 서류들을 제출하느라 스파게티 코드처럼 지저분하게 짜여진 코드들이 많아 프로젝트가 끝난 후 2주동안 급하게 쓴 코드들을 리팩터링하는 시간 및 휴식 시간을 가졌습니다.
8월부터 다시 프로젝트 마무리를 위해 계속 진행될 예정입니다.</p>
<br />

<h5 id="detail-terms">detail terms</h5>
<h6 id="모비-내-프로젝트-전체-진행-기간">모비 내 프로젝트 전체 진행 기간</h6>
<p>전체 기간 : 2024.05.25 ~ 2024.09.01</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/8d8f8b8b-1109-49af-a30d-2d875e8efe98/image.png" alt=""></p>
<blockquote>
<p>07/21 <a href="https://www.figma.com/slides/3ubz8IFlNW7tzkRXGJL2Y4/Yeogi-Presentation?node-id=11-2165&amp;t=2KtuJdu2AMiyIsOw-1">최종 발표</a> 및 회식</p>
</blockquote>
<br />

<h6 id="refactoring-및-re-fresh-기간">refactoring 및 re-fresh 기간</h6>
<p>2024.07.21 ~ 2024.07.31</p>
<h6 id="추가-진행">추가 진행</h6>
<p>2024.08.01 ~ ing</p>
<br />

<h4 id="👥-yeogi-crew">👥 Yeogi Crew</h4>
<p>Yeogi(여기)는 총 7명의 인원이 참여한 프로젝트입니다.
고정 회의는 한 주에 최소 세 번 가졌습니다.</p>
<p>1️⃣ 주에 한 번, 팀별 회의를 진행해 서로의 진행 상황을 공유합니다.</p>
<p>2️⃣ 주에 한 번, 해당 팀마다 대표 한 명이 스테이크 홀더(👑)로써 스테이크 회의를 진행합니다.</p>
<p>3️⃣ 주에 한 번, 전체 회의를 통해 차주의 sprint를 정합니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/2b367d93-92a7-47b4-b21a-f5e50643fb4c/image.png" alt=""></p>
<img src="https://img.shields.io/badge/discord-5865F2?style=flat-square&logo=discord&logoColor=white" />
<img src="https://img.shields.io/badge/jira-0052CC?style=flat-square&logo=jira&logoColor=white" />



<blockquote>
<p>배포 주소는 <a href="https://yeogi-client.vercel.app/">여기</a></p>
</blockquote>
<h5 id="designer">Designer</h5>
<p>👑 <a href="https://www.behance.net/saltkik"><strong>Jayden</strong></a></p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/24ac8124-5977-413f-8fb8-b807288888c2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/4bb78da2-6d32-4e5f-8771-cb55c9032f24/image.png" alt=""></p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/2e69e71a-7863-4b3d-95f9-8fd2e53ccc20/image.png" alt="">화면 설계서</th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/fb090ac0-ad61-4f90-b243-f883088e8828/image.png" alt=""> 디자인</th>
</tr>
</thead>
</table>
<img src="https://img.shields.io/badge/figma-F24E1E?style=flat-square&logo=figma&logoColor=white" />


<blockquote>
<p>피그마로 된 디자인을 보려면 <a href="https://www.figma.com/design/TQX56AWMGdAT5DYDpmWKBk/YeoGi?node-id=0-1&amp;t=QT5c3yGsTOHMJmk8-1">여기</a></p>
</blockquote>
<h5 id="fe-team">FE team</h5>
<p><a href="https://github.com/55555-Jyeon"><strong>Amy</strong></a>, 👑 <a href="https://github.com/ijimlnosk"><strong>Gang</strong></a>, <a href="https://github.com/hayoung78"><strong>Wendy</strong></a></p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/a4300e1e-fbfb-41fa-a788-2e50b04c3d7b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/9c8e20e7-610d-4fa4-8fe8-e376281f5dc0/image.png" alt=""></p>
<img src="https://img.shields.io/badge/next.js-000?style=flat-square&logo=next.js&logoColor=white" />
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white" />

<blockquote>
<p>FE gitHub는 <a href="https://github.com/mobi-projects/yeogi-client">여기</a></p>
</blockquote>
<h5 id="be-team">BE team</h5>
<p><a href="https://github.com/ca1af"><strong>DK</strong></a>, <a href="https://github.com/Yejun4911"><strong>Jun</strong></a>, 👑 <a href="https://github.com/Kwonnamhyung"><strong>Louis</strong></a></p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/c6f76115-0b71-4e34-9314-599cfd8d6501/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/874f9dc3-87ab-46f9-a1de-ac42bf39a417/image.png" alt=""></p>
<img src="https://img.shields.io/badge/Spring-6DB33F?style=flat-square&logo=Spring&logoColor=white" />
<img src="https://img.shields.io/badge/java-007396?style=flat-square" />

<blockquote>
<p>BE gitHub는 <a href="https://github.com/mobi-projects/yeogi-server">여기</a></p>
</blockquote>
<br />
<br />

<h2 id="fe-team-part">FE team Part</h2>
<p>프론트엔드 팀에서 가져가고자 했던 점은 NextJS의 장점을 살리는 프로젝트를 만드는 것이었습니다. 또한 사용자 경험과 성능 향상을 위해 skeleton UI 사용 및 layout shift 해결에 신경을 썼습니다.</p>
<br />

<h3 id="nextjs-적극-활용">NextJS 적극 활용</h3>
<h4 id="1️⃣-rsc--ssr-query-fetching">1️⃣ RSC &amp; SSR query fetching</h4>
<p>NextJS는 RSC와 SSR을 통해 뛰어난 성능과 사용자 경험을 제공합니다. 이는 순수 리액트에서는 제공하기 어려운 몇 가지 핵심 기능들을 가능하게 합니다.</p>
<p>이러한 기능들을 통해 저희는 빠르고 효율적인 웹 애플리케이션 구축과 더불어 최적화된 사용자 경험을 제공하고자 했습니다.</p>
<br />

<blockquote>
<p><strong>RSC</strong> (React Server Components) </p>
</blockquote>
<ul>
<li>서버에서 렌더링되고 실행되는 컴포넌트</li>
<li>초기 로딩 속도 개선 가능</li>
<li>서버의 리소스 활용 가능</li>
<li>데이터베이스나 파일 시스템에 직접 접근 → API 호출 없이 데이터 패칭 가능</li>
</ul>
<p>순수 리액트 환경에서는 클라이언트에서 데이터 패칭을 위해 반드시 API 호출이 필요한 반면 NextJS의 RSC를 활용하면 서버 리소스를 직접 활용이 가능하다는 장점이 있습니다.</p>
<blockquote>
<p><strong>SSR</strong> (Server-Side Rendering) </p>
</blockquote>
<ul>
<li>서버에서 페이지의 초기 HTML을 생성하는 기술</li>
<li>초기 로딩 시간을 단축</li>
<li>SEO를 개선 가능</li>
<li>동적 콘텐츠를 포함한 전체 페이지를 서버에서 렌더링 클라이언트로 전송</li>
</ul>
<p>순수 리액트에서는 CSR을 기본으로 하기 때문에 초기 로딩 시 JS가 모두 로드(load)되고 실행될 때까지 빈 화면이 표시되거나 SEO 최적화가 어렵다는 단점이 있습니다. 그러나 NextJS에서는 SSR을 통해 동적 콘텐츠를 포함한 전체 페이지를 서버에서 렌더링하여 사용자에게 즉시 제공함으로써 위의 단점을 해결할 수 있습니다.</p>
<blockquote>
<p>관련 PR 확인은 <a href="https://github.com/mobi-projects/yeogi-client/pull/123">여기</a></p>
</blockquote>
<br />

<h4 id="2️⃣-dynamic-metadata">2️⃣ dynamic metadata</h4>
<p>다이나믹 메타 데이터를 적용했을 때 웹 사이트가 얻을 수 있는 이점은 크게 세 가지가 될 것 같습니다.</p>
<p>1️⃣ SEO 최적화
각 페이지마다 고유한 메타 데이터를 설정하게 될 경우 검색 엔진 최적화(SEO)에 도움이 된다는 장점이 있습니다.
메타 데이터가 각 페이지에 맞게 설정돼 있다면 검색 엔진에서 해당 페이지를 더 잘 인식할 수 있기 때문에 검색 결과에 더 잘 반영될 수 있습니다.</p>
<p>2️⃣ 소셜 미디어 공유 최적화
소셜 미디어에서 콘텐츠를 공유할 때도 다이나믹 메타데이터가 중요한 역할을 합니다.</p>
<p>페이지마다 고유한 Open Graph(OG) 메타 태그를 설정할 경우 사용자가 해당 페이지를 공유할 때 미리보기 이미지, 제목, 설명이 적절하게 나타나도록 할 수 있습니다.</p>
<p>3️⃣ 향상된 사용자 경험
사용자에게 현재 보고 있는 페이지와 일치하는 정보를 제공함으로써 페이지의 내용과 일관성을 유지할 수 있습니다.</p>
<blockquote>
<p>관련 PR은 <a href="https://github.com/mobi-projects/yeogi-client/pull/128">여기</a></p>
</blockquote>
<blockquote>
<p>관련 벨로그는 <a href="https://velog.io/@55555-jyeon/Metadata-options">여기</a></p>
</blockquote>
<br />

<h4 id="3️⃣-nextauth">3️⃣ NextAuth</h4>
<p>NextAuth를 사용하면 일반 리액트 프로젝트에서 OAuth 관련 로직을 구현할 때보다 훨씬 효율적이고 간편하게 인증 관리를 할 수 있습니다.</p>
<p>또한, NextJS에서는 OAuth 인증을 서버 관리로 변경하면 CORS 문제를 줄일 수 있을 뿐만 아니라 클라이언트가 직접 OAuth API에 접근하지 않기 때문에 브라우저의 CORS 정책 회피도 가능하다는 장점이 있습니다.</p>
<blockquote>
<p>관련 PR은 <a href="https://github.com/mobi-projects/yeogi-client/pull/127#pullrequestreview-2242520899">여기</a></p>
</blockquote>
<blockquote>
<p>관련 벨로그는 <a href="https://velog.io/@hayoung78/NextJS-NextAuth%EB%A1%9C-%EC%86%8C%EC%85%9C%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84-%ED%95%98%EA%B3%A0-%EB%82%9C-%ED%9B%84-%EA%B4%80%EB%A6%AC">여기</a></p>
</blockquote>
<br />

<h3 id="ux-최적화">UX 최적화</h3>
<h4 id="layout-shift">layout shift</h4>
<p>NextJS UI에서 제공하는 skeleton으로 로딩(loading) 시 발생하는 layout shift현상을 해결했습니다.
또한 main의 landing 페이지에서 용량이 큰 두 개의 이미지의 확장자를 svg에서 webp로 변경해 로딩되는 시간을 단축시켰습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/30eb75af-54f8-4369-92d4-158ae723eb21/image.png" alt=""></p>
<p>이미지가 많았던 메인 페이지의 처참했던 performance 점수도 40점대에서 75점으로 올랐습니다.</p>
<br />

<h5 id="svg--webp-">SVG ? WEBP ?</h5>
<blockquote>
<p><strong>SVG</strong> (Scalable Vector Graphics)</p>
</blockquote>
<ul>
<li>벡터 이미지 형식</li>
<li>무한히 확대해도 품질이 손상되지 않는 특성</li>
<li>로고, 아이콘 및 그래픽 디자인에 적합</li>
</ul>
<blockquote>
<p><strong>WebP</strong> (Web Picture)</p>
</blockquote>
<ul>
<li>구글이 개발한 이미지 포맷</li>
<li>픽셀 기반의 사진 및 복잡한 이미지를 위한 형식</li>
<li>손실 압축과 무손실 압축을 모두 지원</li>
<li>파일 크기를 줄이면서도 높은 품질을 유지 가능</li>
</ul>
<p>기존에는 이미지의 품질을 위해 이미지의 확장자를 svg로 가져갔지만 성능 문제로 인해 용량이 큰 이미지를 webP로 변경했습니다. </p>
<p>WebP의 높은 이미지 압축률은 동일한 품질의 이미지를 더 작은 파일 크기로 저장할 수 있도록 해줍니다. 따라서 webP 확장자의 이미지를 사용하면 전체적인 페이지 로딩 시간을 단축시켜 사용자 경험을 향상시킵니다.</p>
<br />

<p>그 외에도 아래와 같은 장점이 있다고 합니다 : </p>
<p>1️⃣ 다양한 이미지 유형 지원
WebP는 손실(lossy) 및 무손실(lossless) 압축을 모두 지원하므로
JPEG, PNG 대안으로 사용 가능</p>
<p>2️⃣ 투명도 지원 → PNG와 같은 무손실 포맷의 대안으로 사용 가능</p>
<p>3️⃣ 애니메이션 지원 → gif 대체 가능</p>
<p>4️⃣ 광범위한 브라우저 지원
최근 웹 브라우저들은 대부분 WebP를 지원하므로 호환성 문제를 최소화 가능 
나아가 다양한 사용자 환경에서 일관된 경험 제공 가능</p>
<p>5️⃣ 효율적인 네트워크 사용
파일 크기가 작아지면 네트워크 대역폭 사용이 줄어들게 되므로 모바일 데이터 사용량을 절약 가능 </p>
<br />



<blockquote>
<p>관련 PR은 <a href="https://github.com/mobi-projects/yeogi-client/pull/100">여기</a></p>
</blockquote>
<br />


<h4 id="debounce">debounce</h4>
<p>FE 팀과 디자인 팀은 사용자 경험이 저하될 것 같은 부분은 바로 의견을 나누며 해결책을 찾아나가려 노력했습니다.</p>
<p align="center">
<img src="https://velog.velcdn.com/images/55555-jyeon/post/af6498a4-6722-4b2a-95ad-ac0e04dc507c/image.png" />
(중략)
<img src="https://velog.velcdn.com/images/55555-jyeon/post/e015c30e-88bd-4470-80c7-23d5c51ca1f7/image.png" />
(중략)
<img src="https://velog.velcdn.com/images/55555-jyeon/post/3f465912-2186-4418-806d-4cf5293cfdb7/image.png" />
 </p>



<blockquote>
<p>관련 PR은 <a href="https://github.com/mobi-projects/yeogi-client/pull/75">여기</a></p>
</blockquote>
<br />

<h4 id="devtools-및-미사용-font-관리">devTools 및 미사용 font 관리</h4>
<p>배포된 페이지에서 React의 devTools가 의도치 않게 로드되는 문제가 있었습니다. 
이를 방지하고 사용자에게 불필요한 파일이 로드되지 않도록 조치했습니다. </p>
<p>또한, 사용되지 않는 폰트를 변수로 설정하여 폰트 로딩을 최적화하였습니다. 
이를 통해 Next.js의 내장 폰트 최적화 기능을 활용해, 필요한 경우에만 폰트 파일이 로드되도록 설정하였습니다. 
Nanum_Myeongjo와 Pretendard 폰트를 CSS 변수로 정의하여 전역적으로 사용 가능하게 하였고, Tailwind CSS 설정을 통해 효율적인 폰트 관리를 구현했습니다.</p>
<blockquote>
<p>관련 PR은 <a href="https://github.com/mobi-projects/yeogi-client/pull/126">여기</a></p>
</blockquote>
<br />

<h4 id="lcp-점수-올리기">LCP 점수 올리기</h4>
<p>그 외에도 LCP 점수를 올림으로써 사용자가 빠르게 웹 페이지의 화면을 볼 수 있도록 최적화에 힘쓰고 있습니다.</p>
<blockquote>
<p>관련 PR은 <a href="https://github.com/mobi-projects/yeogi-client/pull/126">여기</a></p>
</blockquote>
<blockquote>
<p>관련 게시글은 &lt;<a href="https://velog.io/@55555-jyeon/lcp">사용자를 생각한 한 걸음, LCP</a>&gt;</p>
</blockquote>
<br />
<br />

<h2 id="my-part">My Part</h2>
<p>제가 메인으로 맡은 파트는 게시글 관련 쪽과 회원 정보 부분이었습니다.</p>
<h4 id="post-crud">post CRUD</h4>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/085b03bd-cd0b-4d8e-9ef7-ed045f48633a/image.svg" alt=""></p>
<br />

<p>여기(Yeogi)에서 사용한 게시글 에디터는 <strong>react-quill</strong>입니다.</p>
<blockquote>
<p>관련 PR은 <a href="https://github.com/mobi-projects/yeogi-client/pull/27">여기</a></p>
</blockquote>
<br />

<h4 id="ux-최적화-1">UX 최적화</h4>
<h5 id="intersection-observer를-사용한-비디오-재생-최적화">Intersection Observer를 사용한 비디오 재생 최적화</h5>
<p>MainSurveyRecommend 컴포넌트에서는 Intersection Observer API를 사용하여 비디오 재생을 최적화했습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/9a4de1b9-de96-40d9-a23f-2fb8590e6a20/image.png" alt=""></p>
<p>관찰 대상 요소가 화면에 50% 이상 보일 때만 비디오를 재생시키도록 하는 handleIntersection 함수를 만들었습니다.</p>
<p>결과적으로 해당 함수로 인해 비디오가 사용자 화면에 보일 때만 재생되게 함으로써 불필요한 자원 소모를 줄일 수 있도록 신경썼습니다.</p>
<p>또한 비디오가 보이지 않을 때는 재생이 중단되기 때문에 다른 중요한 작업에 더 많은 리소스를 할당해 전체 페이지의 성능을 향상을 도모했습니다.</p>
<blockquote>
<p>관련 PR은 <a href="https://github.com/mobi-projects/yeogi-client/pull/77">여기</a></p>
</blockquote>
<br />

<h2 id="memoirs-💭">Memoirs 💭</h2>
<h4 id="common-kpt">common KPT</h4>
<p>Yeogi Crew는 21일 최종 발표 후 그 주 토요일에 함께 회고하는 시간을 가졌습니다. 전원 모두 8월에도 이어서 프로젝트를 진행하기로 했기 때문에 회고 방식은 KPT로 가져갔습니다.</p>
<blockquote>
<p><strong>KPT memoirs</strong>
KPT 회고는 애자일(Agile) 방법론에서 사용되는 회고 기법 중 하나로, 팀의 작업 과정과 결과를 개선하기 위해 사용됩니다. <br />
KPT는 세 가지 질문을 중심으로 진행</p>
</blockquote>
<ul>
<li><strong>Keep</strong>
  잘 되었던 점이나 효과적이었던 부분을 계속 유지하기 위해 무엇을 해야 하는지를 논의</li>
<li><strong>Problem</strong>
  문제가 있었던 점이나 개선이 필요한 부분을 분석하고 그 원인 모색</li>
<li><strong>Try</strong>
  문제를 해결하고 더 나은 성과를 내기 위해 시도해볼 새로운 방법이나 아이디어를 제안</li>
</ul>
<br />


<p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/fa4d6e69-51fb-4f58-963e-1c88ed315cb2/image.svg" />
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/d0e2e034-7a16-405d-9ab0-f9ef82b08197/image.svg" />
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/2ce44365-f6e0-4db2-846d-1babe7bb6f79/image.svg" />
</p>


<br />

<h4 id="personal-memoirs">Personal Memoirs</h4>
<h6 id="1️⃣-grey한-기획">1️⃣ grey한 기획</h6>
<p>초반에 제대로 잡고 가지 못한 기획에 대한 중요성을 모두 뼈저리게 느꼈습니다.
뒤늦게 프로젝트 진행 기간 후반에 기획을 잡고 가느라 시간은 많이 소모했지만 그 기간을 기회로 전원이 다시 한 번 더 프로젝트의 방향성을 다잡고 갈 수 있었다 생각합니다.</p>
<h6 id="2️⃣-fe와-be의-소통-문제">2️⃣ FE와 BE의 소통 문제</h6>
<p>초반에 스테이크 홀더 간의 회의 시간에 이슈를 공유하고자 하여 문제에 대한 즉각적인 대응이 어려웠습니다. 이는 각자 맡은 파트에서 문제 발생 시 각 팀의 스테이크 홀더를 통해 상대 팀에게 전달되는 방식으로 결과적으로 해당 문제를 해결하기까지의 과정에 지연이 생길 수 밖에 없는 구조였습니다.</p>
<p>프로젝트 중반부터 문제 발생 시 담당자에게 즉각적으로 연락을 취하는 방식으로 변경 후 전보다 빠른 대응이 가능해졌습니다. 하지만 급한 건이라는 이유로 Jira나 Slack을 통하지 않고 개인적인 메신저를 통해 연락을 취하게 되었고 시간 동안 들쭉날쭉했습니다.</p>
<p>BE 팀의 경우, 전원이 재직 중이었기 때문에 문제 대응 시간이 한정적이었던 반면 
FE 팀의 경우, 전원이 취업 준비 중이었기 때문에 24시간 문제를 바라보고 있었습니다.</p>
<p>이와 같은 연락 방식은 서로에게 곤란할 수 밖에 없다고 판단해 8월부터는 함께 정한 코어 시간을 활용해 문제를 공유하고, 불가피할 경우 Jira를 통하기로 했습니다.</p>
<h6 id="3️⃣-be끼리의-소통-문제">3️⃣ BE끼리의 소통 문제</h6>
<p>병목 현상 방지를 위한 즉각적인 문제를 공유한 FE 팀과는 달리 BE 팀은 RNR을 명확히 가져갔습니다. 따라서 바로 해결해야 하는 문제를 BE 담당자가 해결할 수 없는 상황일 경우, 해당 파트 전체가 지연되는 문제가 있었습니다.
또한 서로의 PR에 리뷰를 달지 않았기 때문에 다른 팀원이 문제를 해결하는 데에도 어려움이 있었습니다.</p>
<p>따라서 최종 발표 이후 BE 팀은 서로의 코드 공유를 원활히 하기 위해 8월 전까지 전체적인 코드 리팩터링 및 트랙킹 후 8월부터 서로의 PR에 전보다 열심히 리뷰하기로 했습니다.</p>
<h6 id="4️⃣-grey한-agenda">4️⃣ grey한 agenda</h6>
<p>모비 내에서 진행하고자 했던 방법은 매주 모든 팀원이 하나의 큰 파트를 바라보고 진행하는 거였습니다. </p>
<p>저희는 가져가고자 했던 기능 외적으로도 &quot;그래도 사이트라면...&quot; 하는 생각에 부가적인 기능도 동시에 진행시켰습니다. (예를 들면 로그인 기능이라거나...?)
그래서 모든 인원이 다 다른 파트를 동시다발적으로 진행하게 됨과 동시에 모든 파트에서 생기는 다양한 문제들을 함께 회의에 공유하려니 회의 자체도 길어지고 집중력도 분산되는 문제가 있었습니다.</p>
<p>8월 이후부터는 모두 공통된 하나의 맥락을 공유하며 진행시켜보면 좋을 것 같습니다.</p>
<br />
<br />


<h3 id="🧐-프로젝트를-돌아보며">🧐 프로젝트를 돌아보며...</h3>
<h4 id="얻어가고자-했던-부분이-있다면">얻어가고자 했던 부분이 있다면?</h4>
<h6 id="협업과-소통">협업과 소통</h6>
<p>처음으로 프로젝트만을 위해 모인 사람들과 진행한 프로젝트였던만큼 다른 파트 담당자들, 나아가 초면인 프론트엔드 개발자들과의 협업과 소통이 기대됨과 동시에 긴장되었습니다.</p>
<p>각 팀마다 집중하는 부분이 다를 것이라 생각했고 모든 니즈(needs)를 충족할 수 있을지, 분쟁 발생 시 잘 해결할 수 있을지에 대한 걱정과 더불어 모두가 만족할 프로젝트 완성을 이뤄내고 싶었습니다.</p>
<h6 id="nextjs-project">NextJS Project</h6>
<p>또한 NextJS로 프로젝트를 진행하는 만큼, React에서는 구현할 수 없었던 Next 만의 강점을 살릴 수 있는 프로젝트를 완성하고 싶었습니다.</p>
<br />

<h4 id="얻어갔는가">얻어갔는가?</h4>
<h6 id="협업과-소통-1">협업과 소통</h6>
<p>팀 간 소통 시 최대한 오해의 여지가 없도록 시각 자료를 첨부해 전달하고자 했습니다. 
같은 의견을 공유하는 팀/팀원이 어떤 부분을 문제로 인식하고 있는지와 그에 대한 해결 방안을 제안하고자 했습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/a5d2acba-8034-4a32-8aa6-02259fb7f31b/image.png" alt=""></p>
<br />

<p>기능을 구현하면서 발생하는 문제들로 인한 백엔드 개발자와의 1:1 소통은 여태까지 개인 메신저로 진행한 부분이 조금 아쉬웠습니다.</p>
<p>8월 이후부터 Jira를 통한 이슈 공유를 기대하고 있습니다.</p>
<br />

<h6 id="nextjs에서-만든-react-프로젝트">NextJS에서 만든 React 프로젝트</h6>
<p>NextJS에서 제공하는 수많은 기능들을 많이 활용하지 못한 것 같아 아쉬움이 남습니다. 시간에 쫓기다 보니 구현 자체에 목을 메게 되면서 항상 아쉬움을 남기게 되는 것 같아요. </p>
<p>그래도 현재 NextJS에서 제공하는 기능들을 적극 활용하기 위해 검색해가며 리팩터링을 진행하고 있기 때문에 어느 정도 해소가 되지 않을까 기대하고 있습니다.</p>
<br />

<p>
<img width="16%" src="https://github.com/mobi-projects/yeogi-client/assets/134191817/6a1307e8-9c58-4cda-ad92-a09281d4a95a" alt="yeogi logo" />
</p>  

<br />
<hr />


<h6 id="다른-팀원의-회고가-궁금하다면">다른 팀원의 회고가 궁금하다면?</h6>
<ul>
<li>Gang의 회고가 궁금하다면 <a href="https://velog.io/@skek298/Yeo-gi-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-KPT-%ED%9A%8C%EA%B3%A0">여기</a></li>
<li>Wendy의 회고가 궁금하다면 여기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[This와 This 바인딩, 어디까지 알아?]]></title>
            <link>https://velog.io/@55555-jyeon/this-binding</link>
            <guid>https://velog.io/@55555-jyeon/this-binding</guid>
            <pubDate>Wed, 29 May 2024 17:34:20 GMT</pubDate>
            <description><![CDATA[<h1 id="this-→--">This → {　}</h1>
<blockquote>
<p><strong>This</strong>는 Object(객체)를 참조하는 keyword입니다.</p>
</blockquote>
<p>그런데 어떤 객체를 참조하는 키워드인걸까요?</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/1c76e446-a37b-45d1-805a-51414c003d6b/image.png" alt=""></p>
<br />

<h3 id="전역에서">전역에서</h3>
<p>전역에서, 즉 함수 외부에서 this를 console에 찍어보게 되면 window 객체를 가리키고 있다는 것을 알 수 있습니다. </p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/97e78f01-e7c5-4451-bea8-ebafdda3a97e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/0df70f66-0ac8-425c-88b1-cd65e9edd567/image.png" alt=""></p>
<p>window 객체는 브라우저에 대한 정보를 갖고 있는 전역 객체입니다.</p>
<p><code>&quot;use strict&quot;</code>로 엄격모드에서 같은 코드를 작성해도 전역에서의 this는 전역 객체인 window를 가리키고 있는 것을 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/80fedc8f-ea0c-42fb-9356-93546bb3cf16/image.png" alt=""></p>
<br />

<h3 id="일반-함수-내부에서">일반 함수 내부에서</h3>
<blockquote>
<p><strong>This</strong>는 <strong>함수를 호출한 객체</strong>입니다.</p>
</blockquote>
<p>function 키워드로 선언한 함수, 즉 일반 함수는 window 객체에 등록되게 됩니다. </p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/99115d45-b3a8-4341-b55b-1e8a5dcf512c/image.png" alt=""></p>
<p>따라서 함수 밖에서 window를 console에 찍은 뒤 내부를 살펴보면 main이라는 이름의 함수가 등록된 것을 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/e32f7d71-4b3c-4ebd-9c9b-e6d076b29727/image.png" alt=""></p>
<p>선언된 함수를 호출하고 console을 살펴보면 window 객체가 찍히는 것을 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/4727640e-fe87-450e-910d-cf7b3cddffe1/image.png" alt=""></p>
<p>이는 main 함수를 호출한 부분이 <code>window.main()</code>과 동일하기 때문입니다.</p>
<pre><code class="language-javascript">function main(){
    console.log(this);
}

main(); // === window.main(); ⭐️</code></pre>
<p><strong>This</strong>는 <strong>함수를 호출한 객체</strong>입니다.
그리고 main이라는 함수를 직접적으로 호출한 객체는 window 객체(전역 객체)입니다. </p>
<p>따라서 일반 함수 속 this는 전역에서와 마찬가지로 window 객체를 가리키게 됩니다.</p>
<br />

<p>전역에서의 this와 일반 함수 내부에서의 this의 차이는 <code>&quot;use strict&quot;</code>를 사용했을 때 발견할 수 있습니다.</p>
<p>엄격모드에서는 동일하게 아래와 같이 코드를 작성했을 때 window 객체 대신 undefined를 내보냅니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/b1ffb928-2a57-43cc-9c69-fb85231d48b7/image.png" alt=""></p>
<p>undefined 대신 window 객체를 console에 찍으려면 좀 더 정확하게 코드를 작성해야 합니다.
위에서 언급한 것처럼 축약(?) 대신 <code>window.main()</code>을 다 작성해줘야 window 객체가 console에 찍히게 됩니다.</p>
<br />

<h3 id="객체-메서드-내부에서">객체 메서드 내부에서</h3>
<p>ES6에서 추가된 let과 const 키워드 사용 시 경고가 떠서 일단 var를 사용해 선언했습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/08f6624e-f15c-4fad-a747-47e35bd460a6/image.png" alt=""></p>
<p>This는 함수를 호출한 객체를 가리킨다고 했습니다.
위 코드에서 main 함수를 호출한 객체는 object 객체이기 때문에 이번에는 위에서와는 다르게 object 객체를 가리키게 됩니다.</p>
<p>위 코드는 아래와 같이 작성해도 같은 결과로 나타납니다.</p>
<pre><code class="language-javascript">function main(){
    console.log(this);
}

const object = {
    name: &#39;amy&#39;,
      main,   // main : main,
};

object.main();</code></pre>
<br />

<pre><code class="language-javascript">const object = {
    name: &#39;amy&#39;,
      smallObject : {
        name: &#39;small amy&#39;,
          main: function(){
             console.log(this);
        },
    },
};

object.smallObject.main();  // ???</code></pre>
<p>이렇게 object 안에 smallObject를 만들어 주고, 그 안에 메서드를 만든다면 마지막 코드의 결과는 어떻게 나올까요?</p>
<p>this가 가리키는 것은 smallObject일까요, object일까요?</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/c6bfda1d-0130-4f71-9885-5de980993a48/image.png" alt=""></p>
<p>main 함수를 직접적으로 호출한 객체가 smallObject이기 때문에 this는 smallObject를 가리키게 됩니다.</p>
<p>this의 값은 <code>.</code>으로 해당 함수를 불러오는 바로 왼쪽의 객체라고 생각하면 편할 것 같습니다 🙂</p>
<br />

<p>이런 특징은 객체의 다른 속성에 접근할 때 유용하게 사용될 수 있습니다.</p>
<pre><code class="language-javascript">const object = {
    name: &#39;amy&#39;,
      main: function(){
        console.log(this.name); // &#39;amy&#39;
    },
};

object.main();</code></pre>
<br />
<br />

<p>This는 자신이 속한 객체 혹은 자신이 생성할 인스턴스를 가리키는 자기 참조 변수(self-referencing variable) 입니다.</p>
<p>따라서 this를 통해 자신이 속한 객체 혹은 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있습니다. </p>
<br /> 

<h1 id="this-binding">This Binding</h1>
<p>위에서 이해를 위해 다뤘던 부분들을 항목별로 다시 나눠 짚고 넘어가보겠습니다.</p>
<p>자바스크립트에서 this가 참조하는 것은 <strong>함수가 호출되는 방식에 따라 결정</strong>되는데, 이것을 <strong>This Binding</strong>이라고 합니다.</p>
<p>this 바인딩은 크게 아래 다섯 가지(4가지의 메인 바인딩과 화살표 함수)로 분류할 수 있습니다.</p>
<pre><code>1️⃣ 기본 바인딩
2️⃣ 암시적 바인딩
3️⃣ 명시적 바인딩
4️⃣ new 바인딩
＋ 화살표 함수(ES6)</code></pre><br />

<h3 id="1️⃣-기본-바인딩-default-binding">1️⃣ 기본 바인딩 (Default Binding)</h3>
<p>기본 바인딩이 적용될 경우 this는 전역 객체에 바인딩되며 브라우저 환경인 경우 window, Node.js 환경인 경우 global을 가리키게 됩니다.</p>
<pre><code class="language-javascript">function printName() {
  const name = &quot;Amy&quot;;
  console.log(this.name);
}

printName(); // undefined</code></pre>
<p>위의 코드에서 this는 전역객체에 바인딩되는데 전역객체에는 name이라는 프로퍼티가 없기 때문에 콘솔에는 undefined가 찍히게 됩니다.</p>
<pre><code class="language-javascript">window.name = &quot;Amy&quot;;

function printName() {
  console.log(this.name);
}

printName(); // Amy</code></pre>
<p>코드를 일부 수정했습니다.
위와 같이 전역객체에 name이라는 프로퍼티가 있다면 해당 name 프로퍼티의 값이 찍힙니다.</p>
<p>단, 엄격모드에서는 기본 바인딩 대상에서 전역객체는 제외됩니다. </p>
<pre><code class="language-javascript">&#39;use strict&#39;
window.name = &quot;Amy&quot;;

function printName() {
  console.log(this.name);
}

printName(); // TypeError</code></pre>
<p>전역객체를 참조해야할 this가 있다면 그 값은 undefined가 되므로 주의해야 합니다.</p>
<br />

<h3 id="2️⃣-암시적-바인딩-implicit-binding">2️⃣ 암시적 바인딩 (Implicit Binding)</h3>
<p>암시적 바인딩(Implicit Binding)은 함수가 객체의 메서드로서 호출되는 상황에서 this가 바인딩되는 것을 말합니다. 
이때 this는 해당 함수를 호출한 객체, 즉 콘텍스트 객체에 바인딩됩니다.</p>
<pre><code class="language-javascript">const person = {
  name: &quot;Amy&quot;,
  birthYear: 1990,
  CalcAge: function () {
    console.log(this.birthYear); 
  }
}

person.CalcAge(); // 1990</code></pre>
<p>암시적 바인딩을 사용할 때 발생할 수 있는 문제는 위와 같은 상황에서 함수를 매개변수(콜백)로 넘겨서 실행하는 것입니다.</p>
<p>예를 들어, 위의 코드에 이어 아래와 같이 객체에 정의되어있는 함수의 레퍼런스를 매개변수로 전달한다면 어떤 결과가 나올까요?</p>
<pre><code class="language-javascript">setTimeout(person.CalcAge, 1); // ?</code></pre>
<p>정답은 <strong>undefined</strong>입니다.</p>
<p>이런 결과가 나온 이유는 setTimeout 함수 안에 전달한 콜백은 CalcAge 함수의 레퍼런스일 뿐, person의 콘텍스트를 가지고 있지 않기 때문입니다. </p>
<blockquote>
<p>이런 상황을 <strong>암시적 바인딩이 소실되었다</strong>고 합니다.</p>
</blockquote>
<p>따라서 setTimeout 내부에서 호출되는 콜백은 person 객체의 콘텍스트에서 실행되는 것이 아니기 때문에, this는 기본 바인딩이 적용돼서 전역 객체에 바인딩 됩니다.</p>
<pre><code class="language-javascript">function setTimeout(callback, delay) {
  // delay에 전달된 시간이 흐른 뒤 callback을 실행
  callback(); // 기본 바인딩
}</code></pre>
<br />

<h3 id="3️⃣-명시적-바인딩-explicit-binding">3️⃣ 명시적 바인딩 (Explicit Binding)</h3>
<p>자바스크립트의 모든 Function은 call(), apply(), bind()라는 프로토타입 메소드를 갖고 있습니다. 이 3가지 메서드 중 하나를 호출함으로써 this 바인딩을 코드에서 명시하는 것을 명시적 바인딩이라고 합니다. </p>
<p>이때 this는 내가 명시한 객체에 바인딩됩니다.</p>
<h5 id="apply-call">apply, call</h5>
<pre><code class="language-javascript">const person = {
  age: 20,
}

function printAge() {
  console.log(this.age);
}

printAge.call(person); // 20
printAge.apply(person); // 20</code></pre>
<p>printAge의 함수 프로토타입 메서드 call, apply의 매개변수로 바인딩할 객체를 넘겨줌으로써 printAge 함수를 실행할 때의 this 컨텍스트가 person이 되도록 직접 바인딩 해주었습니다.</p>
<p>call과 apply의 동작은 같지만 두번째 매개변수로 객체의 인자를 전달해주는데
call은 매개변수의 목록, apply는 배열을 받는다는 차이점이 있습니다.</p>
<h5 id="bind">bind</h5>
<p>계속 변경되는 this의 값을 특정 객체가 되도록 지정하기 위해(고정시키기 위해) <code>bind()</code>할 수 있습니다.</p>
<p>bind 메서드는 새로운 바인딩된 함수를 만듭니다. 바인딩된 함수를 호출하면 일반적으로 해당 함수가 래핑하는 함수(대상 함수)가 실행되게 됩니다. 그리고 이때 바인딩된 함수는 this와 인수를 포함하는 전달된 매개변수를 내부 상태로 저장합니다.</p>
<p>bind 메서드가 매개변수로 전달받은 오브젝트로 this가 바인딩된 함수를 반환하는 것을 <strong>하드 바인딩</strong>(hard binding)이라고 합니다. 하드 바인딩된 함수는 이후 호출될 때마다 처음 정해진 this 바인딩을 가지고 호출됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/aee69d2a-5635-4af9-a605-bcb5cfe94f79/image.png" alt=""></p>
<p>함수에 원하는 객체를 묶어 고정시키기 위해서는 새로운 변수를 만들어줘야 합니다. 새로운 변수에 함수를 우선 할당해줍니다. 그리고 고정시킬 객체를 인자로 받는 <code>bind()</code>를 할당한 함수 뒤에 연결합니다.</p>
<pre><code class="language-javascript">// before bind
function main(){
    console.log(this);  // Window Obj
}

main();

// after binding
function main(){
    console.log(this);  // {name: &quot;Amy&quot;}
}

const mainBind = main.bind({name: &quot;Amy&quot;});

mainBind();</code></pre>
<p>함수를 바인딩할 때 주의해야할 점은 <strong>한 번 바인딩된 함수는 다시 바인딩될 수 없다는 것</strong>입니다.</p>
<pre><code class="language-javascript">function main(){
    console.log(this);  // {name: &quot;Amy&quot;}
}

const mainBind = main.bind({name: &quot;Amy&quot;});

const BindAgain = mainBind.bind({name: &quot;something else&quot;});  // ignored

BindAgain();</code></pre>
<br />

<p>새로운 변수를 만들어 적용할수도 있지만 아래와 같이 작성할 수도 있습니다. 🙂</p>
<pre><code class="language-javascript">const outerObject = {
    name: &quot;outer object&quot;,
      main: function(){
        console.log(this); // outerObject {...}
    },
};

object.main();</code></pre>
<p>처음 사용했던 예제를 활용해보자면 :
객체 안의 함수에 바로 bind 메서드를 연결해 사용할 수도 있습니다.</p>
<pre><code class="language-javascript">const outerObject = {
    name: &quot;outer object&quot;,
      main: function(){
        console.log(this); // {name: &quot;inner object&quot;}
    }.bind({name: &quot;inner object&quot;}),
};

object.main();</code></pre>
<br />

<h3 id="4️⃣-new-바인딩-new-binding">4️⃣ new 바인딩 (new Binding)</h3>
<p>자바스크립트의 new 키워드는 함수를 호출할 때 앞에 new 키워드를 사용하는 것으로 객체를 초기화할 때 사용하는데, 이때 사용되는 함수를 생성자 함수라고 합니다.</p>
<p>그리고 생성자 함수에서는 this 키워드를 해당 생성자를 이용해 생성할 객체에 대한 참조로 사용합니다.</p>
<pre><code class="language-javascript">function PrintAge() {
  this.age = 20;
}

const printAge = new PrintAge();

console.log(printAge.age); // 20</code></pre>
<p>① PrintAge 함수가 new 키워드와 함께 호출되는 순간 새로운 객체가 생성되고, 새로 생성된 객체가 this로 바인딩 됩니다. </p>
<p>② 생성된 객체의 age라는 프로퍼티에 20이라는 값이 할당되고, 해당 객체는 printAge 변수에 할당됩니다.</p>
<br />

<h3 id="＋-es6-화살표-함수-arrow-function">＋ ES6 화살표 함수 (Arrow Function)</h3>
<p>ES6에 추가된 화살표 함수(Arrow Function)는 this를 바인딩할 때 앞서 설명한 규칙들이 적용되지 않고, this에 어휘적 스코프(Lexical scope)가 적용됩니다.</p>
<pre><code class="language-javascript">const obj = {
  name: &#39;John Doe&#39;,
  greet: () =&gt; {
    console.log(this.name);
  }
};
obj.greet(); // undefined (외부 스코프의 this를 사용)</code></pre>
<blockquote>
<p>즉, <strong>화살표 함수를 정의하는 시점의 컨텍스트 객체</strong>가 this에 바인딩됩니다.</p>
</blockquote>
<pre><code class="language-javascript">const person = {
  age: 20,
  printAge: function () {
    setTimeout(() =&gt; {
      console.log(this.age);
    }, 1);
  }
}

person.printAge(); // 20</code></pre>
<p>setTimeout의 콜백인 화살표 함수의 선언 시에 this는 person 객체를 가리키고 있기 때문에(렉시컬 스코프), 콜백이 실행될 때 this는 person을 가리키게 됩니다.</p>
<p>화살표 함수로 선언 시에 렉시컬 스코프를 통해 바인딩된 this는 apply, bind등의 함수나 new 함수로 오버라이드할 수 없기 때문에 주로 콜백 함수로 사용할 때 유용하게 사용됩니다.</p>
<br />

<h3 id="else-lexical-scope">else, lexical scope</h3>
<p><code>apply</code>, <code>call</code>, <code>bind</code>와 같은 바인딩 메소드, 또는 화살표 함수가 나오기 전에는 골치아픈 this 바인딩을 렉시컬 스코프로 해결해왔습니다. </p>
<p>호출 시 결정되는 this를 렉시컬 스코프를 이용해 선언시에 정해주는 효과를 주는 것이죠.</p>
<p>위에서도 한 번 확인했던 내용으로 아래와 같은 상황에서 setTimeout에 콜백으로 넘겨진 함수의 this는 setTimeout에 의해 실행될 때 전역객체에 바인딩이 됩니다.</p>
<pre><code class="language-javascript">const person = {
  age: 20,
  printAge: function () {
    setTimeout(function () {
      console.log(this.age);
    }, 1);
  }
}

person.printAge(); // undefined</code></pre>
<p>이 때, setTimeout의 콜백 내부에서 해당 setTimeout을 호출한 객체에 접근하기 위해서 어떻게 해야할까요?</p>
<pre><code class="language-javascript">const person = {
  age: 20,
  printAge: function () {
    const _this = this;
    setTimeout(function () {
      console.log(_this.age);
    }, 1);
  }
}

person.printAge(); // 20</code></pre>
<p>위와같이 printAge 메서드 실행 시에 해당 메서드를 호출한 객체(person)에 대한 참조를 <code>_this</code>라는 변수에 할당합니다. </p>
<p>그러면 setTimeout의 콜백이 실행될때 렉시컬 스코프에 의해 <code>_this</code>에 접근할 수가 있게 되므로 이를 통해 setTimeout을 호출한 객체(person)에 접근이 가능해집니다.</p>
<br />
<br />


<h2 id="이벤트-처리와-this">이벤트 처리와 this</h2>
<p>함수를 DOM 요소의 이벤트 처리기로 사용할 때 this 값은 어떤 식으로 설정될까요?</p>
<p>버튼을 클릭하거나 스크롤을 내리고 올릴 때 발생하는 이벤트를 처리할 때 이벤트 리스너(EventListener)와 this를 사용한 경험이 있을 겁니다.</p>
<pre><code class="language-javascript">const button = document.getElementbyId(&quot;btn&quot;);

button.addEventListener(&quot;click&quot;, function(){
    console.log(this);
})</code></pre>
<p><code>index.html</code> 파일 안에 btn이라는 아이디의 버튼이 있다고 가정하고 위와 같이 script 파일을 작성했습니다.</p>
<p>이제 버튼을 클릭할 때마다 위의 함수가 실행됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/7776196d-d9a0-48e1-9178-81a071f63118/image.png" alt=""></p>
<p>버튼을 클릭하면 this 값으로 버튼 요소가 콘솔에 찍히는 것을 확인할 수 있습니다.
이렇게 함수를 DOM 요소의 이벤트 처리기로 사용하게 될 경우, this는 이벤트가 적용된 요소를 가리키게 됩니다.</p>
<pre><code class="language-javascript">const button = document.getElementbyId(&quot;btn&quot;);

button.addEventListener(&quot;click&quot;, function(e){
    console.log(e.target === this); // true
})</code></pre>
<br />
<br />

<h2 id="conclusion">conclusion</h2>
<h5 id="왜-this와-this-바인딩에-대해-알아야-할까">왜 this와 this 바인딩에 대해 알아야 할까?</h5>
<p>이러한 this 바인딩 규칙을 이해하고 활용하면 자바스크립트 코드의 유지보수성을 높이고 객체 지향적인 설계를 효율적으로 구현할 수 있습니다.</p>
<p>아래 내용을 정리하자면 : </p>
<br />

<p>1️⃣ <strong>유연한 컨텍스트 관리</strong></p>
<p>this를 통해 함수가 호출된 컨텍스트에 접근할 수 있으므로, 다양한 객체에서 동일한 함수나 메소드를 재사용할 수 있습니다. 이는 코드의 중복을 줄이고 재사용성을 높이는 데 유리합니다.</p>
<pre><code class="language-javascript">function introduce() {
  console.log(`My name is ${this.name}`);
}

const person1 = { name: &#39;John Doe&#39;, introduce };
const person2 = { name: &#39;Jane Doe&#39;, introduce };

person1.introduce(); // &#39;My name is John Doe&#39;
person2.introduce(); // &#39;My name is Jane Doe&#39;</code></pre>
<br />

<p>2️⃣ <strong>명확한 코드 구조</strong></p>
<p>메소드 내에서 this를 사용하면 객체 지향 프로그래밍 패러다임을 따르기 쉬워집니다. 객체의 속성과 메소드를 함께 정의하여 관련 있는 데이터를 논리적으로 묶을 수 있습니다.</p>
<br />

<p>3️⃣ <strong>콜백 함수의 컨텍스트 유지</strong></p>
<p><code>bind</code> 메소드를 사용하면 콜백 함수가 호출될 때의 this를 미리 지정하여 예상치 못한 컨텍스트 변경을 방지할 수 있습니다.</p>
<pre><code class="language-javascript">const button = document.getElementById(&#39;btn&#39;);
const obj = {
  name: &#39;Jane Doe&#39;,
  handleClick: function() {
    console.log(this.name);
  }
};

button.addEventListener(&#39;click&#39;, obj.handleClick.bind(obj)); // &#39;Jane Doe&#39;</code></pre>
<br />

<p>4️⃣ <strong>화살표 함수의 lexical this</strong></p>
<p>화살표 함수를 사용하면 외부 컨텍스트의 this를 그대로 사용할 수 있어, 특히 콜백 함수나 비동기 코드에서 유용합니다.</p>
<br />



<br />
<hr />

<p><em>References.</em></p>
<p>📚 Books.</p>
<ul>
<li>이웅모의 모던 자바스크립트 Deep Dive</li>
<li>카일 심슨의 You Dont’t Know JS (this와 객체 프로토타입, 비동기와 성능)</li>
</ul>
<p>🌎 Official Sites.</p>
<ul>
<li>MDN web docs&#39;s <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this">this</a></li>
<li>MDN web docs&#39;s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind">bind</a></li>
</ul>
<p>👩🏻‍💻 posts.</p>
<ul>
<li>Kyle&#39;s <a href="https://velog.io/@proshy/JS-%EC%83%81%ED%99%A9%EC%97%90-%EB%94%B0%EB%A5%B8-this-%EB%B0%94%EC%9D%B8%EB%94%A9">[JS] 상황에 따른 this 바인딩</a></li>
<li>nana_log&#39;s <a href="https://nykim.work/71">[JS] 자바스크립트에서의 this</a></li>
<li>kyle kwon&#39;s <a href="https://velog.io/@defaultkyle/js-this-1">this 바인딩 이해하기</a></li>
</ul>
<p>🎥 videos.</p>
<ul>
<li>별코딩의 <a href="https://www.youtube.com/watch?v=j6VkGimAs-E">This와 Bind | 멋진 개발자라면 꼭 알아야됨!!</a></li>
</ul>
<br />

]]></description>
        </item>
        <item>
            <title><![CDATA[BookStudy: CS 전공지식 노트]]></title>
            <link>https://velog.io/@55555-jyeon/bookStudy-cs-note</link>
            <guid>https://velog.io/@55555-jyeon/bookStudy-cs-note</guid>
            <pubDate>Wed, 22 May 2024 22:23:07 GMT</pubDate>
            <description><![CDATA[<h3 id="📚-coding-inside">📚 coding-inside</h3>
<p>&quot;코딩인사이드&quot;는 모비 출신 신입 개발자들의 북스터디입니다.
코딩인사이드의 첫 번째 책은 면접 대비 위한 얕고 넓은 지식 습득을 위한 &lt;면접을 위한 CS 전공지식노트&gt;입니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/07aabf46-d744-41da-a464-b093884915f1/image.png" alt=""></p>
<h3 id="📅-schedule">📅 Schedule</h3>
<table>
<thead>
<tr>
<th>기간</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>0주 ( 3/7 ~ 3/10)</td>
<td>6장 포트폴리오/면접</td>
</tr>
<tr>
<td>1주 (3/11 ~ 3/17)</td>
<td>1장 디자인패턴과 프로그래밍 패러다임</td>
</tr>
<tr>
<td>2주 (3/18 ~ 3/24)</td>
<td>2장 네트워크</td>
</tr>
<tr>
<td>3주 (3/25 ~ 3/31)</td>
<td>3장 운영체제</td>
</tr>
<tr>
<td>4주 (4/1 ~ 4/7)</td>
<td>4장 데이터베이스</td>
</tr>
<tr>
<td>5주 (4/8 ~ 4/14)</td>
<td>5장 자료구조</td>
</tr>
</tbody></table>
<br />


<h3 id="⚙️-operate-method">⚙️ Operate Method</h3>
<p>이전 스터디와 비슷하게 <a href="https://github.com/inside-coding/cs-note">repo</a>를 만들어 정리한 내용을 첨부했습니다. 
스터디원 전부 책 내용이 CS 쪽이기 때문에 이해하는데 어려움이 있어 매 주차마다 피드백을 통해 다양한 시도를 해왔습니다.</p>
<p>대면 외 사용한 툴로는 추후 프로젝트 진행 시 slack을 사용 예정이라 미리 익숙해질 겸 slack을 활용해 토의 및 회의를 진행했습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/393dd694-b730-49d8-a7cf-71a3ae13018c/image.png" alt="">
<img src="https://velog.velcdn.com/images/55555-jyeon/post/696fb5dc-7b6f-4ce9-8115-3cc84fbf5285/image.png" alt=""></p>
<br />

<h3 id="👩🏻💻-study-details">👩🏻‍💻 Study Details</h3>
<br />

<h5 id="0주차">0주차</h5>
<p>책 주문 후 6장 개인적으로 읽기
규칙과 스터디 방향성을 위해 slack으로 비대면 회의 진행</p>
<hr />

<h5 id="1주차">1주차</h5>
<p>1장 읽고 마크다운 파일로 정리하기 
slack으로 비대면 모임 진행</p>
<h6 id="🗣️-feedback">🗣️ FeedBack</h6>
<pre><code>&quot;매일 조금씩 나눠 읽기보다 하루나 이틀동안 몰아서 읽게 돼요.&quot;
&quot;그럼 직장인 스터디처럼 모여서 읽어볼까요?&quot;</code></pre><hr />



<h4 id="2주차">2주차</h4>
<p>대면으로 모여 책읽기 진행 </p>
<p align="center">
<img width="60%" src="https://github.com/inside-coding/cs-note/assets/134191817/7b5909e8-ae92-43b7-b816-01e023ef36f1" />
</p>

<h6 id="🗣️-feedback-1">🗣️ FeedBack</h6>
<pre><code>&quot;컴퓨터와 책을 다 들고 나와야 해서 공간이 너무 좁아요.&quot;
&quot;다 읽고 내가 무엇을 모르는지 공유하는 데까지 시간이 너무 오래 걸려요.&quot;

&quot;책은 각자 읽고 챕터 내에서 몰라서 알아본 부분 혹은 공유하고 싶은 정보를 만나서 공유해봐요.&quot;</code></pre><hr />

<h5 id="3주차">3주차</h5>
<p>대면으로 모여 각자 공부한 부분 공유하기 
카페 대신 스터디룸에서 회의 진행 </p>
<p align="center">
<img width="60%" src="https://github.com/inside-coding/cs-note/assets/134191817/231839f8-504d-47c2-ae2d-90244968f4d7" />
</p>

<h6 id="🗣️-feedback-2">🗣️ FeedBack</h6>
<pre><code>&quot;공유한 내용을 읽고 얘기를 나누기엔 시간이 너무 많이 소요돼요.&quot;
&quot;차라리 시간을 좀 아껴서 이 인원대로 면접 스터디도 같이 진행하면 좋을 것 같아요.&quot;

&quot;각자 만나기 이틀 전에 내용 공유 후 전 날 사전에 읽어보고 만나봐요.&quot;</code></pre><hr />

<h5 id="4주차">4주차</h5>
<p>3 ~ 4 주차 사이 개인 사정으로 탈퇴자 발생🥹 
스터디원의 건강 이슈로 비대면(slack)으로 진행 
QNA 관련해서 git의 마크다운 파일로 전원 업로드 완료 </p>
<p align="center">
<img width="60%" src="https://github.com/inside-coding/cs-note/assets/134191817/3d0e2ba9-bcc9-484e-bf17-e3c178d52602" />
</p>

<h6 id="🗣️-feedback-3">🗣️ FeedBack</h6>
<pre><code>&quot;다음 주는 마지막 주차이므로 대면으로 만나 스터디 회식까지 겸하는 거 어때요&quot;</code></pre><br />

<h5 id="5주차">5주차</h5>
<p>전 날 서로 정리한 내용 읽고 준비한 질문들을 토대로 문답 진행
대면으로 만나 회식 진행</p>
<h6 id="🗣️-feedback-4">🗣️ FeedBack</h6>
<pre><code>&quot;다음 스터디들에 대한 내용은 비대면으로 내일(다음 날) 더 얘기 나눠봅시다.&quot;</code></pre><br />

<h3 id="final-meeting">Final Meeting</h3>
<h6 id="20240416">2024.04.16</h6>
<p align="center">
<img width="60%" src="https://github.com/inside-coding/cs-note/assets/134191817/b2037785-d391-4b5f-8ef3-70fac23defcb" />
</p>


<h3 id="💬-memoirs">💬 Memoirs</h3>
<p>책의 내용이 어려워 읽으면서도 완벽히 이해하지 못한 점이 아쉬웠지만 자바스크립트 엔진을 이해하는데 반 걸음.. 정도는 가까워지지 않았나 싶다.</p>
<p>추후에 자격증을 취득할 때 다시 한 번 바짝 공부할 계기가 생기거나 혹은 오랜 시간을 거쳐 자연스럽게 익히게 되거나 둘 중 하나가 될 것 같다 : 앞으로도 계속 관련 공부를 하면서 &#39;어, 이거 CS 전공지식노트에서 본 것 같은데...&#39;를 떠올리며 몇 번 더 읽다보면 자연스럽게 뇌리에 박히지 않을까? 🤔</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS의 시작은 실행 컨텍스트에서부터]]></title>
            <link>https://velog.io/@55555-jyeon/execution-context</link>
            <guid>https://velog.io/@55555-jyeon/execution-context</guid>
            <pubDate>Wed, 22 May 2024 21:49:49 GMT</pubDate>
            <description><![CDATA[<h2 id="실행-컨텍스트">실행 컨텍스트?</h2>
<p>실행 컨텍스트(Execution Context)는 뭘까요?</p>
<p>FE 기술 면접에서 많이 물어보는 질문들 중 대다수가 실행 컨텍스트와 관련이 있으며 자바스크립트 DeepDive 책에도 설명되어 있습니다.</p>
<p>그만큼 실행 컨텍스트는 자바스크립트의 동작 원리를 담고 있는 핵심 개념이라고 할 수 있습니다. 그리고 실행 컨텍스트의 동작 원리를 제대로 이해하면 식별자 바인딩, 호이스팅, 클로저, 이벤트의 동작 원리 등을 이해하는데 수월합니다.</p>
<br />

<h2 id="소스코드">소스코드</h2>
<h4 id="4가지-타입의-소스코드">4가지 타입의 소스코드</h4>
<p>소스코드(ECMAScript code), 즉 실행이 가능한 코드는 크게 4가지 타입으로 구분되며 실행 컨텍스트를 생성합니다. 그리고 소스코드 타입에 따라 생성된 실행 컨텍스트는 생성 과정과 관리 내용이 다르다는 차이가 있습니다.</p>
<br />

<p><strong>1️⃣ 전역 코드</strong> (global code)</p>
<p>전역에 존재하는 소스코드를 의미하며 전역 코드가 평가되면 전역 실행 컨텍스트가 생성됩니다. 이때 전역에 정의된 함수, 클래스 등의 내부 코드는 포함되지 않습니다.</p>
<ul>
<li>전역 변수를 관리하기 위해 최상위 스코프인 <strong>전역 스코프</strong>를 생성</li>
<li>전역 변수와 전역 함수를 전역 객체의 프로퍼티와 메서드로 바인딩하고 참조하기 위해 <strong>전역 객체와 연결</strong>하기 위해 전역 실행 컨텍스트 생성</li>
</ul>
<br />

<p><strong>2️⃣ 함수 코드</strong> (function code)</p>
<p>함수 내부에 존재하는 소스코드를 의미하며 함수 코드가 평가되면 함수 실행 컨텍스트가 생성됩니다. 이때 함수 내부에 중첩된 함수, 클래스 등의 내부 코드는 포함되지 않습니다.</p>
<ul>
<li>지역 변수, 매개변수, arguments 객체 관리하기 위해 <strong>지역 스코프</strong>를 생성</li>
<li>생성한 지역 스코프를 <strong>스코프 체인에 연결</strong>하기 위해 함수 실행 컨텍스트를 생성</li>
</ul>
<br />

<p><strong>3️⃣ eval 코드</strong> (eval code)</p>
<p>eval 함수에 인수로 전달돼 실행되는 소스 코드를 의미하며 eval 코드가 평가되면 eval 실행 컨텍스트가 생성됩니다.</p>
<ul>
<li>strict mode(엄격 모드)에서 자신만의 독자적인 스코프를 생성</li>
</ul>
<br />

<p><strong>4️⃣ 모듈 코드</strong> (module code)</p>
<p>모듈 내부에 존재하는 소스코드로 모듈 코드가 평가되면 모듈 실행 컨텍스트가 생성됩니다. 이때 모듈 내부의 함수, 클래스 등의 내부 코드는 포함되지 않습니다.</p>
<ul>
<li>모듈별로 독립적인 모듈 스코프를 생성</li>
</ul>
<br />

<h4 id="소스코드의-평가와-실행">소스코드의 평가와 실행</h4>
<p>자바스크립트 엔진은 소스코드를 평가와 실행, 2단계로 나누어 처리합니다.</p>
<p>1️⃣ <strong>평가 과정</strong> (혹은 생성 단계, creation phase)</p>
<p>① 실행 컨텍스트를 생성
② 변수, 함수 등의 선언문만 먼저 실행
③ 생성된 변수/함수 식별자를 키(key)로 스코프에 등록</p>
<br />

<p>2️⃣ <strong>실행 과정</strong> (실행 단계, execution phase)</p>
<p>① 선언문을 제외한 소스코드가 순차적으로 실행 (런타임 시작)
② 실행에 필요한 정보를 스코프에서 검색해 취득
③ 소스코드에 의해 변경된 실행 결과는 다시 스코프에 등록</p>
<br />
<br />

<h2 id="실행-컨텍스트-1">실행 컨텍스트</h2>
<h4 id="☝🏻-역할">☝🏻 역할</h4>
<p>코드가 실행되려면 스코프, 식별자, 코드의 실행 순서 등 여러 부분에서 관리가 필요하며 이러한 관리를 해주는 것이 실행 컨텍스트 입니다.</p>
<pre><code>[자세한 설명/조건]

① 선언에 의해 생성된 모든 식별자는 스코프를 구분해 등록하고 상태 변화를 지속적으로 관리할 수 있어야 한다.

② 스코프는 중첩 관계에 의해 스코프 체인을 형성해야 한다.
  스코프 체인을 통해 상위 스코프로 이동하며 식별자를 검색할 수 있어야 한다.

③ 현재 실행 중인 코드의 실행 순서를 변경할 수 있어야 하며 다시 되돌아갈 수도 있어야 한다.</code></pre><br />

<p>실행 컨텍스트는 식별자를 등록하고 관리하는 <strong>스코프</strong>와 코드 실행 순서 관리를 구현한 내부 매커니즘으로 모든 코드는 실행 컨텍스트를 통해 실행 및 관리됩니다.</p>
<p>식별자와 스코프는 실행 컨텍스트의 <strong>렉시컬 환경</strong>으로 관리하고 코드의 실행 순서는 <strong>실행 컨텍스트 스택</strong>으로 관리합니다.</p>
<br />
<br />

<h4 id="✌🏻-구성-요소">✌🏻 구성 요소</h4>
<h3 id="스택">스택</h3>
<blockquote>
<p><strong>실행 컨텍스트의 스택은 코드의 실행 순서를 관리</strong>합니다.</p>
</blockquote>
<p>소스코드가 평가되면 실행 컨텍스트가 생성되고 실행 컨텍스트의 최상위에 쌓이게 됩니다. 그리고 <strong>실행 컨텍스트 스택의 최상위</strong>에 존재하는 실행 컨텍스트는 <strong>언제나 현재 실행 중인 코드의 실행 컨텍스트</strong>입니다. 그래서 실행 컨텍스트 스택의 최상위 실행 컨텍스트를 실행 중인 실행 컨텍스트(running execution context)라고 합니다.</p>
<p>예를 들어 아래와 같은 소스코드가 실행 컨텍스트 스택에 쌓일 때는 아래 이미지와 같을 것입니다.</p>
<pre><code class="language-javascript">function outer(){
    // ...codes
  function inner(){
      // ...codes
  }
  inner();
}
outer();</code></pre>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/a40e3f91-8405-4a52-adb9-edc5e9be8a02/image.svg" alt=""></p>
<br />
<br />

<h3 id="렉시컬-환경">렉시컬 환경</h3>
<blockquote>
<p>렉시컬 환경(lexical environment)은 <strong>식별자와 식별자에 바인딩된 값 그리고 상위 스코프에 대한 참조를 기록하는 자료구조</strong>입니다.</p>
</blockquote>
<p>렉시컬 환경은 키와 값을 갖는 객체 형태의 스코프를 생성해 식별자를 키(key)로 등록하고 식별자에 바인딩된 값을 관리합니다. 즉, 렉시컬 환경은 스코프를 구분해 식별자를 등록하고 관리하는 저장소 역할을 하는 렉시컬 스코프의 실체라고 할 수 있습니다.</p>
<p>실행 컨텍스트는 Lexical Environment 컴포넌트와 Variable Environment 컴포넌트로 구성됩니다. </p>
<p>생성 초기의 실행 컨텍스트와 렉시컬 환경을 그림으로 표현하면 아래와 같습니다.
생성 초기에 두 컴포넌트는 하나의 동일한 렉시컬 환경을 참조하게 됩니다. </p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/d4f63bf4-f9ef-4fc0-b2d8-358ba7e1f3da/image.svg" alt=""></p>
<p>렉시컬 환경는 환경 레코드와 외부 렉시컬 환경에 대한 참조, 두 개의 컴포넌트로 구성되어 있습니다.</p>
<br />

<p>1️⃣ <strong>환경 레코드</strong> (environment record)</p>
<ul>
<li>스코프에 포함된 식별자를 등록</li>
<li>등록된 식별자에 바인딩된 값을 관리하는 저장소</li>
<li>소스코드의 타입에 따라 관리하는 내용에 차이가 존재</li>
</ul>
<br />

<p>2️⃣ <strong>외부 렉시컬 환경에 대한 참조</strong> (outerLexical environment reference)</p>
<ul>
<li>상위 스코프를 가리킴</li>
<li>이를 통해 단방향 링크드 리스트(linked list)인 스코프 체인을 구현</li>
</ul>
<br />


<p>다시 한 번 정리하기 위해 스택에서 설명했던 예시를 그대로 사용해 그림으로 나타내면 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/fa684cd5-8f1b-4008-ab81-d47df0043291/image.svg" alt=""></p>
<p>Variable Environment에서는 현재 컨텍스트 내의 식별자들에 대한 정보와 외부 환경 정보를 관리합니다.</p>
<p>Variable Environment를 선언 시점의 Lexical Environment의 스냅샷과 같다고 생각하면 편합니다. 스냅샷이기 때문에 변경된 사항이 반영되지는 않습니다.</p>
<p>Lexical Environment의 초기는 Variable Environment과 동일하지만 변경 사항이 실시간으로 반영되기 때문에 내용이 달라지게 됩니다.</p>
<p>실행 컨텍스트를 생성할 때 Variable Environment에 정보를 먼저 담은 다음, 이를 그대로 복사해 Lexical Environment를 만듭니다. 그런 이후에는 Lexical Environment를 주로 활용하게 됩니다.</p>
<br />
<br />

<h4 id="🤟🏻-전역-코드-평가-과정">🤟🏻 전역 코드 평가 과정</h4>
<p>소스코드가 로드(load)되면 자바스크립트 엔진은 전역 코드를 평가합니다.
전역 코드 평가는 다음과 같은 순서로 진행됩니다.</p>
<br />


<h5 id="①-전역-실행-컨텍스트-생성">① 전역 실행 컨텍스트 생성</h5>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/ed1cb77d-3b18-4fff-bc04-c0e3b90e6266/image.svg" alt=""></p>
<p>가장 먼저 비어 있는 전역 실행 컨텍스트를 생성해 실행 컨텍스트 스택에 푸시(push)합니다.
동시에 전역 실행 컨텍스트는 실행 중인 실행 컨텍스트가 됩니다.</p>
<br />

<h5 id="②-전역-렉시컬-환경-생성">② 전역 렉시컬 환경 생성</h5>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/f201776b-d839-42e3-b73a-464d985d9ea8/image.svg" alt=""></p>
<p>다음으로 전역 렉시컬 환경을 생성하고 전역 실행 컨텍스트에 바인딩합니다.</p>
<p>렉시컬 환경은 위에서도 설명했듯 환경 레코드와 외부 렉시컬 환경에 대한 참조, 두 개의 컴포넌트로 구성되어 있습니다.</p>
<h6 id="전역-환경-레코드-생성">전역 환경 레코드 생성</h6>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/99970232-9068-4b94-8e65-6d607c9c0a7c/image.svg" alt=""></p>
<p>전역 렉시컬 환경을 구성하는 컴포넌트인 전역 환경 레코드는 아래 세 가지를 제공합니다.</p>
<pre><code>1. 전역 변수를 관리하는 전역 스코프
2. 전역 객체의 built-in 전역 프로터티와 built-in 전역 함수
3. 표준 built-in 객체</code></pre><p><img src="https://velog.velcdn.com/images/55555-jyeon/post/2de2f397-a00f-4fd8-866f-7c87d9a136d7/image.svg" alt=""></p>
<p>전역 환경 레코드는 객체 환경 레코드와 선언전 환경 레코드로 구성되어 있습니다.
두 개의 컴포넌트는 서로 협력해 전역 스코프와 전역 객체를 관리합니다.</p>
<p>1️⃣ 객체 환경 레코드</p>
<pre><code>1. var 키워드로 선언한 전역 변수
2. 함수 선언문으로 정의한 전역 함수
3. built-in 전역 프로퍼티
4. built-in 전역 함수
5. 표준 built-in 객체</code></pre><p>2️⃣ 선언전 환경 레코드</p>
<pre><code>1. let, const 키워드로 선언한 전역 변수</code></pre><br />

<p>객체 환경 레코드는 BindingObject라는 객체와 연결되는데 이때 <strong>BindingObject</strong>는 전역 객체 생성에서 생성된 <strong>전역 객체</strong>입니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/48567fef-1f57-48a5-b6d4-349c94f6bb37/image.svg" alt=""></p>
<p>전역 코드 평가 과정에서 전역 변수(var 키워드로 선언)와 전역 함수는 BindingObject를 통해 전역 객체의 프로퍼티와 메서드가 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/86f12919-f602-4d9f-85bc-3770452bf3ce/image.svg" alt=""></p>
<p>이것이 전역 변수(var 키워드로 선언)와 전역 함수가 전역 객체를 가리키는 식별자(window) 없이 전역 객체의 프로퍼티를 참조할 수 있는 매커니즘입니다.</p>
<pre><code>example )  window.alert을 alert으로 참조</code></pre><p>객체 환경 레코드 외 렉시컬 환경을 구성하는 컴포넌트 중 하나인 선언적 환경 레코드도 생성됩니다. let, const 키워드로 선언한 전역 변수가 여기에 등록되고 관리됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/1086fee1-5c36-47e5-9671-6bf889c65a34/image.svg" alt=""></p>
<p>선언전 환경 레코드는 전역 객체의 프로퍼티가 되지 않기 때문에 전역 객체 프로퍼티로서 참조가 불가능합니다.</p>
<p>또한 const 키워드로 선언한 변수는 선언 단계와 초기화 단계가 분리되어 진행되므로 일시적 사각지대(TDZ : Temporal Dead Zone)에 빠지게 됩니다.</p>
<br />

<h6 id="this-바인딩">This 바인딩</h6>
<p>전역 환경 레코드의 [[GlobalThisValue]] 내부 슬롯에 this가 바인딩됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/06d9af15-e5f6-425e-93f8-78821776a308/image.svg" alt=""></p>
<p>일반적으로 전역 코드에서 this는 전역 객체를 가리키기 때문에 전역 객체가 바인딩되게 됩니다. </p>
<p>참고로 위 그림에서도 알 수 있지만, 객체 환경 레코드와 선언적 환경 레코드에는 this 바인딩이 없습니다.</p>
<br />

<h6 id="외부-렉시컬-환경에-대한-참조">외부 렉시컬 환경에 대한 참조</h6>
<p>외부 렉시컬 환경에 대한 참조는 현재 평가 중인 소소코드를 포함하는 외부 소스코드의 상위 스코프를 가리키기 때문에 이를 통해 스코프 체인을 구현할 수 있게 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/e9cdad3d-a0d3-475f-ab43-19e950eaf99c/image.svg" alt=""></p>
<p>현재 평가 중인 소스코드는 전역 코드이며 전역 코드를 포함하는 소스코드는 없기 때문에 여기에 null이 할당되게 됩니다. 이는 전역 렉시컬 환경이 스코프 체인의 종점에 존재함을 의미합니다. </p>
<br />
<br />

<h3 id="정리">정리</h3>
<blockquote>
<p>실행 컨텍스트란?</p>
</blockquote>
<p>실행 컨텍스트는 실행할 코드에 제공할 환경 정보를 모아놓은 객체로 해당 객체에는 변수 객체, 스코프 체인, this 정보가 담겨있습니다.
이 객체들을 콜 스택(실행 컨텍스트 스택)에 담아 순차적으로 실행시킵니다.</p>
<p>자동으로 전역 컨텍스트가 생성된 후 함수 호출시마다 함수 컨텍스트가 생성되고, 컨텍스트 생성이 완료된 후에 함수가 실행됩니다. </p>
<p>함수 실행 중에 사용 되는 변수들을 변수 객체 안에서 값을 찾고 값이 존재하지 않는다면 Lexical 환경의 outerEnvironmentReference(외부 렉시컬 환경에 대한 참조)를 통해 Scope 체인을 따라 올라가면서 탐색합니다. </p>
<p>함수 실행이 마무리가 되면 해당 컨텍스트는 사라지고, 페이지가 종료되면 전역 컨텍스트도 사라집니다.</p>
<blockquote>
<p>this 란?</p>
</blockquote>
<p>실행 컨텍스트의 this 바인딩에는 this로 지정된 객체가 저장됩니다.
실행 컨텍스트 활성화 당시에 this가 지정되지 않은 경우엔 this에 전역 객체가 저장됩니다.</p>
<p>그 밖에는 함수를 호출하는 방법에 따라 저장되는 대상이 달라집니다.</p>
<br />
<hr />

<p><em>References.</em></p>
<p>📚 <em>mostly based on. modern javascript DeepDive</em></p>
<p>👩🏻‍💻 posts.</p>
<ul>
<li>개발자 황준일 님의 <a href="https://junilhwang.github.io/TIL/Javascript/Domain/Execution-Context/#_2-%E1%84%89%E1%85%B5%E1%86%AF%E1%84%92%E1%85%A2%E1%86%BC-%E1%84%8F%E1%85%A5%E1%86%AB%E1%84%90%E1%85%A6%E1%86%A8%E1%84%89%E1%85%B3%E1%84%90%E1%85%B3-%E1%84%80%E1%85%AE%E1%84%89%E1%85%A5%E1%86%BC">자바스크립트 실행 컨텍스트</a></li>
<li>제로초 님의 실행 <a href="https://www.zerocho.com/category/JavaScript/post/5741d96d094da4986bc950a0">컨텍스트</a></li>
<li>Positive Ko&#39;s <a href="https://velog.io/@edie_ko/js-execution-context">실행 컨텍스트란 무엇인가요?</a></li>
<li>서연주 님의 <a href="https://velog.io/@kados22/FE-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94#:~:text=%EC%8B%A4%ED%96%89%20%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%8A%94%20%EC%8B%A4%ED%96%89%20%EA%B0%80%EB%8A%A5%ED%95%9C,%ED%9B%84%EC%97%90%20%ED%95%A8%EC%88%98%EA%B0%80%20%EC%8B%A4%ED%96%89%EB%90%A9%EB%8B%88%EB%8B%A4.">FE 기술 면접 실행 컨텍스트가 무엇인가요?</a></li>
</ul>
<p>🎥 videos.</p>
<ul>
<li>큰돌의 터전의 <a href="https://www.youtube.com/watch?v=RxaiFq2krAA">실행컨텍스트</a></li>
</ul>
<p>🖼️ images.
recreated by @55555-Jyeon</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Microtask Queue? Macrotask Queue?]]></title>
            <link>https://velog.io/@55555-jyeon/event-loop</link>
            <guid>https://velog.io/@55555-jyeon/event-loop</guid>
            <pubDate>Wed, 08 May 2024 15:29:53 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이벤트 루프에 대해서 설명해주세요.
마이크로태스크 큐와 매크로태스크 큐에 대해서 아시나요?</p>
</blockquote>
<p>위 두 개의 질문은 프론트엔드 개발자 면접에서 들을 수 있는 질문입니다.
질문을 받고 어디서부터 어디까지 설명할 수 있나요?</p>
<br />

<h2 id="execution-context">Execution Context</h2>
<p>이벤트 루프를 이해하기 전 간단하게 실행 컨텍스트에 대해 짚고 넘어가보겠습니다.</p>
<pre><code class="language-javascript">const foo = () =&gt; {}
const bar = () =&gt; {}

foo();
bar();</code></pre>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/c1dbb357-bd11-46d0-a5df-613d114daa26/image.png" alt=""></p>
<p>함수를 호출하게 되면 함수 코드가 평가되어 함수 실행 컨텍스트가 생성됩니다.
이때 생성된 함수 실행 컨텍스트는 콜 스택(call stack, 혹은 실행 컨텍스트 스택)에 push 되고 함수 코드가 실행되게 됩니다.</p>
<p>함수가 호출된 순서대로 순차적으로 실행되는 이유는 함수가 호출된 순서대로 실행 컨텍스트가 call stack에 push되기 때문입니다. 따라서 함수의 실행 순서는 call stack으로 관리되게 됩니다.</p>
<br />

<h2 id="동기-처리와-비동기-처리">동기 처리와 비동기 처리</h2>
<p>자바스크립트 엔진은 <strong>단 하나의 call stack</strong>(콜 스택, 실행 컨텍스트 스택)을 갖고 있습니다.</p>
<p>단 하나의 call stack을 갖는다는 말은 함수를 실행할 수 있는 창구가 단 하나 뿐이기 때문에 동시에 2개 이상의 함수를 실행할 수 없다는 것을 의미합니다.</p>
<p>한 번에 하나의 태스크(task)만 실행할 수 있는 것을 <strong>싱글 스레드</strong>(single thread) 방식으로 동작한다고 합니다. </p>
<p>하지만 자바스크립트 코드를 작성해 결과를 보다보면 동시에 여러 개의 함수들이 실행되는 것처럼 느껴질 때가 있습니다. 이는 싱글 스레드의 방식으로 인한 <strong>블로킹</strong>(blocking, 작업 중단)을 보다 효과적으로 처리하기 위한 <strong>비동기 처리</strong> 때문입니다.</p>
<p>비동기(asynchronous) 처리란 현재 실행 중인 태스크가 종료 되지 않은 상태라 하더라도 다음 태스크를 곧바로 실행하는 방식을 말합니다. 비동기 처리 방식으로 동작하는 함수로는 타이머 함수(setTimeout(), setInterval()), HTTP 요청과 이벤트 핸들러(eventHandler)가 있습니다.</p>
<blockquote>
<p>💡 <strong>자바스크립트는 싱글 스레드, 브라우저는 멀티 스레드</strong> <br/>
자바스크립트는 싱글 스레드 방식으로 동작합니다. 
이때 싱글 스레드 방식으로 동작하는 것은 브라우저가 아닌 브라우저에 내장된 자바스크립트 엔진이기 때문에 브라우저는 멀티 스레드로 동작한다는 것에 주의해야 합니다. <br/>
만약 모든 자바스크립트 코드가 자바스크립트 엔진에서 싱글 스레드 방식으로 동작한다면 자바스크립트는 비동기로 동작할 수 없기 때문입니다.</p>
</blockquote>
<br />

<h2 id="이벤트-루프">이벤트 루프</h2>
<p>HTML 요소가 애니메이션 효과를 통해 움직이면서 이벤트를 처리하거나 HTTP 요청을 통해 서버로부터 데이터를 갖고 오며 렌더링하기도 합니다. 이런 자바스크립트의 동시성(concurrency)을 지원할 수 있도록 도와주는 것이 이벤트 루프입니다.</p>
<p>이벤트 루프는 브라우저에 내장돼 있는 기능 중 하나로 브라우저 환경을 그림으로 표현하면 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/6bf76c00-15b5-4d78-bc92-8ecbcc8185fa/image.svg" alt=""></p>
<p>구글의 v8 자바스크립트 엔진은 크게 heap과 call stack, 2개의 영역으로 구분할 수 있습니다.</p>
<blockquote>
<p>📝 용어 정리 <br />
1️⃣ <strong>Heap</strong></p>
</blockquote>
<ul>
<li>객체가 저장되는 메모리 공간</li>
<li>콜 스택의 요소는 힙에 저장된 객체를 참조</li>
<li>구조화 X  <br />
2️⃣ **Call Stack**</li>
<li>소스코드 평가 과정에서 생성된 실행 컨텍스트가 추가/제거되는 스택 자료구조</li>
<li>실행 컨텍스트 스택이라고도 함</li>
</ul>
<br />

<p>자바스크립트 엔진은 단순히 태스크가 요청되면 콜 스택을 통해 요청된 작업을 순차적으로 실행시킵니다. 비동기 처리에서 소스코드의 평가와 실행을 제외한 모든 처리는 자바스크립트 엔진을 구동하는 환경인 브라우저 혹은 Node.js가 담당하게 됩니다.</p>
<p>예를 들면, 비동기 방식인 setTimeout의 콜백 함수의 평가와 실행은 자바스크립트 엔진이 담당하지만 호출 스케줄링을 위한 타이머 설정과 콜백 함수의 등록은 브라우저/Node.js가 담당하게 된다는 의미입니다.</p>
<p>이러한 과정을 위해 브라우저는 태스크 큐와 이벤트 루프를 제공하고 있습니다.</p>
<blockquote>
<p>📝 용어 정리 <br />
1️⃣ <strong>Task Queue</strong></p>
</blockquote>
<ul>
<li>task queue === event queue === callback queue</li>
<li>비동기 함수의 콜백 함수/이벤트 핸들러가 일시적으로 보관되는 영역<br />
2️⃣ **MicroTask Queue**</li>
<li>태스크 큐와는 별개</li>
<li>프로미스의 후속 처리 메서드의 콜백 함수가 일시적으로 보관</li>
<li>태스크 큐보다 <strong>우선순위가 높음</strong> ⭐️<br />
3️⃣ **Event Loop**</li>
<li>콜 스택에 현재 실행 중인 실행 컨텍스트가 있는지 &amp; 태스크 큐에 대기 중인 함수가 있는지 반복해서 확인 </li>
<li>콜 스택이 비어 있고 태스크 큐에 대기 중인 함수가 있다면 순차적(FIFO, 선입선출)으로 태스크 큐에 대기 중인 함수를 콜 스택으로 이동</li>
</ul>
<br />
<br />

<h3 id="example">example</h3>
<p>싱글 스레드, 동기와 비동기 처리, 이벤트 루프, 매크로태스크 큐, 마이크로태스크 큐...
많은 키워드가 지나갔는데 더 확실히 차이를 살펴보고 정립하기 위해서 하나의 예시를 살펴봅시다.</p>
<pre><code class="language-javascript">// 출력하고자 하는 내용
① 1+1
② 1초 뒤 2+2
③ 3+3 </code></pre>
<p>위와 같은 지문을 출력하고 싶다고 할 때 일반 프로그래밍 언어들은 아래 파이썬과 같이 출력하고 싶은 순서대로 작성할 수 있습니다. 보통 위에서 아래 방향으로 코드가 실행되기 때문입니다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/35e2e9cf-287f-4c6b-ab32-4cd87b9259d3/image.svg" alt="">CODES</th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/44d909c0-f388-41d9-9532-c35478af5f6a/image.svg" alt="">OUTPUT</th>
</tr>
</thead>
</table>
<p>좌측 사진과 같이 코드를 작성하고 확인을 해보면 우측과 같이 순서대로 결과가 터미널에 찍히는 것을 확인할 수 있습니다.</p>
<p>그럼 자바스크립트는 어떻게 될까요?</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/ee9f66d8-740d-4f8a-94fa-721fd3c5bb58/image.svg" alt="">CODES</th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/76b13a0c-f2e7-4e0f-b777-aff28c477c35/image.svg" alt="">OUTPUT</th>
</tr>
</thead>
</table>
<p>동일하게 다른 프로그래밍 언어들과 마찬가지로 출력되길 원하는 순서대로 코드를 작성하면 좌측 사진과 같습니다. 하지만 작성한 순서대로 결과가 콘솔에 찍히지 않는 것을 볼 수 있습니다. 시간이 더 걸리는 코드가 나중에 출력되고 있어요.</p>
<br />

<p><em>코드의 작성된 순서와 관계 없이 더 빨리 처리되는 코드부터 처리를 해주네?
자바스크립트는 병렬 처리를 해주는 코드인가봐 🫢</em></p>
<br />

<p>하는 생각이 들 수 있지만 <strong>아닙니다</strong>. 
다시 한 번 위에서 설명된 내용들을 토대로 코드를 살펴보겠습니다.</p>
<br />

<p>위에서 작성한 자바스크립트 코드는 아래와 같은 공간들에 배치되게 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/dfc7598e-c935-4280-8024-f4be4c334f1e/image.svg" alt=""></p>
<p>바로 처리할 수 없는, 어느 정도의 시간이 소요되는 작업의 경우에는 call stack에 쌓이지 않고 web API라는 코드들의 대기실과 같은 공간으로 보내집니다. </p>
<p>즉시 처리할 수 없는 코드들은 대기실로 좌천된다고 생각하면 편할 것 같네요.</p>
<p>call stack은 모든 코드들이 일사불란하게 처리돼야 하는 굉장히 바쁜 공간입니다. 
출퇴근의 지하철과 같은 공간이죠. 바빠 죽겠는데 누가 가운데에 덩그러니 서 있으면 방해되잖아요. </p>
<p>이렇게 오래 걸려 공간을 차지하게 될 코드들을 따로 web API라는 공간에 모아둠으로써 모든 코드들이 call stack에서는 순서대로 빠르게 처리될 수 있게 됩니다.</p>
<br />

<blockquote>
<p>Call Stack이 이름 그대로 stack의 자료 구조를 나타내는 것이라면 
후입선출이어야 하는데 왜 선입선출인 것처럼 동작하나요?</p>
</blockquote>
<p>예시에서 <code>console.log(1+1)</code>, <code>console.log(2+2)</code>, <code>console.log(3+3)</code>를 사용했고, 결과 값이 후입선출이라면 역순으로 6, 4, 2가 나와야 하는 것 아니냐는 의문이 생길 수 있을 것 같습니다.</p>
<p>콜 스택(call stack)의 후입선출(LIFO)은 주로 함수 호출과 관련이 있습니다. 
즉, 함수가 호출되면 해당 함수의 실행 컨텍스트가 call stack의 맨 위에 푸시(push)되고, 함수가 종료되면 해당 실행 컨텍스트가 팝(pop)되어 콜 스택에서 제거됩니다.</p>
<p>하지만 <code>console.log</code>는 함수 호출이라기보다는 브라우저나 실행 환경에서 제공하는 API이며, 이 API를 사용하여 결과를 콘솔에 출력합니다. 
따라서 <code>console.log</code>는 단순히 순차적으로 실행되는 문장이기 때문에 콜 스택에 푸시되지 않습니다. 이러한 코드들은 실행되는 즉시 완료되며 그 결과가 콘솔에 출력되게 됩니다.</p>
<p>따라서 이 경우 콜 스택의 동작 방식인 후입선출(LIFO)과는 직접적인 관련이 없습니다.
코드의 실행은 작성된 순서대로 순차적으로 진행되며, 결과가 콘솔에 출력되는 것은 브라우저나 실행 환경이 처리하는 부분이므로 결과가 콘솔에 출력되는 순서는 실행 컨텍스트의 푸시와 팝과는 무관합니다. 브라우저나 실행 환경의 내부 로직에 따라 결정되게 때문입니다.</p>
<br />

<p>다시 예시로 돌아오자면 :</p>
<p>바로 처리할 수 있는 코드들이 call stack에서 처리되고 난 다음에서야 callback queue에 있는 코드들이 실행될 기회가 옵니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/dc7ed24f-0f8e-4a57-ba9e-f01b03de71b1/image.svg" alt=""></p>
<p>web API에서는 시간이 걸리는 코드들이 모여 있는 대기 장소라고 설명했습니다.
예시에서의 setTimeout은 코드에 적힌 대로 1초 뒤에 실행돼야 하기 때문에 1초 동안 web API에서 대기해야 합니다.</p>
<p>onClick과 같은 이벤트 리스너들은 해당 이벤트가 발생할 때까지 대기해야 하고요.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/6e895a94-7a03-495f-8c3e-656a5dbf198a/image.svg" alt=""></p>
<p>대기가 끝난 web API의 코드들은 callback Queue로 보내지게 됩니다.
Queue에서 다시 한 번 차례대로 대기를 해야 합니다. Call Stack의 모든 코드들이 실행되어 공간이 비워져야만 callback Queue의 코드들이 실행될 수 있기 때문입니다.</p>
<br />
<br />

<h6 id="conclusion">conclusion</h6>
<h2 id="event-loop">Event Loop</h2>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/99ce6f8e-52e7-4c71-80ed-b878b907ff11/image.svg" alt=""></p>
<p>이벤트 루프(event loop)는 web API에서 대기가 완료되어 실행할 준비가 된 코드들을 순서대로 대기시킨 callback Queue(task Queue)의 코드들의 실행 타이밍을 확인해주는 역할을 합니다.</p>
<p>call stack이 비워졌는지 확인하고 비워졌을 때에만 callback queue의 코드들을 call stack으로 올려보내 실행될 수 있도록 해줍니다.</p>
<blockquote>
<p><strong>Event Loop에 대해서 설명해주세요.</strong> <br />
이벤트 루프는 큐에 할당된 함수를 순서에 맞춰 호출 스택(call stack)에 할당해주는 역할을 합니다.
이벤트 루프는 비동기 작업을 관리하는 매커니즘으로 프로그램이 외부 이벤트를 감지하고 적절히 처리할 수 있도록 도와줍니다.
call stack이 다 비워지면 callback queue에 존재하는 함수를 하나씩 call stack으로 옮기는 역할을 합니다.</p>
</blockquote>
<br />

<h2 id="macrotask--microtask">Macrotask &amp; Microtask</h2>
<p>그럼 매크로태스크 큐와 마이크로태스크 큐는 뭘까요?</p>
<p>위의 callback Queue(Task Queue)을 세부적으로 매크로태스크 큐와 마이크로태스크 큐로 나눌 수 있습니다.</p>
<p>마이크로태스크 큐와 매크로태스크 큐 모두 콜백함수가 들어간다는 점에서 공통점을 갖지만 어떤 함수를 실행하는지에 대한 차이가 있습니다. </p>
<p>이벤트 루프는 마이크로태스크 큐의 모든 태스크들을 처리한 다음, 태스크 큐의 태스크들을 처리합니다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/73aac699-4c75-40bf-9aa4-e6a3a15cf7ea/image.png" alt="">MACRO</th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/de122064-e1a7-4c17-83e8-e5ede034af1f/image.png" alt="">MICRO</th>
</tr>
</thead>
</table>
<p>이름을 보면 짐작해볼 수 있지만 비교적 적게 걸리는 건 마이크로태스크 큐에서, 비교적 오래 걸리는 규모가 큰 코드는 매크로태스크 큐에서 처리를 하게 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/d4a20d9c-1400-41c5-82f0-c8ac62305293/image.svg" alt=""></p>
<p>또한 명칭은 큐(Queue)이지만 자료구조의 큐와는 다릅니다.</p>
<p>엄밀히 말하자면 우선순위 큐 (Priority Queue) 라고 할 수 있는데,
이벤트 루프가 각각의 큐에서 태스크를 꺼내는 조건이 “<strong>제일 오래된 태스크</strong>”(FIFO, 선입선출) 이기 때문입니다.</p>
<br />

<blockquote>
<p><strong>마이크로태스크 큐</strong>(혹은 task queue)<strong>와 마이크로태스크 큐에 대해서 설명해주세요.</strong></p>
</blockquote>
<p><strong>| Macrotask Queue(Task Queue)</strong></p>
<p>매크로태스크 큐에는 주로 비교적 오랜 시간이 소요되는 함수들의 처리에 사용됩니다.
대표적인 예로는 setTimeout, setInterval, XMLHttpRequest, 이벤트 핸들러 등이 있습니다. </p>
<p>이러한 작업들은 브라우저나 Node.js 환경에서 비교적 오래 걸리는 작업으로 처리되며, 주로 콜 스택이 완전히 비어있을 때 실행됩니다.</p>
<p><strong>| Microtask Queue</strong></p>
<p>마이크로태스크 큐는 일반적으로 더 빠른 작업에 사용됩니다. 
대표적으로 Promise의 처리, MutationObserver 콜백, queueMicrotask 등이 해당됩니다. </p>
<p>마이크로태스크 큐의 작업은 현재 실행 중인 작업이 완료된 직후에 처리되며, 이러한 특성 때문에 매크로태스크 큐보다 우선순위가 높다고 볼 수 있습니다.</p>
<br />
<br />

<p>아래 GIF를 보면 더 잘 이해가 될 것 같습니다 🙂</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/04961deb-d8a9-4558-8eca-4afbb6869e8f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/2c2533f9-a5bb-4426-b7cb-3e7855c15e5a/image.png" alt=""></p>
<br />




<br />
<hr />

<p><em>References</em></p>
<p>📚 BOOKS</p>
<ul>
<li>이웅모가 집필한 모던 자바스크립트 DeepDive </li>
</ul>
<p>🎥 VIDEOS</p>
<ul>
<li>코딩애플의 <a href="https://www.youtube.com/watch?v=v67LloZ1ieI">개발자 90%가 모르는 자바스크립트 동작원리 (Stack, Queue, event loop)</a></li>
<li>Lydia Hallie&#39;s <a href="https://frontendmasters.com/courses/javascript-quiz/event-loop-task-queue/">Event Loop &amp; Task Queue</a></li>
<li>코드 스피츠의 <a href="https://youtu.be/0NsJsBdYVHI?si=QSwKv8WVVcjh7TY0">거침없는 자바스크립트 1회차</a></li>
</ul>
<p>👩🏻‍💻 BLOGS</p>
<ul>
<li>Bora Lee&#39;s <a href="https://ko.javascript.info/event-loop#ref-1407">Event Loop &amp; Macrotask Queue</a> </li>
<li>Bora Lee&#39;s <a href="https://ko.javascript.info/microtask-queue">Microtask Queue</a></li>
<li>Ashish Mishra&#39;s <a href="https://javascript.plainenglish.io/lets-spin-the-event-loop-by-ashish-mishra-8ec4d1412376">Let&#39;s spin the event loop</a></li>
<li>Javascript Jeep&#39;s <a href="https://medium.com/swlh/in-depth-introduction-to-call-stack-in-javascript-a07b8513bcc3">n-Depth Introduction to Call Stack in JavaScript.</a></li>
<li>55555-jyeon&#39;s <a href="https://velog.io/@55555-jyeon/data-structure">선형 자료 구조와 비선형 자료 구조</a></li>
<li>Minsu&#39;s Dev Log <a href="https://alstn2468.github.io/Javascript/2020-02-28-callstack">콜스택 (Call Stack)</a></li>
<li>Heejeong Choi&#39;s <a href="https://velog.io/@jennyfromdeblock/%ED%98%B8%EC%B6%9C-%EC%8A%A4%ED%83%9Dcall-stack">호출 스택(call stack)</a></li>
</ul>
<p>🌠 IMAGES</p>
<ul>
<li><a href="https://roseline.oopy.io/dev/javascript-back-to-the-basic/execution-context">실행 컨텍스트와 관련된 이미지 출처</a></li>
<li>이벤트 루프 gif 출처 → Lydia Hallie</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[왜 SEO를 해야 할까?]]></title>
            <link>https://velog.io/@55555-jyeon/SEO</link>
            <guid>https://velog.io/@55555-jyeon/SEO</guid>
            <pubDate>Wed, 24 Apr 2024 16:57:05 GMT</pubDate>
            <description><![CDATA[<p>프론트엔드에서 코딩을 하다보면 <em>&quot;<strong>검색엔진을 최적화해야 한다</strong>&quot;</em> 라는 말을 자주 보고 듣게 됩니다. 검색엔진을 최적화해야 한다는 것이 무슨 소리일까요?</p>
<br />

<h3 id="seo-그게-뭔데-🫤">SEO, 그게 뭔데 🫤</h3>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/b055765e-2323-4fa1-bd81-39c5cacf2f87/image.png" alt=""></p>
<p>검색엔진 최적화(SEO)는 Search Engine Optimization의 약어로, 검색엔진이 이해하기 쉽도록 홈페이지의 구조와 페이지를 개발해 검색 결과 상위에 노출될 수 있도록 하는 작업을 말합니다.</p>
<p>기본적인 작업 방식은 특정 검색어를 웹 페이지에 적절하게 배치하고 다른 웹 페이지에서 링크가 많이 연결되도록 하는 것입니다.</p>
<br />

<h3 id="seo-왜-해야-할까-🤔">SEO, 왜 해야 할까 🤔</h3>
<p>사용자가 구글, 네이버와 같은 검색 포털 사이트에서 특정 키워드를 검색하면 해당 키워드와 관련된 검색 결과가 출력됩니다. 
이때, <strong>검색 결과의 최상단에 &quot;우리&quot; 사이트를 위치하게</strong> 만드는 게 SEO를 하는 이유입니다. 검색 결과의 목록에서 후순위에 위치할수록 노출 효과는 급격히 떨어지게 되기 때문입니다.</p>
<p>결국 <strong>어떤 비즈니스 유형이든 SEO는 가장 중요한 마케팅 유형 중 하나</strong>일 수 밖에 없습니다. 검색 포털 사이트는 검색하는 사람들에게 긍정적인 사용자 경험(UX)을 선사하는 것이 목표이기 때문에 가능한 한 최고의 정보를 제공하길 원하기 때문입니다. 따라서, 검색 엔진 최적화를 위한 노력은 검색 엔진이 사이트의 콘텐츠를 특정 검색어에 대한 <strong>웹 상의 주요한 정보로 인식하도록 하는 과정</strong>에 포커스를 맞추어야 합니다.</p>
<br />

<h3 id="seo-동작-원리부터-🧐">SEO, 동작 원리부터 🧐</h3>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/5b04b214-e285-40ac-a45c-05ec0b5225c9/image.png" alt=""></p>
<p>사용자가 검색어를 입력하고 검색 결과를 확인하기까지 크게 아래와 같은 프로세스를 거치게 됩니다. SEO 과정이나 단계에 대해 검색을 해보면 적게는 4단계, 많게는 7단계까지 상세히 나눠져 있습니다. 그리고 내용도 조금씩 상이합니다.</p>
<p>키워드로 나눠보자면 세 단계로 압축해볼 수 있을 것 같습니다.</p>
<br />

<p>① <strong>크롤링 (Crawling)</strong>
웹 크롤러가 웹페이지의 콘텐츠를 복사해서 모든 정보를 수집하고 수집한 정보를 검색엔진으로 가져오는 단계</p>
<p>② <strong>인덱싱 (Indexing)</strong>
웹 크롤러가 검색엔진으로 가져온 정보를 주제별로 색인(index)해서 데이터를 보관하는 단계</p>
<p>③ <strong>랭킹 (Ranking)</strong>
색인된 콘텐츠를 검색 의도에 맞춰서 순위를 부여
사용자가 해당 키워드로 검색했을 때 랭킹 순서대로 결과를 제공하는 단계</p>
<br />
<br />

<h4 id="웹-크롤러">웹 크롤러</h4>
<p>위에서 언급된 웹 크롤러는 월드 와이드 웹에서 정보를 수집하는 컴퓨터 프로그램입니다. 검색 키워드와 검색 맥락을 파악하는 것부터 사이트를 상위로 노출하는 것까지 전부 웹 사이트의 크롤러 봇이 관여하게 됩니다. </p>
<blockquote>
<p>① 웹페이지가 어떤 콘텐츠를 가지고 있는지
② 해당 페이지가 무엇에 대한 것인지 </p>
</blockquote>
<p>검색 엔진은 위 두 가지를 판단하기 위해 <strong>웹페이지를 크롤링하는 로봇</strong>인 <strong>웹 크롤러</strong>를 사용합니다. 웹 크롤러는 코드를 스캔하여 웹페이지에 표시되는 텍스트, 이미지, 동영상을 등을 수집하여 가능한 모든 정보를 얻습니다. </p>
<p>웹 크롤러가 각 페이지에서 사용할 수 있는 정보 유형에 대한 충분한 정보를 수집하여 해당 내용이 검색자에게 유용하다고 판단하면 해당 페이지를 색인(index)에 추가합니다. 여기서 말하는 색인은 본질적으로 검색 엔진이 잠재적인 검색자에게 제공하기 위해 저장한 모든 가능성 있는 웹 결과입니다.</p>
<br />
<br />

<h3 id="seo-어떻게-설정해-😣">SEO, 어떻게 설정해? 😣</h3>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/58b96726-c550-4130-b6a4-2ce215528ee0/image.png" alt=""></p>
<p>검색엔진 최적화 작업은 사실상 비즈니스 현황을 이해하는 것에서부터 시작합니다. </p>
<p>자사의 사업 분야와 관련 경쟁사에 대한 리서치를 통해 타깃 기장을 분석하고, 자사 웹사이트 퍼포먼스 진단을 통해 검색엔진 최적화 마케팅 전략을 수립하는 등 모든 단계를 포함합니다. </p>
<p>어떤 부분이 검색 엔진의 순위에 가장 큰 영향을 미치는지에 대해서는 정확히 알 방법이 없기 때문에 SEO 전략에는 다양한 전술을 포함하는 것이 유리합니다. 이러한 전술은 크게 On-page SEO와 Off-page SEO라는 두 가지 범주로 나눌 수 있습니다.</p>
<h5 id="on-page-off-page">On-page? Off-page?</h5>
<p>On-page SEO는 디자인 및 작성한 콘텐츠에서부터 메타데이터, 대체 텍스트 등에 이르기까지 웹페이지 자체에 구현하는 전략을 말합니다. 
Off-page SEO는 페이지의 외부에서 수행하는 단계를 말합니다. 여기에는 외부 링크, SNS 게시물, 다른 웹사이트 프로모션 방식 등이 포함됩니다.</p>
<p>On-page SEO 및 Off-page SEO 모두 내 사이트로 트래픽을 유도하고, 궁극적으로 내 사이트가 인터넷에서 중요한 참가자라는 신호를 Google에 보내기 위해 필수적입니다. 내 페이지들이 중요하고, 사람들이 내가 제공하는 것들을 아는 것에 관심이 있다는 것을 검색엔진에게 알림으로써 내 페이지가 상위에 노출되고, 더 많은 트래픽을 유도하도록 만들 수 있습니다.</p>
<br />

<p>해당 포스팅에서는 프론트엔드 개발자가 관여할 부분인 테크니컬 SEO와 관련된 내용을 위주로 다룰 예정입니다.</p>
<br />

<h3 id="technical-seo">technical SEO</h3>
<p>테크니컬 SEO를 기점으로 본격적인 검색엔진 최적화 작업에 들어가게 됩니다. </p>
<p>구글이 발표한 랭킹 요소는 2021년 기준으로 200여 가지가 넘습니다. 하지만 랭킹 요소 200가지를 모두 동일하게 중요시할 필요는 없기 때문에 가장 중요한 요소를 우선적으로 적용하여 웹사이트를 최적화하는 것만으로도 웹사이트 퍼포먼스를 충분히 개선할 수 있습니다.</p>
<p>아래는 가장 기본적으로 적용해야 할 테크니컬 SEO 작업이기 때문에 신경을 써주는 것이 좋습니다.</p>
<br />

<h4 id="🔒-https">🔒 HTTPS</h4>
<p>2014년 구글은 공식적으로 보안은 구글의 최우선 순위이며, 사용자가 구글을 통해 접속하는 모든 웹사이트가 안전할 수 있도록 보안 프로토콜을 랭킹 요소로 지정하여 보안 프로토콜을 적용한 웹사이트에게 적용하지 않은 웹사이트(HTTP)보다 더 높은 점수를 부여할 것이라고 발표했습니다. </p>
<p>따라서 모든 웹사이트에 보안 프로토콜 (HTTPS) 적용을 <strong>강력히 권고</strong>하지만, 특히나 웹사이트 상에서 금전적 거래가 이루어지는 웹사이트 혹은 사용자의 개인 정보를 수집하는 웹사이트의 경우는 필수적으로 적용해야 합니다.</p>
<p>보안 프로토콜을 적용하는 데는 여러 가지 방법이 있습니다. 
그 중에서 클라우드 플레어 (CloudFlare)라는 웹사이트에서 무료로 HTTPS를 손쉽게 적용할 수도 있기 때문에 보안 프로토콜 적용 비용이 부담스러운 회사나 개인의 경우에는 이 방법을 이용하면 될 것 같습니다. 🙂</p>
<br />

<h4 id="🗺️-sitemap">🗺️ Sitemap</h4>
<p>웹사이트를 등록했다면 Sitemap을 제출해야 합니다. </p>
<blockquote>
<p><strong>Sitemap</strong>(사이트맵) 
웹사이트를 구성하는 개별 페이지의 목록을 담은 xml 파일</p>
</blockquote>
<p>검색 포탈에게 웹사이트의 존재를 알렸다면 이제 웹 크롤러가 웹사이트를 구성하는 개별 페이지를 모두 확인해 정보를 수집하게 됩니다. 웹 크롤러는 특정 페이지에서 다른 페이지로 연결된 하이퍼 링크를 따라가며 각 페이지의 정보를 파악합니다. 이때 페이지 사이의 연결이 잘 안 됐다면, 웹 크롤러가 개별 페이지를 읽는 과정에서 어려움을 겪게 됩니다.</p>
<p>이러한 문제를 해결하기 위해 사이트맵이 존재합니다. 사이트 맵은 웹사이트가 어떻게 구성됐는지 웹 크롤러에게 미리 알려줌으로써, 개별 페이지의 탐색을 잘 할 수 있도록 도와주는 (이름에서도 알 수 있지만) 일종의 지도 역할을 하는 겁니다.</p>
<h4 id="🗺️-react-router-sitemap">🗺️ <a href="https://www.npmjs.com/package/react-router-sitemap">react-router-sitemap</a></h4>
<p>① install → <code>npm i --save react-router-sitemap</code>
② <code>sitemapRoutes.js</code> 파일 생성
기존에 라우트를 관리하는 컴포넌트 파일이 존재한다면 해당 파일로 react-router-sitemap을 실행했을 때 Babel 이슈가 발생하기 때문에 새롭게 작성해주는 것이 좋습니다.</p>
<p>react-router의 버전에 따라 4 이전이라면 Route를, 4 이후라면 Switch를 사용하면 됩니다.</p>
<pre><code class="language-javascript">// sitemapRoutes.js
import React from &#39;react&#39;;
import { Switch } from &#39;react-router&#39;;

export default (
    &lt;Switch&gt;
        &lt;Route path=&#39;/&#39; /&gt;
        &lt;Route path=&#39;/about&#39; /&gt;
    &lt;/Switch&gt;
);</code></pre>
<p>③ <code>sitemapGenerator.js</code> 파일 생성
sitemapGenerator는 sitemap 파일을 생성하는 파일입니다.</p>
<pre><code class="language-javascript">require(&quot;@babel/register&quot;)({
  presets: [&quot;@babel/preset-env&quot;, &quot;@babel/preset-react&quot;]
});

const router = require(&quot;./sitemapRoutes&quot;).default; // sitemapRoutes 파일의 경로
const Sitemap = require(&quot;react-router-sitemap&quot;).default;

function generateSitemap() {
    return (
      new Sitemap(router)
          .build(&quot;https://www.yourDomainName.com&quot;) // 도메인 이름
          .save(&quot;./public/sitemap.xml&quot;) // sitemap.xml 파일이 생성될 위치
    );
}

generateSitemap();</code></pre>
<p>④ 위 파일을 실행하기 전 아래 dev dependecy들을 설치해주세요.</p>
<pre><code class="language-javascript">npm install --save-dev @babel/register @babel/preset-env @babel/preset-react</code></pre>
<p>⑤ <code>package.json</code> 파일에 sitemaGenerator 파일의 경로 추가</p>
<pre><code class="language-javascript">// package.json
    // ... 코드 생략
  &quot;scripts&quot;: {     
    // ... 코드 생략     
    &quot;sitemap&quot;: &quot;babel-node ./sitemaGenerator.js&quot;   
  } </code></pre>
<p>이제 <code>npm run sitemap</code> 명령어로 sitemap을 실행하게 되면 public 디렉토리 안에 <code>sitemap.xml</code> 파일이 생성된 것을 확인할 수 있게 됩니다.</p>
<br />

<h4 id="🤖-robotstxt">🤖 robots.txt</h4>
<p><code>robots.txt</code>를 로봇 배제 표준 파일이라고 하며 React 프로젝트 생성 시 기본적으로 제공되는 파일 중 하나이기도 합니다. 로봇 배제 표준 파일은 웹 크롤러의 접근을 차단 및 허용과 관련된 내용을 작성하는 용도로 사용됩니다. 구글이나 네이버를 포함한 모든 검색엔진 로봇에게 공통된 명령을 내릴 수도 있고 각 검색엔진 로봇별로 다른 명령을 내릴 수도 있습니다. </p>
<p>예를 들어, 웹사이트의 모든 페이지를 모든 검색엔진 크롤러에게 색인 허용하고 싶다면 아래와 같이 로봇 배제 표준 파일을 작성하면 됩니다.</p>
<pre><code class="language-javascript">User-agent: *
Allow: /</code></pre>
<p>여기서 User-agent는 웹 크롤러를 의미하며, * (별표) 입력 시 모든 크롤러에게 명령을 내린다는 뜻입니다.</p>
<br />

<h4 id="📋-matadata">📋 MataData</h4>
<p>메타데이터는 내 웹페이지에 포함된 내용을 설명하기 위해 Google에 제공하는 정보를 말합니다. 메타데이터의 중요한 측면에는 메타 설명과 타이틀 태그가 포함됩니다. </p>
<p>웹 크롤러에게는 또한 각 페이지 안에서 중요한 정보와 그렇지 않은 정보를 알려줄 필요가 있습니다. 중요도가 높은 정보를 강조할수록 웹 크롤러가 해당 페이지가 어떤 정보를 담고 있는지 쉽게 파악할 수 있기 때문입니다. </p>
<p>페이지의 정보 중요도를 알려주는 방식은 크게 두 가지로 나눌 수 있습니다. </p>
<p>① Mata Tag 삽입
② 태그의 위계질서 설정</p>
<p>메타 태그는 HTML 문서 안에 삽입되어 있으며 이 태그들은 해당 문서의 메타데이터, 즉 <strong>데이터에 대한 정보를 제공</strong>합니다. 이 정보는 주로 브라우저나 검색 엔진 등이 사용하며 웹 페이지의 제목, 설명, 작성자, 문자 인코딩 등을 포함할 수 있습니다. </p>
<p>메타 태그를 사용하면 사용자에게 웹 페이지의 내용과 관련된 보조 정보를 제공하거나, 검색 엔진이 웹 페이지를 색인할 때 도움이 됩니다. 또한 페이지의 핵심적인 내용이 무엇이지 크롤러 봇에게 바로 알려줄 수 있습니다.</p>
<p>대표적인 메타 태그로는 <code>&lt;title&gt;</code>, <code>&lt;meta charset&gt;</code>, <code>&lt;meta name=&quot;description&quot;&gt;</code>, <code>&lt;meta name=&quot;keywords&quot;&gt;</code> 등이 있습니다.</p>
<br />

<h4 id="🔖-og-tag">🔖 OG tag</h4>
<p>OG(Open Graph) 태그도 SEO에 빼놓을 수 없는 부분입니다.
오픈 그래프 태그는 웹 페이지의 링크가 카카오톡이나 다른 SNS에서 공유될 때 어떻게 노출될지를 정의할 수 있게 도와줍니다.</p>
<p>단순히 SNS를 통한 공유에 효과적일 뿐만 아니라 검색엔진 최적화 과정에서 해당 웹페이지가 SNS에서 얼마나 공유되고 있는지 판단하는 기준이 될 수도 있기 때문에 검색 상위 노출을 위한 품질 평가에도 영향을 줍니다.</p>
<ul>
<li><code>og:title</code> → 웹페이지 제목</li>
<li><code>og:description</code> → 웹페이지 상세 설명</li>
<li><code>og:image</code> → 웹페이지 카드에 나타나는 썸네일 이미지 (1200*630)</li>
<li><code>og:type</code> → 웹페이지 유형</li>
<li><code>og:url</code> → 웹페이지 주소</li>
</ul>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/84f6b255-6ea3-4744-91e1-013eecf46161/image.png" alt=""></p>
<p>위 공유된 링크에서 보일 내용들에 대한 정보는 아래와 같습니다.</p>
<pre><code class="language-typescript">import type { Metadata } from &quot;next&quot;;

export const metadata: Metadata = {
  title: &quot;Juyeon OH&quot;,
  description: &quot;juyeon OH&#39;s portfolio&quot;,
};</code></pre>
<p>metadata 안의 title이 <code>og:title</code>, description이 <code>og:description</code>과 같습니다. 그리고 썸네일 이미지에 대한 내용이 없음에도 <code>og:image</code>가 보여지고 있는 것을 확인할 수 있습니다.</p>
<p>이는 NextJS가 자체적으로 페이지를 렌더링할 때 미리보기 이미지를 생성하여 반환하는 기능을 제공하고 있기 때문입니다. 그래서 페이지를 공유했을 때 공유된 페이지에 Open Graph 태그가 없거나 이미지가 명시적으로 설정되지 않았더라도 기본 이미지가 생성되어 나타나게 됩니다. </p>
<p>만약 react로 만든 프로젝트라면 기본적으로 제공되는 <code>index.html</code> 파일 내에서 관련 코드를 작성해 추가할 수 있습니다.</p>
<p>아래는 제가 진행했던 다른 토이 프로젝트 중 하나인 postMobism의 index 파일입니다. </p>
<pre><code class="language-javascript">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;link rel=&quot;icon&quot; type=&quot;image/svg+xml&quot; href=&quot;/favicon.svg&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.googleapis.com&quot;&gt;
    &lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.gstatic.com&quot; crossorigin&gt;
    &lt;link href=&quot;https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght@0,100..900;1,100..900&amp;display=swap&quot; rel=&quot;stylesheet&quot;&gt;
    &lt;title&gt;post-mobism&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;script type=&quot;module&quot; src=&quot;/src/main.tsx&quot;&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/20d38a7d-3969-4e15-a66f-fae7a32ab2fc/image.png" alt=""></p>
<p>이렇게 오픈 그래프와 관련된 내용이 없다면 링크를 공유하게 되었을 때 페이지에 대한 정보가 나타나지 않게 됩니다.</p>
<br />

<p>오픈 그래프 태그는 아래와 같이 추가하면 됩니다.</p>
<pre><code class="language-javascript">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;!-- 🔖 Open Graph Meta Tags --&gt;
    &lt;meta property=&quot;og:title&quot; content=&quot;post-mobism&quot; /&gt;
    &lt;meta property=&quot;og:description&quot; content=&quot;post your code and get reviews&quot; /&gt;
    &lt;meta property=&quot;og:type&quot; content=&quot;website&quot; /&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;link rel=&quot;icon&quot; type=&quot;image/svg+xml&quot; href=&quot;/favicon.svg&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.googleapis.com&quot;&gt;
    &lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.gstatic.com&quot; crossorigin&gt;
    &lt;link href=&quot;https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght@0,100..900;1,100..900&amp;display=swap&quot; rel=&quot;stylesheet&quot;&gt;
    &lt;title&gt;post-mobism&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;script type=&quot;module&quot; src=&quot;/src/main.tsx&quot;&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>NextJS와는 달리 React로 프로젝트를 만들 경우 SEO에 신경을 더욱 쓸 수 밖에 없습니다. NextJS가 기본적으로 제공해주는 기능들을 React에서는 직접 구현해야 하기 때문이죠.</p>
<p>React는 SPA이기 때문에 웹 크롤러가 리액트로 제작된 웹사이트에 대한 정보를<code>public/index.html</code>, 단 하나의 파일에서만 얻을 수 있습니다. 이는 각각의 페이지에 대한 정보를 읽지 못한다는 단점으로 이어지게 되죠.</p>
<p>React에서도 NextJS처럼 페이지마다 메타태그를 별도로 지정하고 싶다면 <a href="https://github.com/nfl/react-helmet"><strong>react-helmet-async</strong></a> 라이브러리를 사용하면 됩니다.</p>
<br />

<h4 id="⛑️-react-helmet-async">⛑️ react-helmet-async</h4>
<p>이러한 라이브러리를 사용하는 이유는 React가 NextJS처럼 SSR이 아닌 SPA이기  때문입니다. SPA는 head 태그 내부는 수정할 수 없기 때문에 이와 같은 라이브러리를 사용할 수 밖에 없는 것이죠.</p>
<p>검색을 하다보면 <code>react-helmet</code>이라는 라이브러리도 있고 <code>react-helmet-async</code>라는 라이브러리도 있습니다.</p>
<p><code>react-helmet</code>은 react-side-effect에 의존하기 때문에 thread-safe하지 않습니다. 따라서, 비동기 데이터 처리에 문제가 생길 우려가 있습니다.</p>
<p><code>react-helmet-async</code>는 <code>react-helmet</code>의 단점을 보완해주는 라이브러리이므로 꼭 async를 사용해줘야 합니다.</p>
<blockquote>
<p><strong>thread-safe</strong>
여러 스레드로부터 동시에 접근이 이루어져도 프로그램의 실행에 문제가 없음</p>
</blockquote>
<hr />
<br />

<p>react-helmet-async의 적용 방법은 간단합니다. </p>
<p>① install → <code>npm i react-helmet-async</code> / <code>yarn add react-helmet-async</code>
② <code>&lt;HelmetProvider&gt;</code>로 <code>&lt;App /&gt;</code> 감싸기</p>
<pre><code class="language-javascript">// Index.js
import { HelmetProvider } from &#39;react-helmet-async&#39;;

ReactDOM.render(
    &lt;BrowserRouter&gt;
      &lt;HelmetProvider&gt;
        &lt;App /&gt;
      &lt;/HelmetProvider&gt;
    &lt;/BrowserRouter&gt;
);</code></pre>
<p>③ <code>app.js</code> 안에 <code>&lt;helmet&gt;</code>으로 메타태그 적용</p>
<pre><code class="language-javascript">// App.js
import { Helmet } from &#39;react-helmet-async&#39;;

const App = () =&gt; {
  return (
    &lt;&gt;
      &lt;Helmet&gt;
        &lt;title&gt;your project name&lt;/title&gt;
      &lt;/Helmet&gt;
      &lt;RouterProvider router={router} /&gt;
    &lt;/&gt;
  );
};</code></pre>
<p>페이지별 메타태그는 각 페이지 컴포넌트 파일 안에 <code>app.js</code>와 마찬가지로 helmet 컴포넌트를 통해 정의해주면 됩니다.</p>
<blockquote>
<p>Helmet 메타태그 우선순위
더 깊숙한 곳에 위치한 Helmet이 우선순위가 더 높습니다.</p>
</blockquote>
<p>react-helmet을 사용해 메타 태그를 설정하려고 하는데 <code>index.html</code>에 이미 메타 태그와 관련된 코드가 있다면 중복 메타 태그들은 반드시 삭제해 중복 적용을 막아야 합니다.</p>
<p>메타태그의 내용을 따로 분리해 관리하고 싶다면 <code>metatags.js</code>와 같이 별도의 파일로 만들면 좋을 것 같습니다. </p>
<br />

<h4 id="img-alt⭐️-"><code>&lt;img alt=&quot;⭐️&quot; /&gt;</code></h4>
<p>대체 텍스트는 내 사이트에 표시되는 이미지에 대한 짧은 설명을 말합니다. 이는 사이트의 HTML에 포함되어 있으며, 중요한 SEO 에셋입니다. 웹 크롤러는 이미지 내용을 이해하기 위해 대체 텍스트를 빠르게 읽을 수 있습니다.</p>
<p>대체 텍스트는 시각 장애인 웹 브라우저가 눈으로 보지 않아도 페이지의 전체적인 그림을 파악할 수 있도록 도와주는 중요한 <strong>접근성 기능</strong>이기도 합니다. 웹페이지를 소리 내어 읽는 도구는 이미지를 볼 수 없는 사람들에게 어떤 이미지가 포함되어 있는지 설명하는 대체 텍스트를 읽어줍니다.</p>
<p>SEO가 목적이라면 여러분의 대체 텍스트에 대해 전략적으로 생각하고 사이트를 더 많이 알릴 수 있는 키워드를 포함하는 것이 좋습니다. 하지만, 대체 텍스트는 키워드에만 초점을 맞출 수 없습니다. 이미지가 묘사하는 것을 정확하게 설명하고 있는지 또한 중요하기 때문입니다.</p>
<br />

<h4 id="📱-responsive">📱 Responsive</h4>
<p>예전에는 집집마다 컴퓨터가 있었지만 요즘은 가족 구성원마다 핸드폰을 갖고 있습니다. 컴퓨터를 통한 검색량이 모바일을 통한 검색량에 뒤쳐지게 되면서 모바일 중심 색인 생성이 중요해졌습니다. </p>
<blockquote>
<p><strong>모바일 중심 색인 생성</strong>
모바일 버전의 콘텐츠를 우선적으로 색인한다는 의미입니다.</p>
</blockquote>
<p>그렇다 보니 웹사이트 모바일 친화성은 아주 중요한 랭킹 요소가 되었습니다.
웹사이트의 모바일 친화성은 반응형이 적용되어 있는가와 밀접한 연관이 있습니다.</p>
<p>만약 모바일 전용 웹사이트(예: m.example.com)를 사용 중인 경우에는 모바일 웹사이트와 데스크톱 웹사이트의 상관관계를 알리는 <strong><a href="https://www.twinword.co.kr/blog/how-to-apply-canonical-tag-properly/">캐노니컬 태그</a></strong> 를 반드시 적용해야 합니다.</p>
<p>캐노니컬 태크는 <code>&lt;head&gt;</code>태그 안에 삽입하는 코드로 특정 웹페이지의 대표 url주소를 검색엔진에게 알려주는 역할로 상위노출 시키는데 중요한 역할을 합니다.</p>
<br />

<h4 id="💡-lighthouse">💡 Lighthouse</h4>
<p>페이지 로딩 속도란 웹사이트 혹은 웹 페이지를 클릭했을 때 로딩되기까지 시간이 얼마나 걸리는지를 의미합니다. 페이지 로딩 속도는 사용자 경험에 막대한 영향을 끼치기 때문에 보안 프로토콜, 모바일 친화성과 함께 구글이 가장 중요하게 생각하는 랭킹 요소 중 하나입니다. </p>
<p>구글은 데스크톱의 경우 3초 미만, 모바일의 경우 2초 미만의 로딩 속도를 보유한 웹사이트가 가장 경쟁력이 있다고 보고 있습니다. </p>
<p>웹사이트 로딩 속도는 구글이 제공하는 <a href="https://pagespeed.web.dev/?utm_source=psi&amp;utm_medium=redirect&amp;hl=ko">PageSpeed Insights</a> 도구를 통해 진단할 수도 있고 개발자 도구의 Lighthouse로도 진단할 수 있습니다. Lighthouse와 페이지 로딩 속도에 대한 자세한 내용은 제 다른 게시글인 <a href="https://velog.io/@55555-jyeon/React-optimise">&lt;React, 성능 최적화 (feat.Devtools)&gt;</a>에서 확인할 수 있습니다.</p>
<br />

<h4 id="🔑-keyword">🔑 keyword</h4>
<p>SEO를 이해하고 구현하는 데 있어서 가장 중요한 부분 중 하나는 키워드 리서치입니다. 키워드 리서치는 내 웹페이지에서 사용할 가장 관련성이 높은 단어를 찾는 과정입니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/49daaaf7-cba4-41ea-837e-ed3d0647b7c3/image.png" alt=""></p>
<p>전문적인 키워드 리서치 도구를 사용함으로써 전 세계 사람들이 자사 혹은 개인의 제품 또는 서비스와 관련된 것들을 어떻게 검색하는지 이해할 수 있습니다. 검색엔진마다 키워드 리서치 도구를 제공하기 때문에 주 타겟이 될 검색엔진의 서비스를 이용하는 것이 좋겠죠? 🙂</p>
<blockquote>
<p>구글 → <a href="https://support.google.com/google-ads/answer/7337243?hl=ko">키워드 플래너</a>
네이버 → <a href="https://saedu.naver.com/help/faq/ncc/view.naver?faqSeq=64">키워드 도구</a></p>
</blockquote>
<br />

<h4 id="🔍-seo-service">🔍 SEO service</h4>
<p>검색 포털 사이트마다 SEO를 위해 제공하는 서비스도 있습니다. </p>
<blockquote>
<p>구글 → <a href="https://search.google.com/search-console/welcome">Search console</a>
네이버 → <a href="https://searchadvisor.naver.com/">Search advisor</a></p>
</blockquote>
<p>위의 서비스는 두 가지 기능을 제공합니다. </p>
<p>① 검색 포탈에서 웹사이트를 등록
② 포탈에서 자사 사이트의 검색 데이터를 확인</p>
<p>단, 위 서비스를 통해 웹 사이트를 등록하려면 한 가지 조건이 충족되어야 합니다. 바로 HTML의 <code>&lt;head&gt;</code> 안에 관련 정보를 저장하는 <code>&lt;meta&gt;</code> 태그를 추가하는 것입니다. </p>
<p><code>&lt;meta&gt;</code> 태그는 직접 추가할 수도 있고 도메인을 통해 간접적으로 등록할 수도 있습니다. </p>
<br />
<hr />

<p><em>References.</em></p>
<ul>
<li><a href="https://growthacking.kr/%EA%B2%80%EC%83%89%EC%97%94%EC%A7%84%EC%97%90-%EC%82%AC%EC%9D%B4%ED%8A%B8-%EB%93%B1%EB%A1%9D%ED%95%98%EA%B8%B0-seo/">검색엔진에 사이트 등록하기 SEO</a></li>
<li><a href="https://eopla.net/magazines/5082">초기 창업 팀을 위한 검색 노출(SEO) 가이드</a></li>
<li><a href="https://lasbe.tistory.com/179">[React] SPA 사이드 프로젝트 검색 엔진 최적화(SEO) 끝장내기</a></li>
<li><a href="https://seo.tbwakorea.com/blog/seo-guide-2022/">SEO (검색엔진 최적화)란? – 구글, 네이버 가이드 총정리</a></li>
<li><a href="https://yozm.wishket.com/magazine/detail/1540/">검색엔진 최적화(SEO)란?</a></li>
<li><a href="https://ujeon.medium.com/react-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EC%82%AC%EC%9D%B4%ED%8A%B8%EB%A7%B5-%EB%A7%8C%EB%93%A4%EA%B8%B0-1116ff8b6c2a">[React] 리액트 웹사이트 사이트맵 만들기</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[선형 자료 구조와 비선형 자료 구조]]></title>
            <link>https://velog.io/@55555-jyeon/data-structure</link>
            <guid>https://velog.io/@55555-jyeon/data-structure</guid>
            <pubDate>Sat, 20 Apr 2024 11:27:52 GMT</pubDate>
            <description><![CDATA[<h6 id="본-게시글은-면접을-위한-cs-전공지식노트의-내용을-정리한-글입니다">본 게시글은 &lt;면접을 위한 CS 전공지식노트&gt;의 내용을 정리한 글입니다.</h6>
<br />
<hr />

<h1 id="자료-구조">자료 구조</h1>
<h6 id="data-structure">data structure</h6>
<ul>
<li>자료 구조는 효율적으로 데이터를 관리, 수정, 삭제, 탐색, 저장할 수 있는 데이터 집합 </li>
<li>C++은 STL을 기반으로 전반적인 자료 구조를 가장 잘 설명할 수 있는 언어</li>
</ul>
<blockquote>
<p><strong>STL</strong>
C++의 표준 템플릿 라이브러리이자 스택, 배열 등 데이터 구조의 함수 등을 제공하는 라이브러리의 묶음</p>
</blockquote>
<br />
<br />

<h2 id="복잡도">복잡도</h2>
<h3 id="시간-복잡도">시간 복잡도</h3>
<p align="center">
  <img width="40%" src="https://github.com/inside-coding/cs-note/assets/134191817/a4071084-80f7-4d40-9052-883d5d252b0c" />
</p>


<ul>
<li>입력 크기에 대해 어떠한 알고리즘이 실행되는 데 걸리는 시간</li>
<li>주요 로직의 반복 횟수를 중점으로 측정</li>
<li>일반적으로 <strong>빅오 표기법</strong>으로 나타냄</li>
<li><strong>효율적인 코드로 개선하는데 쓰이는 척도</strong></li>
</ul>
<h5 id="빅오-표기법">빅오 표기법</h5>
<ul>
<li>입력 범위 n을 기준으로 로직이 몇 번 반복되는지 나타내는 표기법</li>
<li>가장 영향을 많이 끼치는 항의 상수 인자를 빼고 나머지 항을 제외</li>
<li>입력 크기가 커질수록 연산량이 가장 많이 커지는 항만 신경 쓰면 된다는 이론</li>
</ul>
<br />

<h4 id="자료-구조에서의-시간-복잡도">자료 구조에서의 시간 복잡도</h4>
<p>아래는 자주 쓰이는 자료 구조의 시간 복잡도를 나타낸 표입니다.
보통 시간 복잡도를 생각할 때 평균과 최악을 고려하며 사용합니다.</p>
<p align="center">
  <img width="70%" src="https://github.com/inside-coding/cs-note/assets/134191817/c1db6ef0-dae4-4bfe-ab5d-af628595cef2" />
  <img width="70%" src="https://github.com/inside-coding/cs-note/assets/134191817/f9a6bf13-8bc2-4db5-a69c-42f4af996299" />
</p>

<br />

<h3 id="공간-복잡도">공간 복잡도</h3>
<ul>
<li>프로그램을 실행시켰을 때 필요로 하는 자원 공간의 양</li>
<li>공간을 계속해서 필요로 하는 경우도 포함</li>
</ul>
<br />
<hr />

<h2 id="선형-자료-구조">선형 자료 구조</h2>
<p>요소가 일렬로 나열돼 있는 자료 구조</p>
<h3 id="연결-리스트">연결 리스트</h3>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/b51a4d6e-c01d-42aa-ab5a-bc0d7226d94c" />
</p>

<ul>
<li>데이터를 감싼 노드를 포인터로 연결해 공간적인 효율성을 극대화시킨 자료 구조</li>
<li>삽입과 삭제 → O(1)</li>
<li>탐색 → O(n)</li>
<li>next와 prev 포인터로 앞/뒤의 노드를 연결시킨 것</li>
<li>맨 앞에 있는 node는 head node라고 함</li>
<li><strong>데이터 추가와 삭제</strong>에 용이</li>
</ul>
<br />

<h4 id="연결-리스트-종류">연결 리스트 종류</h4>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/73394dfd-92b7-46a1-9fa1-d123f58e4c3f" />
</p>

<ul>
<li><strong>싱글 연결 리스트</strong> : next 포인터만</li>
<li><strong>이중 연결 리스트</strong> : next 포인터 + prev 포인터 둘 다</li>
<li><strong>원형 이중 연결 리스트</strong> : 마지막 노드의 next 포인터가 head node를 가리킴 (나머지는 이중 연결 리스트와 동일)</li>
</ul>
<br />

<h3 id="배열-array">배열 (Array)</h3>
<ul>
<li>같은 타입의 변수들로 이뤄짐</li>
<li>크기가 정해져 있음</li>
<li>인접한 메모리 위치에 있는 데이터를 모아놓은 집합</li>
<li>중복을 허용</li>
<li>순서가 존재</li>
<li>접근/참조 → O(1)</li>
<li>삽입과 삭제 → O(n)</li>
<li>랜덤 접근 가능</li>
<li><strong>접근/참조</strong>에 용이</li>
</ul>
<br />

<h4 id="랜덤-접근과-순차적-접근">랜덤 접근과 순차적 접근</h4>
<p align="center">
  <img width="40%" src="https://github.com/inside-coding/cs-note/assets/134191817/c9d9577f-878d-4ec3-a1b1-2e7109ef85b6" />
</p>

<ul>
<li><strong>랜덤 접근</strong> : 동일한 시간에 배열과 같은 순차적인 데이터가 있을 때 임의의 인덱스에 해당하는 데이터에 접근할 수 있는 기능</li>
<li><strong>순차 접근</strong> : 데이터를 저장된 순서대로 검색</li>
</ul>
<h4 id="배열과-연결-리스트의-차이">배열과 연결 리스트의 차이</h4>
<ul>
<li>배열 : 상자를 순서대로 나열한 데이터 구조 → 몇 번째 상자인지 알면 해당 상자의 요소를 끄집어낼 수 있음</li>
<li>리스트 : 상자를 선으로 연결한 데이터 구조 → 상자 안 요소를 알기 위해선 상자 내부를 확인해야 함</li>
</ul>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/6ea3b337-5e49-47c2-aefd-2df801eb8522" />
</p>

<p>접근/참조는 배열이 용이하고 추가와 삭제는 리스트가 용이합니다.</p>
<br />

<h3 id="벡터-vector">벡터 (Vector)</h3>
<ul>
<li>동적으로 요소를 할당할 수 있는 동적 배열</li>
<li>컴파일 시점에 개수를 모를 경우 사용</li>
<li>중복을 허용</li>
<li>순서 존재</li>
<li>랜덤 접근 가능</li>
<li>탐색과 맨 뒤 요소 삭제와 삽입 → O(1)</li>
<li>맨 뒤가 아닌 요소 삭제와 삽입 → O(n)</li>
</ul>
<br />

<h3 id="스택-stack">스택 (Stack)</h3>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/df1fb95a-9303-4c04-b01e-5a28c06c6b89" />
</p>

<ul>
<li>선입선출 (LIFO)</li>
<li>삽입과 삭제 → O(1)</li>
<li>탐색 → O(n)</li>
<li>사용 : 재귀적인 함수, <strong>알고리즘</strong>, <strong>웹 브라우저 방문 기록</strong> 등</li>
</ul>
<br />

<h3 id="큐-queue">큐 (Queue)</h3>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/35addbf5-482a-4089-9543-c00626f950e8" />
</p>

<ul>
<li>후입선출 (FIFO)</li>
<li>삽입과 삭제 → O(1)</li>
<li>탐색 → O(n)</li>
<li>사용 : CPU 작업을 기다리는 프로세스, <strong>스레드 행렬</strong>, <strong>네트워크 접속을 기다리는 행렬</strong>, 너비 우선 탐색, <strong>캐시</strong> 등</li>
</ul>
<br />
<hr />

<h2 id="비선형-자료-구조">비선형 자료 구조</h2>
<p>일렬로 나열하지 않고 자료 순서나 관계가 복잡한 구조</p>
<br />

<h3 id="그래프-graph">그래프 (Graph)</h3>
<p align="center">
  <img width="40%" src="https://github.com/inside-coding/cs-note/assets/134191817/5279f9cf-5119-41ef-982a-d9f08664d680" />
</p>

<ul>
<li>정점과 간선으로 이뤄진 자료 구조</li>
<li>&quot;어떠한 곳에서 무언가를 통해 간다.&quot; 에서 어떠한 곳은 정점(vertex), 무언가는 간선(edge)</li>
<li>단방향 간선과 양방향 간선</li>
</ul>
<p align="center">
  <img width="40%" src="https://github.com/inside-coding/cs-note/assets/134191817/8a2cb855-fdf7-4fb8-a21b-885309b13c0d" />
</p>

<ul>
<li>정점으로 나가는 간선을 해당 정점의 outerdegree, 들어오는 간선을 해당 정점은 indegress라고 함</li>
<li>보통 어떤 정점으로붜 시작해 어떤 정점까지 간다 === &quot;U에서부터 V까지 간다.&quot;</li>
<li><strong>가중치</strong> : 간선과 정점 사이에 드는 비용</li>
</ul>
<br />

<h3 id="트리">트리</h3>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/3a44acab-f73f-4b60-bba8-5eac151a023b" />
</p>

<ul>
<li>그래프 중 하나로 그래프의 특징처럼 정점과 간선으로 이뤄짐</li>
<li>트리 구조로 배열된 일종의 계층적 데이터의 집합</li>
<li>구성요소 : 루트 노드, 내부 노드, 리프 노드</li>
<li>숲 : 트리로 이뤄진 집합</li>
</ul>
<h4 id="트리의-종류">트리의 종류</h4>
<h5 id="이진-트리">이진 트리</h5>
<p>자식의 노드 수가 두 개 이하인 트리</p>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/bdbd35e1-e178-4f5b-8b2d-c16041eb2b44" />
</p>

<ul>
<li><strong>정이진 트리</strong> : 자식 노드가 0 또는 두 개인 이진 트리</li>
<li><strong>완전 이진 트리</strong> : 왼쪽에서부터 채워져있는 이진 트리</li>
<li><strong>변질 이진 트리</strong> : 자식 노드가 하나 밖에 없는 이진 트리</li>
<li><strong>포화 이진 트리</strong> : 모든 노드가 꽉 차 있는 이진 트리</li>
<li><strong>균형 이진 트리</strong> : 왼쪽과 오른쪽 노드의 높이 차이가 1 이하인 이진 트리</li>
</ul>
<br />

<h4 id="이진-탐색-트리-bst">이진 탐색 트리 (BST)</h4>
<p>노드의 오른쪽 하위 트리에는 &#39;노드 값보다 큰 값&#39;이 있는 노드만 포함되고 왼쪽 하위 트리에는 &#39;노드 값보다 작은 값&#39;이 들어 있는 트리</p>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/948969eb-c910-4b50-847f-f1d031b727e4" />
</p>

<br />

<h4 id="avl-트리">AVL 트리</h4>
<h6 id="adelson-velsky-and-landis-tree">Adelson-Velsky and Landis tree</h6>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/9c6cb769-87e6-48f9-8590-0c0dcab2b18d" />
</p>


<ul>
<li>위에 있는 최악의 경우 선형적인 트리가 되는 것을 방지하고 스스로 균형을 잡는 이진 탐색 트리</li>
<li>두 자식 서브 트리의 높이는 항상 최대 1만큼 차이가 난다는 특징 존재</li>
</ul>
<br />

<h4 id="레드-블랙-트리">레드 블랙 트리</h4>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/4b26b87f-1a0c-4338-b1ee-f035588f845f" />
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/4fd677a1-b144-454b-b208-6239d0cbfb3e" />
</p>

<ul>
<li>균형 이진 탐색 트리</li>
<li>탐색, 삽입, 삭제 모두 시간 복잡도가 O(logn)</li>
<li>각 노드는 빨간색/검은색의 색상을 나타내는 추가 비트를 저장</li>
<li>삽입과 삭제 시 트리가 균형을 유지하도록 하는 데 사용</li>
<li>규칙 : &quot;모든 리프 노드와 루트 노드는 블랙이고 어떤 노드가 레드이면 그 노드의 자식은 반드시 블랙이다.&quot;</li>
</ul>
<br />

<h3 id="힙-heap">힙 (heap)</h3>
<ul>
<li>완전 이진 트리 기반의 자료 구조</li>
<li>최소힙과 최대힙</li>
<li>해당 힙에 따라 특정한 특징을 지킨 트리</li>
<li>어떤 값이 들어와도 특정 힙의 규칙을 지키도록 만들어짐</li>
</ul>
<br />

<h3 id="우선순위-큐-priority-queue">우선순위 큐 (Priority Queue)</h3>
<p align="center">
  <img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/84dfcb04-394b-43c1-8dc5-7331ac820282" />
</p>

<ul>
<li><strong>대기열</strong>이라고도 함</li>
<li>우선순위가 높은 요소가 우선순위가 낮은 요소보다 먼저 제공되는 자료 구조</li>
<li>힙을 기반으로 구현</li>
</ul>
<br />

<h3 id="맵-map">맵 (Map)</h3>
<ul>
<li>특정 순서에 따라 키와 매핑된 값의 조합으로 형성된 자료 구조</li>
<li>레드 블랙 트리 자료 구조를 기반으로 형성</li>
<li>삽입 시 자동으로 정렬</li>
<li>map은 해시 테이블을 구현할 때 사용</li>
<li>정렬 보장이 되지 않는 unordered_map과 정렬을 보장하는 map으로 나뉨</li>
</ul>
<br />

<h3 id="셋-set">셋 (Set)</h3>
<ul>
<li>특정 순서에 따라 고유한 요소를 저장하는 컨테이너</li>
<li>중복되는 요소는 없고 오로지 희소한 unique 값만 저장하는 자료 구조</li>
</ul>
<br />

<h3 id="해시-테이블-hash-table">해시 테이블 (hash table)</h3>
<ul>
<li>무한에 가까운 데이터들을 유한한 개수의 해시 값으로 매핑한 테이블</li>
<li>삽입,삭제, 탐색 시 평균적으로 O(1) 시간 복잡도를 가짐</li>
<li>unordered_map으로 구현</li>
</ul>
<br />
<hr />]]></description>
        </item>
        <item>
            <title><![CDATA[비동기 처리로 더 빠르고 부드러운 UX 🏃‍♀️]]></title>
            <link>https://velog.io/@55555-jyeon/suspenseerrorBoundary</link>
            <guid>https://velog.io/@55555-jyeon/suspenseerrorBoundary</guid>
            <pubDate>Fri, 19 Apr 2024 16:01:05 GMT</pubDate>
            <description><![CDATA[<h1 id="suspense">Suspense</h1>
<p>웹에서의 Lazy Loading이란 필요한 자원을 미리 가져오지 않고 필요할 때 가져오는 전략을 말합니다. 웹에서 필요한 모든 자원들은 Lazy Loading의 대상이 될 수 있습니다. </p>
<p>뿐만 아니라 데이터를 미리 다 불러오지 않고 필요할 때 불러와 화면을 채우게 할 수 있기 때문에 axios나 fetch등의 클라이언트를 사용해 서버에 요청을 보내 가져오는 데이터(AJAX) 역시 Lazy Loading의 한 종류로 볼 수 있습니다. </p>
<p>주로 JS 번들을 스플리팅하고 웹 자원 중 코드를 Lazy Loading하는데 쓰였던 Suspense는 React 18에서 무엇이든 기다릴 수 있는 기능으로 확장됩니다. Suspense는 이제 이미지, 스크립트, 그 밖의 비동기 작업을 기다리는데에 모두 사용 될 수 있는 기능입니다. </p>
<br />


<p>가장 일반적인 세 가지 렌더링 아키텍처와 리액트 Suspense의 역할은 아래와 같습니다 : </p>
<p>1️⃣ <strong>CSR</strong>
<code>React.lazy</code>가 로드되는 동안 폴백을 표시합니다. 
Suspense 호환 프레임워크로 데이터를 불러올 때 로딩/오류를 선언적으로 처리합니다.
<br /></p>
<p>2️⃣ <strong>SSR</strong>
(CSR 내용 포함)
<code>&lt;Suspense /&gt;</code>로 감싸진 SSR 컴포넌트는 클라이언트에서 선택적으로 hydration됩니다.
<br /></p>
<p>3️⃣ <strong>Server Component</strong>
(SSR 내용 포함)
<code>&lt;Suspense /&gt;</code>로 감싸진 비동기 서버 컴포넌트는 단계적으로 클라이언트에서 스트리밍됩니다. fallback → 최종 콘텐츠 순으로 스트리밍됩니다.</p>
<br />
<hr />

<h3 id="1️⃣-csr">1️⃣ <strong>CSR</strong></h3>
<p>CSR은 리액트의 가장 기본적인 렌더링 방법입니다. 
<br /></p>
<p>① 요청 시 <strong>서버는 html 파일로 응답</strong>을 보냅니다. 
이때 html 파일은 JS bundle을 참조하는 <code>&lt;script&gt;</code> 태그가 있는 기본적인 형태입니다.</p>
<p>② 자바스크립트가 로드되고 실행되면 <strong>페이지에 콘텐츠를 생성</strong>하고 빈 html 파일을 채웁니다. </p>
<p>③ 네비게이션은 완전히 클라이언트 측에서 이루어지며 서버에 추가 요청을 하지 않으므로 Suspense의 첫 번째 사용 사례로 이어집니다. </p>
<br />

<p>JS bundle에는 앱의 모든 부분을 생성하는 데 필요한 코드가 포함되어 있기 때문에 상당히 커질 수 있습니다. 페이지의 콘텐츠가 렌더링되기 전에 전체 자바스크립트 파일을 로드, 구문 분석 및 실행해야 하므로 이는 <strong>심각한 성능 병목 현상</strong>이 됩니다.</p>
<br />
<br />

<h3 id="lazy-loading">Lazy Loading</h3>
<p>앱을 여러 개의 다른 JS bundle로 분할하여 각각 필요할 때만 클라이언트에 전송하기 위해 <code>Suspense</code>와 <code>React.lazy</code>를 사용할 수 있습니다.</p>
<p>React 16.6부터 추가된 Suspense는 주로 JS bundle의 Lazy Loading을 위한 기능이었습니다.  <code>React.lazy</code>를 사용해 컴포넌트를 동적으로 import 후 Suspense로 감싸주면 자동으로 bundle이 분리되고(Code Splitting) 해당 컴포넌트가 렌더링될 필요가 있을 때 React가 비동기적으로 bundle을 가져오는 방식입니다.</p>
<pre><code class="language-javascript">// 지연 로딩
const ProfilePage = React.lazy(() =&gt; import(&#39;./HomePage&#39;)); 

// HomePage를 불러오는 동안 스피너를 표시
&lt;Suspense fallback={&lt;Spinner /&gt;}&gt;
  &lt;HomePage /&gt;
&lt;/Suspense&gt;;</code></pre>
<p>비동기로 load되는 컴포넌트를 감싸는 Suspense 컴포넌트의 fallback prop으로 로딩 UI를 넣어주면, 컴포넌트를 가져오는 동안 보여줄 로딩 UI를 선언적으로 지정할 수 있습니다. JSX를 복잡하게 만들지 않고 직관적으로 로딩 UI를 지정할 수 있다는 점이 특히 편리합니다.</p>
<br />
<br />

<h3 id="2️⃣-ssr">2️⃣ <strong>SSR</strong></h3>
<blockquote>
<p>현재 SSR 프레임워크는 선택적 하이드레이션을 지원 ❌ <br />앱 디렉토리를 사용하는 <strong>Next.js 애플리케이션에서만</strong> 서버에서 html로 렌더링되는 클라이언트 컴포넌트에 대한 <strong>선택적 하이드레이션을 지원</strong>합니다. </p>
</blockquote>
<p>CSR에 비해 SSR은 JS bundle이 로드되고 실행되는 동안 사용자가 서버에서 생성된 일부 html을 볼 수 있으므로 첫 페이지 로드 시 <strong>더 나은 사용자 경험</strong>을 제공합니다. 하지만 자바스크립트가 없으면 어차피 페이지와 상호 작용할 수 없기 때문에 Suspense의 세번째 사용 사례인 <strong>선택적 하이드레이션</strong>이 발생하게 됩니다. </p>
<p><code>Suspense</code>로 컴포넌트를 감싸게 되면 리액트는 해당 컴포넌트를 페이지의 다른 컴포넌트들과 별개로 hydration을 진행합니다. 언뜻 보기에는 선택적 하이드레이션과 큰 차이가 없어 보입니다. 모든 hydration된 html이 클라이언트에 한꺼번에 전송되면 전체 페이지가 동시에 hydration될 것이기 때문입니다. </p>
<p>하지만 아래 두 가지 상황에서 차이가 드러납니다 :</p>
<br />

<p>① <strong>여러 컴포넌트를 Suspense로 감싸는 경우</strong></p>
<p>리액트는 사용자가 현재 어떤 컴포넌트와 상호작용하고 있는지에 따라 어떤 컴포넌트를 먼저 hydration할지 결정할 수 있습니다. 
즉, 리액트는 페이지 내에서 우선순위를 정해 사용자와 상호 작용 가능한 부분을 먼저 hydration해 제공한 후 백그라운드에서 페이지의 나머지 부분을 hydration할 수 있다는 겁니다. 자바스크립트 구문 분석 및 실행에 병목 현상이 발생할 수 있는 느린 기기에서는 사용자에게 더 빠른 경험을 제공할 수 있습니다.</p>
<br />

<p>② <strong>스트리밍 아키텍처를 사용하는 경우</strong></p>
<p>페이지의 여러 부분을 클라이언트에 개별적으로 전송할 수 있으므로 페이지의 다른 부분이 서버에서 렌더링되는 동안 특정 html 청크를 클라이언트에 전송하여 선택적으로 hydration할 수 있습니다.</p>
<h6 id="스트리밍-아키텍처란">스트리밍 아키텍처란?</h6>
<p>스트리밍 아키텍처는 데이터나 콘텐츠를 조각조각으로 전송하는 방식을 가리킵니다. 
이러한 방식을 사용하면 전체 데이터나 콘텐츠가 준비되지 않았더라도 일부분을 클라이언트로 전송하여 이를 먼저 사용할 수 있게 됩니다. 특히 SSR에서는 페이지의 일부분을 서버로부터 클라이언트로 스트리밍하여 사용자가 더 빠르게 페이지를 볼 수 있도록 하는데 사용될 수 있습니다.</p>
<br />
<br />

<h3 id="3️⃣-server-component">3️⃣ <strong>Server Component</strong></h3>
<p>서버 컴포넌트는 클라이언트로 전송되기 전에 서버에서 html을 렌더링하는 리액트 컴포넌트입니다. SSR과 비슷한 점이 많지만 서버 컴포넌트는 서버 전용이며 클라이언트에서 실행되지 않습니다. 사용자와 상호 작용을 하는 event handler, state 또는 hook을 사용할 수 없습니다. 즉, 서버 컴포넌트는 사용자와의 상호 작용이 필요 없는 정적 데이터를 가져오고 렌더링하는 데 최적화되어 있습니다.</p>
<br />


<pre><code class="language-javascript">export default async function Post() {
  const data = await fetch(...)

  return &lt;div&gt;{data}&lt;/div&gt;
}</code></pre>
<p>위 예시를 한 번 살펴 봅시다.
데이터가 로드될 때까지 기다린 다음 콘텐츠를 html로 렌더링하여 클라이언트로 전송하고 있습니다. 비동기 작업이 완료될 때까지 컴포넌트는 화면에 렌더되지 않으므로 사용자는 해당 페이지에서 빈 화면 밖에 볼 수 없습니다.</p>
<p>이러한 상황을 위해 로딩 상태가 만들어졌습니다. 
Suspense를 사용하면 서버 컴포넌트에 로딩 상태를 부여할 수 있습니다.</p>
<pre><code class="language-javascript">async function Post() {
  const data = await fetch(...)

  return &lt;div&gt;{data}&lt;/div&gt;
}

export default function Wrapper() {
  return (
    &lt;Suspense fallback={&lt;div&gt;Loading ...&lt;/div&gt;}&gt;
      &lt;Post /&gt;
    &lt;/Suspense&gt;
  )
}</code></pre>
<p>비동기 서버 컴포넌트를 <code>&lt;Suspense /&gt;</code>로 감싸면, 리액트는 컴포넌트에서 필요로 하는 데이터들을 불러오는 동안 fallback을 렌더링해 클라이언트로 먼저 보냅니다. 그러면 사용자는 fallback의 loading 화면을 보고 있게 되는 것입니다.
이후 데이터 로딩이 완료되면 컴포넌트 자체에서 렌더링된 콘텐츠를 전송해 사용자가 해당 html의 내용을 보게 됩니다. 이 과정을 스트리밍이라고 합니다.</p>
<br />
<hr />
<br />


<h1 id="error-boundary">Error Boundary</h1>
<p>Suspense는 비동기 작업을 처리하고 사용자 경험을 향상시키는 데 중요한 역할을 합니다. 그러나 애플리케이션에서 발생하는 예기치 못한 런타임 에러는 별도의 처리가 필요합니다. 이때 Error Boundary가 중요한데, 이를 통해 애플리케이션의 안정성을 유지하고 사용자에게 친숙한 오류 화면을 제공할 수 있습니다.</p>
<p>즉, 언젠가는 예상치 못한 곳에서 문제가 생길 수 있다는 사실을 인지하고 이를 다루기 위한 Fault Tolerance이 필요합니다.
<br /></p>
<h4 id="fault-tolerance내결함성이란">Fault Tolerance(내결함성)이란?</h4>
<blockquote>
<p>내결함성이란 시스템이 시스템을 구성하는 컴포넌트 중 일부가(하나 또는 그 이상) 고장나더라도 계속 동작할 수 있도록 하는 속성입니다.</p>
</blockquote>
<p>React 앱에 내결함성을 부여하기 위해서는 결과부터 말하자면 error boundary를 사용하면 됩니다.</p>
<br />

<h4 id="error의-boundary는">error의 boundary는?</h4>
<p>Error Boundary를 적용하는 것 자체는 전혀 어렵지 않습니다. 
고려해야 하는 것은 error boundary를 어디에 배치할지입니다. 골디락스의 원리를 따라 <strong>&quot;딱 적당한&quot;</strong> 만큼 error boundary를 설정하는 것이 제일 좋겠지만 다시 적당하다의 기준이 무엇인지 고민해봐야 합니다.</p>
<p>적당하다의 기준을 세우기 위해서는 먼저 극단적인 예시를 통해 각각 어떤 문제가 발생하는지 파악해볼 필요가 있습니다.</p>
<br />

<h6 id="부족하게">부족하게</h6>
<h3 id="최상단에-위치한-단-하나의-error-boundary">최상단에 위치한 단 하나의 Error Boundary</h3>
<p>최상단에 App 컴포넌트를 감싸는 단 하나의 error boundary만 있다는 것은 아래와 같습니다. </p>
<p>이렇게 코드를 짜게 되면 서버 측에서 렌더링되는 애플리케이션이 고장날 때와 결과가 유사하게 나타나게 됩니다. 최악의 경험은 아니겠지만 최선의 조치도 아닙니다. </p>
<p>이러한 에러 처리가 초래하는 문제는 결국 한 군데만 고장나도 전체가 고장난 것처럼 보인다는 것입니다.</p>
<pre><code class="language-javascript">import ErrorBoundary from &quot;react-error-boundary&quot;;
import App from &quot;./App.js&quot;;

ReactDOM.render(
  &lt;ErrorBoundary&gt;
    &lt;App /&gt;
  &lt;/ErrorBoundary&gt;
);</code></pre>
<p>내결함성이란 시스템이 시스템을 구성하는 컴포넌트 중 일부가 고장나더라도 계속 동작할 수 있도록 하는 속성입니다.</p>
<blockquote>
<p>결과적으로 단일 Error Boundary의 경우 하나의 컴포넌트에서 문제가 발생하게 되면 전체 애플리케이션이 망가지기 때문에 사실상 <strong>내결함성을 제공하지 못한다</strong>고 볼 수 있습니다.</p>
</blockquote>
<br />

<h6 id="넘쳐나게">넘쳐나게</h6>
<h3 id="모든-컴포넌트마다-error-boundary">모든 컴포넌트마다 Error Boundary</h3>
<p>반대로 모든 컴포넌트를 Error Boundary로 감싸게 된다면 어떻게 될까요?</p>
<pre><code class="language-javascript">// 모든 컴포넌트에 Error Boundary를 부여할 경우
&lt;form&gt;
  &lt;ErrorBoundary&gt;
    &lt;CartDescription items={props.items} /&gt;
  &lt;/ErrorBoundary&gt;
  &lt;ErrorBoundary&gt;
    &lt;CreditCardInput /&gt;
  &lt;/ErrorBoundary&gt;
  &lt;ErrorBoundary&gt;
    &lt;CheckoutButton cartId={props.id} /&gt;
  &lt;/ErrorBoundary&gt;
&lt;/form&gt;</code></pre>
<p>전의 상황과 반대되기 때문에 내결함성을 확실하게 제공할 수 있겠다는 생각이 들 수 있습니다. 하지만 이 방식의 문제점은 단순히 오류가 미치는 영향을 최소화하는것과 내결함성은 다르다는 것입니다.</p>
<p>예를 들어, <code>CreditCardInput</code>에서 에러가 발생하는 상황을 살펴봅시다 :</p>
<pre><code class="language-javascript">&lt;form&gt;
  &lt;ErrorBoundary&gt;
    &lt;CartDescription items={props.items} /&gt;
  &lt;/ErrorBoundary&gt;
  &lt;ErrorBoundary&gt;
    {/* Oops! Error Occured! 😢 */}
    &lt;CreditCardInput /&gt; 
  &lt;/ErrorBoundary&gt;
  &lt;ErrorBoundary&gt;
    &lt;CheckoutButton cartId={props.id} /&gt;
  &lt;/ErrorBoundary&gt;
&lt;/form&gt;</code></pre>
<p>① <code>&lt;CreditCardInput /&gt;</code>은 자체적인 Error Boundary를 가지기 때문에 해당 오류는 <code>CheckoutForm</code> 컴포넌트로 전파되지 않습니다. </p>
<p>② 하지만 <code>&lt;CheckoutForm /&gt;</code>은 <code>&lt;CreditCardInput /&gt;</code> 컴포넌트 없이는 사용이 불가합니다. </p>
<p>③ <code>&lt;CheckoutButton /&gt;</code>과 <code>&lt;CardDescription /&gt;</code>는 여전히 마운팅된 상태이기 때문에 사용자는 장바구니를 확인하고 결제 시도를 진행할 수 있습니다.</p>
<br />

<p>위와 같은 상황에서 발생할 문제는 바로 아래 질문들을 통해 확인할 수 있습니다 :</p>
<p>만약 사용자가 카드 정보를 <code>&lt;CreditCardInput /&gt;</code> 에 오류가 발생하기 전에 입력을 했다면 그 상태는 보존될까요? 🤔</p>
<p>그 상태로 결제 시도를 하면 어떻게 되죠? 😵‍💫 </p>
<br />

<p>사용자는 결국 혼란스러운 사용자 경험을 하게 될 것입니다.</p>
<p>모든 컴포넌트를 error boundary로 감싸는 것의 문제점은 여기서 끝이 아닙니다. 각 error boundary의 fallback 값이 어떤 것이냐에 따라서도 다양한 혼란을 겪게 됩니다.</p>
<p>fallback 값이 없어서 해당 컴포넌트가 그냥 보여지지 않는 상황도 혼란스러울 것이고, 공유 fallback UI를 사용할 때에도 마찬가지입니다.
UI가 부재 중인 상황보다는 낫지만 모든 컴포넌트를 다 error boundary로 감싼 상황이라면 각각의 컴포넌트의 오류 상황에 맞게 fallback을 제공해야 합니다.</p>
<p>각각의 컴포넌트들은 서로 다른 레이아웃/크기를 갖을 가능성이 높기 때문에 이를 올바르게 구현하는 것도 어려울 뿐더러 구현했다고 하더라도 정말 조잡할 것입니다. 
자세히 설명하자면 페이지 단위의 컴포넌트에 맞춘 fallback UI는 input이나 button과 같은 컴포넌트에는 적용할 수 없을 것입니다. (그 반대도.)</p>
<blockquote>
<p>결과적으로 모든 컴포넌트를 error boundary로 감싸는 것은 <strong>혼란스럽고 조잡한 사용자 경험을 제공</strong>하게 됩니다. 애플리케이션 상태의 <strong>일관성을 해쳐</strong> 사용자들에게 <strong>혼동과 실망을 초래</strong>하기 때문입니다. </p>
</blockquote>
<br />


<h6 id="적당하게">적당하게</h6>
<h2 id="적당한-error-boundary">적당한 Error Boundary</h2>
<p>애플리케이션의 특성마다 상황이 다르기 때문에 정확한 수치를 제시하는 것은 어렵습니다. 가장 좋은 접근방식은 애플리케이션의 <strong>기능 경계를 파악</strong>하고 error boundary를 그곳에 배치하는 것입니다.</p>
<br />

<blockquote>
<p>⚠️ <strong>성능 패널티</strong> 
Error Boundary는 오버헤드를 가지고 있어서, 과도하게 사용할 경우 성능에 부정적인 영향을 줄 수 있으므로 남용하면 안 됩니다.</p>
</blockquote>
<br />
<br />

<h3 id="1️⃣-기능의-경계가-어디일까">1️⃣ 기능의 경계가 어디일까?</h3>
<p>대부분의 애플리케이션은 독립적인 섹션들을 조합해서 만들어집니다. 각 요소의 컴포넌트들의 집합이 하나의 페이지를 그려내고 개별 컴포넌트들은 어느 정도의 독립성을 유지하게 됩니다.</p>
<p>layout으로 나누는 구조를 떠올리면 편합니다.
기본적으로 header, content(main혹은 section), footer로 나뉘죠. content는 다시 side menubar와 같이 고정된 컴포넌트와 바뀌는 컴포넌트들로 나뉠 수 있습니다.</p>
<p>아래 인스타그램 홈페이지를 만든다면 박스 친 부분들이 각각 컴포넌트가 될 겁니다. 일반적으로 딱 봤을 때 분리된 section들은 독립적인 기능을 갖기 때문에 이런 부분들에 각각 error boundary를 배치하는 것이 좋습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/40be44af-534c-41f1-8016-a356614cdd66/image.png" alt=""></p>
<p>위의 컴포넌트들 중 하나에 문제가 생겼다고 다른 부분에 지장이 가서는 안 된다고 볼 수 있습니다. 위 페이지에서 이어 예를 들자면, 위 친구들의 목록이 뜨는 부분에 에러가 발생했다고 좌측의 menubar가 화면에 렌더되지 않으면 안 된다는 겁니다.</p>
<br />

<h3 id="2️⃣-각-컴포넌트들-간의-주고-받을-영향-고려해보기">2️⃣ 각 컴포넌트들 간의 주고 받을 영향 고려해보기</h3>
<p>error boundary의 배치를 더욱 정석에 가깝게 하고 싶다면 아래와 같은 질문을 하는 것이 가장 좋습니다.</p>
<blockquote>
<p>&quot;이 컴포넌트에서 <strong>발생할 에러가</strong> 형제 컴포넌트들에게 <strong>어떻게 영향을 미쳐야 할까?</strong>&quot; </p>
</blockquote>
<p>각 컴포넌트들 간의 관계를 생각하며 error의 boundary를 정하는 것이 가장 적절한 위치일테니까요.</p>
<p>위 인스타그램 페이지에서 계속 이어 예시를 들어보겠습니다.</p>
<p>인스타그램 친구들의 게시물을 불러오는 과정에서 지연이나 에러가 발생한 상황입니다. 이러한 에러 상황이 좌측 menubar에 영향을 끼쳐야 할까요?</p>
<p>더 자세히 풀어보자면 :</p>
<p>① 친구들의 게시물의 부재로 인해 좌측 menubar도 같이 화면에 렌더되지 않는 것이 맞을까요? 
② 친구들의 게시물의 부재가 menubar와 연관이 있을 필요가 있나요?</p>
<p>각 컴포넌트들 간에 영향을 주고 받아야 한다면 같은 경계 안에 넣어두는 것이 좋겠죠? 🙂</p>
<br />
<br />

<blockquote>
<p><strong>Chaos Engineering</strong>
내결함성을 테스트하기 위해 의도적으로 오류를 발생시키는 것은 카오스 엔지니어링의 가장 가벼운 예제 중 하나입니다.</p>
</blockquote>
<h3 id="3️⃣-고의적으로-에러를-발생시켜보기">3️⃣ 고의적으로 에러를 발생시켜보기</h3>
<p>컴포넌트들 간의 주고 받을 영향을 고려하는 것이 어렵다면 실제로 에러를 발생시켜 직접 확인하는 것도 하나의 확실한 방법이 될 수 있습니다.</p>
<pre><code class="language-javascript">function OnePost(props) {
  // ✅ throw new Error on purpose 
  throw new Error(&quot;oops, Error Occured!&quot;);
  return (
      &lt;main&gt;/*...코드 생략...*/&lt;/main&gt;
  );
}</code></pre>
<br />
<hr />

<h1 id="suspense--error-boundary">suspense + error boundary</h1>
<p>일반적으로 비동기 요청은 로딩, 실패(에러), 성공의 3가지 상태를 갖습니다. 이 3가지의 상태에 해당하는 UI를 Suspense와 ErrorBoundary를 함께 사용해 모두 선언적으로 표현할 수 있습니다.</p>
<blockquote>
<p><strong>선언형 프로그래밍</strong> : 비동기 상태값에 따른 UI를 Prop으로 주입하기</p>
</blockquote>
<br />

<pre><code class="language-javascript">
function OnePost() {
  const { data } = apiClient.read(&#39;api/post&#39;);
  return (
    &lt;div&gt;{data.content}&lt;div/&gt;
  )
}

function App() {
  return (
    &lt;ErrorBoundary fallback={&lt;Error/&gt;}&gt; // 실패 UI
      &lt;Suspense fallback={&lt;Spinner/&gt;}&gt; // 로딩 UI
        &lt;OnePost /&gt; // 성공 UI
      &lt;/Suspense&gt;
    &lt;/ErrorBoundary&gt;
  )
}</code></pre>
<p>Suspense는 데이터 가져오기와 같은 비동기 작업을 처리하고, Error Boundary는 예기치 못한 에러를 적절하게 처리하여 애플리케이션의 안정성을 유지할 수 있도록 도와줍니다.
결과적으로 사용자가 원활하게 상호작용할 수 있도록 데이터를 로딩하고 오류를 처리하여 더욱 향상된 사용자 경험을 제공하기 때문입니다.
Suspense와 Error Boundary를 함께 활용함으로써 비동기 처리를 통해 더 빠르고 부드러운 사용자 경험을 제공할 수 있습니다.</p>
<br />
<hr />

<p><em>References.</em></p>
<ul>
<li><p>officials
<a href="https://react.dev/reference/react/Suspense">react official page about suspense</a></p>
</li>
<li><p>suspense
<a href="https://elanmed.dev/blog/suspense-in-different-architectures">[원문] React Suspense in three different architectures</a>
<a href="https://velog.io/@lky5697/suspense-in-different-architectures">[번역] 세 가지 아키텍처에서의 리액트 Suspense</a></p>
</li>
<li><p>error-boundary
<a href="https://www.brandondail.com/posts/fault-tolerance-react">[원문]Fault Tolerance</a>
<a href="https://velog.io/@plrs9816/error-boundary-fault-tolerance">[번역] 유연하게 React 오류 처리하기 - 내결함성과 Error Boundary</a>
<a href="https://kyuhyuk.kr/article/react/2022/05/24/Use-react-error-boundary-to-handle-errors-in-React">react-error-boundary를 사용하여 오류 처리하기</a></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[debounce? throttle?]]></title>
            <link>https://velog.io/@55555-jyeon/debounce-throttle</link>
            <guid>https://velog.io/@55555-jyeon/debounce-throttle</guid>
            <pubDate>Mon, 01 Apr 2024 16:49:35 GMT</pubDate>
            <description><![CDATA[<p>디바운싱(Debouncing)과 쓰로틀링(Throttling)은 자바스크립트의 개념이라기 보다는 프로그래밍 기법중 하나입니다. 둘 다 디바이스에게 무리를 주지 않기 위해 사용되곤 합니다. 일종의 최적화라고 볼 수 있습니다.</p>
<p>Throttle와 Debounce는 자주 사용 되는 이벤트나 함수들이 실행되는 빈도를 줄여서 성능 상의 유리함을 가져오기 위한 개념입니다.</p>
<p>자주 사용되는 간단한 예로 자동 완성을 들 수 있습니다.</p>
<p>키보드가 한자씩 입력될 때마다 api로 데이터를 가져오게 되면 사용자의 의도와 무관한 요청이 자주 발생하게 됩니다. 이를 줄이기 위해 입력이 끝난 후나 입력되는 중간 중간 특정 시간(ms)마다 api 값을 가져온다면 성능에서 매우 유리해지게 됩니다.</p>
<p>Throttle은 입력 주기를 방해하지 않고 일정 시간 동안의 입력을 모아서 한 번에 출력을 제한하는 것이고 Debounce 는 입력 주기가 끝나면 출력하게 합니다.</p>
<p>위 예제에서 Throttle은 특정 시간마다 api 값을 가져오는 것이고, Debounce 는 입력이 끝난후 api 값을 가져오는 것입니다.</p>
<h2 id="🏈-debounce">🏈 Debounce</h2>
<h3 id="사전에-등록된-의미">사전에 등록된 의미</h3>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/8954b1c6-320d-45c8-96d5-1f415514b7ab/image.png" alt=""></p>
<p>debounce 는 사전에 등재된 단어는 아닙니다. 
<strong>Debouncing</strong>이라는 단어만 컴퓨터 사이언스 용어로 등재되어 있습니다. </p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/99c2b2d1-c048-41b2-83b8-6dfd0f4c53a4/image.png" alt=""></p>
<p>위 내용을 번역하면 아래와 같습니다.</p>
<blockquote>
<p><strong>Debouncing</strong>은 시간이 많이 걸리는 작업이 너무 자주 실행되어 웹 페이지의 성능이 저하되지 않도록 하는 데 사용되는 프로그래밍 방식입니다. <br /> 즉, <strong>함수가 호출되는 속도를 제한</strong>합니다. JavaScript의 디바운싱은 브라우저 성능을 향상시키는 데 사용되는 방식입니다.</p>
</blockquote>
<p>전자 쪽에서도 bouncing 이라는 용어가 있습니다. 
스위치들이 접점에서 떨어지거나 붙는 시점에 <strong>물리적으로 미세하게 여러 번의 on/off 가 되는 현상</strong>을 뜻합니다. </p>
<p>이는 의도했던 바가 아니므로 방지하는 게 좋습니다.
그런 의미에서 이런 불필요한 튀는 현상( 여러 on/off 발생)을 방지하는 의미에서 debouncing이라고 표현한 것 같습니다. 처음에 말했던 &#39;여러 이벤트가 발생할 때, 일정 그룹으로 묶어서 하나로 처리&#39;하는 debouncing의 의미와 어느 정도 부합한다고 볼 수 있습니다.</p>
<br />

<p>다시 한 번 정리하자면: 
Debounce는 여러번 발생하는 이벤트에서 가장 마지막 이벤트만을 실행 되도록 만드는 개념입니다. 그리고 가장 마지막 이벤트만을 실행해 성능성 유리함을 가져올 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/bba8d654-e468-4cbe-9d01-78e8c3378957/image.png" alt=""></p>
<h3 id="debounce-example">debounce example</h3>
<br />

<p><strong>1️⃣ scroll</strong></p>
<p align="center">
  <img src="https://github.com/55555-Jyeon/nextLog/assets/134191817/f277193f-9eae-4557-a7c7-b44b32d99d30" />
</p>

<p>스크롤 이벤트에 debounce를 적용하는 경우, 일정 시간 동안 스크롤 이벤트가 여러 번 발생하더라도 마지막 스크롤 위치만 사용하여 처리됩니다. 일반적으로 스크롤 이벤트는 사용자가 스크롤을 할 때마다 많은 양의 이벤트가 연속적으로 발생할 수 있습니다. 이런 경우에 모든 스크롤 이벤트를 처리하면 성능이 저하될 수 있습니다.</p>
<p>따라서 debounce를 적용하면, 연속적으로 발생하는 스크롤 이벤트를 일정 시간 동안 무시하고, 마지막 스크롤 위치만 고려하여 한 번만 처리합니다. 이렇게 함으로써 성능을 향상시킬 수 있으며, 사용자 경험을 개선할 수 있습니다. debounce를 사용하면 스크롤 이벤트가 연속적으로 발생할 때마다 처리되는 것이 아니라, 일정 시간이 지난 후에 한 번만 처리되므로 스크롤 이벤트에 대한 응답이 부드럽고 효율적으로 이루어집니다.</p>
<br />
<br />

<p><strong>2️⃣ input</strong></p>
<p align="center">
  <img src="https://github.com/55555-Jyeon/nextLog/assets/134191817/45c146f0-ffd5-4d01-822c-89d7df101ac1" />
</p>


<p>debounce는 입력 값이 변경될 때마다 즉시 반영되지 않고, 입력이 멈춘 후에 일정 시간이 지난 후에 반영됩니다. 따라서 debounce를 적용한 input 창에는 입력이 발생할 때마다 입력 값이 즉시 반영되지 않고, 입력이 멈춘 후에 일정 시간이 지난 후에 입력 값이 반영됩니다.</p>
<p>예를 들어, debounce를 적용한 input 창에서 사용자가 문자를 입력할 때마다 입력 값이 바로 반영되지 않고, 사용자가 일정 시간동안 입력을 멈춘 후에 입력 값이 반영됩니다. 이렇게 함으로써 사용자가 입력을 마치고 입력값을 사용할 때까지 기다리는 동안 입력값이 계속 변경되는 것을 방지할 수 있습니다.</p>
<p>위 input을 활용할 수 있는 방법은 아래와 같습니다.</p>
<p><strong>| 검색 기능</strong>
사용자가 검색어를 입력할 때마다 검색을 실행하는 것이 아니라, 사용자가 입력을 멈춘 후 일정 시간이 지난 후에 검색을 실행합니다. 이렇게 함으로써 사용자가 입력하는 동안 매번 검색을 실행하지 않고, 입력이 완료된 후에 한 번만 검색을 실행하여 서버 부하를 줄일 수 있습니다.</p>
<p><strong>| 자동 완성 기능</strong>
사용자가 입력하는 동안 매번 자동 완성 기능을 실행하지 않고, 입력이 멈춘 후 일정 시간이 지난 후에 자동 완성을 실행합니다. 이렇게 함으로써 사용자가 입력을 마친 후에 자동 완성이 제공되므로 사용자 경험이 개선됩니다.</p>
<br />

<h3 id="usuage">usuage</h3>
<p><strong>1️⃣ 검색 기능</strong>
사용자가 검색어를 입력할 때마다 실시간으로 검색을 수행하는 경우, 사용자가 입력을 멈추고 일정 시간이 지난 후에 검색을 수행하도록 debounce를 적용할 수 있습니다. 이렇게 함으로써 사용자가 입력하는 동안 계속해서 검색 요청이 발생하는 것을 방지하고, 사용자 경험을 향상시킬 수 있습니다.</p>
<p><strong>2️⃣ 자동 완성 기능</strong>
사용자가 입력하는 동안 자동 완성 기능을 제공할 때 debounce를 사용하여 입력이 멈춘 후 일정 시간이 지난 후에 자동 완성을 수행하도록 할 수 있습니다. 이는 사용자가 입력을 마치기 전에 너무 자주 자동 완성이 발생하는 것을 방지하고, 사용자가 원하는 결과를 더 쉽게 찾을 수 있도록 도와줍니다.</p>
<p><strong>3️⃣ resize 이벤트 처리</strong>
브라우저 창 크기가 변경될 때마다 발생하는 리사이즈 이벤트를 debounce를 사용하여 처리할 수 있습니다. 사용자가 창 크기를 변경하는 동안 이벤트가 계속해서 발생하는 것을 방지하고, 창 크기 조정이 멈춘 후에 이벤트를 처리하여 불필요한 처리를 줄일 수 있습니다.</p>
<p><strong>4️⃣ 텍스트 입력</strong>
사용자가 텍스트를 입력할 때마다 입력값을 실시간으로 처리하는 경우, debounce를 사용하여 입력이 멈춘 후에 처리를 수행할 수 있습니다. 이는 사용자가 입력을 멈추기 전까지 불필요한 처리를 하지 않도록 도와주고, 성능을 향상시킬 수 있습니다.</p>
<p>이렇게 debounce는 입력 또는 이벤트가 발생하는 동안 일정 시간 동안 다음 입력 또는 이벤트를 기다리는 것을 가능하게 하여, 불필요한 이벤트 핸들러의 호출 빈도를 제어하고 성능을 최적화하는 데 유용합니다.</p>
<br />

<h3 id="difference">difference</h3>
<p>Throttle과 다른 점은, 마지막 이벤트에서 일정 시간동안 이벤트가 발생할 경우 또 일정 시간을 기다린다는 점입니다.</p>
<br />
<hr />

<h2 id="🚰-throttle">🚰 Throttle</h2>
<h3 id="사전에-등록된-의미-1">사전에 등록된 의미</h3>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/e534db56-1437-4c48-b53e-2aa5243b9269/image.png" alt=""></p>
<p>이것 외에도 쓰이는 의미를 보면:<br>보통 무언가를 &#39;조이거나 조르는&#39; 의미를 담고 있습니다. throttling은 &#39;압력 조절&#39; 이라는 뜻을 가지고 있습니다. 
자바스크립트 혹은 컴퓨터 사이언스에서도 마찬가지의 의미를 담고있습니다. </p>
<p>요청 혹은 이벤트가 의도한 바보다 너무 과도하게 발생할 때 일정 delay를 주고 delay 동안은 수도꼭지를 조여버리는 것입니다. 그 기간동안 발생한 이벤트, 요청, 함수 등은 무시가 되는 것이고요.</p>
<p>Throttle은 여러 번 발생하는 이벤트를 일정 시간 동안, 한번만 실행 되도록 만드는 개념입니다. 한 번만 실행 때문에 잦은 이벤트 발생을 막아 성능상의 유리함을 가져 올 수 있습니다.</p>
<h3 id="throttle-example">throttle example</h3>
<p><strong>1️⃣ scroll</strong></p>
<p align="center">
  <img src="https://github.com/55555-Jyeon/nextLog/assets/134191817/f7ef51a5-8aff-4a29-9832-784d7f35f257" />
</p>

<p>일반적인 스크롤 이벤트와 throttle를 적용한 스크롤 이벤트의 주요 차이점은 이벤트 핸들러의 호출 빈도와 업데이트 속도에 있습니다.</p>
<p><strong>| 이벤트 핸들러 호출 빈도</strong></p>
<p>일반적인 스크롤 이벤트에서는 스크롤이 발생할 때마다 이벤트 핸들러가 호출됩니다. 이는 사용자가 스크롤을 조작할 때마다 많은 양의 이벤트가 발생할 수 있음을 의미합니다.
throttle를 적용한 스크롤 이벤트에서는 일정 시간 동안 한 번만 이벤트 핸들러가 호출됩니다. 이는 사용자가 스크롤을 조작할 때 이벤트 핸들러가 너무 자주 호출되는 것을 방지하고, 일정 시간 간격으로만 스크롤 위치를 업데이트하여 성능을 향상시킵니다.</p>
<p><strong>| 업데이트 속도</strong></p>
<p>일반적인 스크롤 이벤트에서는 스크롤이 발생할 때마다 즉시 스크롤 위치가 업데이트됩니다. 따라서 스크롤이 빠르게 발생할 경우에는 스크롤 위치의 업데이트가 매우 빠르게 이루어지게 됩니다.
throttle를 적용한 스크롤 이벤트에서는 일정 시간 동안 한 번만 스크롤 위치가 업데이트됩니다. 따라서 사용자가 스크롤을 조작할 때마다 즉시 반응하지 않고, 일정 시간 간격으로만 스크롤 위치가 업데이트됩니다. 이는 부드러운 스크롤 경험을 제공할 수 있으며, 스크롤 이벤트에 대한 불필요한 처리를 줄여 성능을 개선할 수 있습니다.
따라서 throttle를 적용한 스크롤 이벤트는 이벤트 핸들러의 호출 빈도를 제어하고 업데이트 속도를 조절하여 사용자 경험을 개선하고 성능을 최적화하는 데 도움이 됩니다.</p>
<br />

<p><strong>2️⃣ input</strong></p>
<p align="center">
  <img src="https://github.com/55555-Jyeon/nextLog/assets/134191817/cdc30d0d-20f3-4c5a-b41c-160176e4667b" />
</p>

<p>일반 input과 throttle이 적용된 input의 가장 큰 차이는 사용자 입력에 대한 처리 방식입니다. 일반 input은 사용자가 입력할 때마다 즉시 이벤트가 발생하고 해당 이벤트 핸들러가 실행되어 입력값이 업데이트됩니다. 반면에 throttle이 적용된 input은 입력에 대한 이벤트 핸들러 호출을 제어하여 일정 시간 동안 여러 번의 입력에 대한 핸들러 호출을 제한합니다.</p>
<p>여기에는 몇 가지 차이점이 있습니다.</p>
<p><strong>| 이벤트 핸들러 호출 빈도</strong>
throttle이 적용된 input의 경우 일정 시간 간격으로만 이벤트 핸들러가 호출되므로, 사용자가 빠르게 입력을 하더라도 핸들러의 호출 빈도가 제한됩니다. 반면에 일반 input은 사용자의 입력에 따라 즉시 핸들러가 호출되므로, 빠른 입력에 더 많은 이벤트 핸들러 호출이 발생할 수 있습니다.</p>
<p><strong>| 업데이트 속도</strong>
throttle이 적용된 input은 일정 시간 간격으로만 입력값이 업데이트되므로, 사용자가 입력하는 동안 입력값이 즉시 업데이트되지 않을 수 있습니다. 이는 입력값의 업데이트 속도가 느려질 수 있음을 의미합니다. 반면에 일반 input은 사용자의 입력에 따라 즉시 입력값이 업데이트되므로, 더 빠른 업데이트 속도를 제공할 수 있습니다.</p>
<p>따라서 throttle이 적용된 input은 입력값의 <strong>업데이트 속도를 제어</strong>하고, 사용자의 <strong>빠른 입력에 따른 이벤트 핸들러 호출을 제한</strong>하여 성능을 최적화할 수 있습니다. 그러나 <strong>사용자에게는 결과적으로 비슷하게 보일 수 있습니다</strong>.</p>
<br />
<br />

<h3 id="usuage-1">usuage</h3>
<p>throttle은 다양한 상황에서 사용될 수 있지만, 주로 다음과 같은 경우에 많이 활용됩니다.</p>
<p><strong>1️⃣ 사용자 입력 이벤트 처리</strong></p>
<p>사용자가 입력하는 이벤트(예: 텍스트 입력, 마우스 이동 등)를 처리할 때 throttle을 사용하여 이벤트 핸들러의 호출 빈도를 제한할 수 있습니다. 이를 통해 사용자의 빠른 입력에 따른 불필요한 연산을 줄이고 성능을 향상시킬 수 있습니다.</p>
<p><strong>2️⃣ scroll 이벤트 처리</strong>
스크롤 이벤트와 같이 빈번하게 발생하는 이벤트를 throttle을 적용하여 처리할 수 있습니다. 스크롤 이벤트는 화면이 스크롤될 때마다 발생하므로, 너무 자주 발생하는 경우에는 throttle을 적용하여 스크롤 이벤트 핸들러의 호출 빈도를 제어하여 성능을 최적화할 수 있습니다.</p>
<p><strong>3️⃣ resize 이벤트 처리</strong>
창 크기가 변경될 때 발생하는 리사이즈 이벤트도 throttle을 사용하여 처리할 수 있습니다. 창 크기가 변경될 때마다 레이아웃이 재배치되는 경우가 많으므로, throttle을 적용하여 리사이즈 이벤트 핸들러의 호출 빈도를 제어하여 성능을 향상시킬 수 있습니다.</p>
<p><strong>4️⃣ API 요청 제어</strong>
API 요청을 throttle을 사용하여 제어할 수 있습니다. 사용자가 빠르게 연속적인 요청을 보내는 경우에는 throttle을 적용하여 일정 시간 동안 한 번만 요청을 보내도록 제어할 수 있습니다. 이를 통해 서버 부하를 줄이고 성능을 개선할 수 있습니다.</p>
<p>최적화에 가장 유용하게 쓰일 때는 사용자 입력과 같이 빈번하게 발생하는 이벤트 처리나 API 요청 제어 등에서 throttle을 사용하는 경우입니다. throttle을 적용함으로써 이벤트 핸들러의 호출 빈도를 제어하고 불필요한 연산을 줄이므로, 성능을 최적화하고 웹 애플리케이션의 반응성을 향상시킬 수 있습니다.</p>
<br />

<h3 id="difference-1">difference</h3>
<p>Debounce와 다른 점은 이벤트 발생 시간 이후에 일정 시간 동안만을 기다리고, 이벤트를 실행 후 재차 기다린다는 점입니다.</p>
<br />
<hr />

<h3 id="throttle-와-debounce-차이점">Throttle 와 Debounce 차이점</h3>
<blockquote>
<p>Throttle 와 Debounce 의 차이점은 <strong>이벤트를 언제 발생 시킬지의 시점 차이</strong>이다.</p>
</blockquote>
<p>Debounce 는 입력이 끝날때까지 무한적으로 기다리지만 Throttle 는 입력이 시작되면 일정 주기로 계속 실행합니다. Debounce 의 시간을 짧게 가져간다면 Throttle 와 비슷한 효과가 날 수 있지만 그럼에도 시점에서 차이가 날 수 있습니다. 
때문에 작업물의 성격에 따라 사용방법이 달라질 수 있습니다.</p>
<p>대표적인 예로 자동완성 만들 경우, 일정 주기로 자동으로 완성되는 리스트를 보여주는 것에는 사용자 측면에서 Throttle (검색 되는 경험) 가 유리할 수 있지만, 성능상에서는 Debounce (1번만 호출) 가 훨씬 유리할 수 있습니다.</p>
<br />
<hr />

<h2 id="libraries">libraries</h2>
<h3 id="throttle-debounce">throttle-debounce</h3>
<p><a href="https://github.com/niksy/throttle-debounce?source=post_page-----2335a9c426ff--------------------------------">throttle-debounce</a> 라이브러리를 이용하면, 매우 쉽게 throttle 와 debounce 개념을 사용할 수 있습니다.</p>
<p>throttle-debounce는 입력 또는 이벤트 핸들러의 호출 빈도를 제어하기 위한 라이브러리입니다. 이 라이브러리는 throttle과 debounce를 모두 제공하며, 주로 사용자 입력 처리나 이벤트 핸들러의 호출을 최적화하는 데 활용됩니다.</p>
<p>throttle-debounce는 입력이 발생할 때마다 이벤트 핸들러의 호출 빈도를 제한하거나, 입력이 멈춘 후 일정 시간이 지난 후에 이벤트 핸들러를 호출하는 등의 기능을 쉽게 구현할 수 있습니다.</p>
<br />

<h4 id="code-sample">code sample</h4>
<pre><code class="language-javascript">import { throttle } from &#39;throttle-debounce&#39;;

// 버튼 클릭 이벤트 핸들러
const handleClick = throttle(1000, () =&gt; {
  console.log(&#39;Button clicked with throttle&#39;);
});

// 버튼 클릭 이벤트에 핸들러 연결
document.querySelector(&#39;button&#39;).addEventListener(&#39;click&#39;, handleClick);
</code></pre>
<pre><code class="language-javascript">import { debounce } from &#39;throttle-debounce&#39;;

// 입력 이벤트 핸들러
const handleInput = debounce(1000, (event) =&gt; {
  console.log(&#39;Input debounced:&#39;, event.target.value);
});

// 입력 이벤트에 핸들러 연결
document.querySelector(&#39;input&#39;).addEventListener(&#39;input&#39;, handleInput);</code></pre>
<p>위의 예시에서 throttle-debounce 라이브러리의 throttle 함수는 지정된 시간 간격 동안에 한 번만 이벤트를 처리하도록 하고, debounce 함수는 이벤트가 발생한 후 지정된 시간이 지난 후에 이벤트를 처리합니다.</p>
<br />
<br />

<h4 id="라이브러리-특징">라이브러리 특징</h4>
<p><strong>1️⃣ Throttle 기능</strong>
입력이 발생할 때 일정 시간 동안 한 번만 이벤트 핸들러를 호출하도록 설정할 수 있습니다. 이는 사용자가 빠르게 연속적인 입력을 하더라도 이벤트 핸들러의 호출 빈도를 제어하여 성능을 최적화할 수 있습니다.</p>
<p><strong>2️⃣ Debounce 기능</strong>
입력이 발생한 후 일정 시간이 지난 후에 이벤트 핸들러를 호출하도록 설정할 수 있습니다. 이는 사용자 입력이 멈춘 후 일정 시간이 지나기 전에는 이벤트 핸들러를 호출하지 않고, 입력이 멈춘 후에 한 번만 호출하여 성능을 최적화할 수 있습니다.</p>
<p><strong>3️⃣ 유연성</strong>
라이브러리를 사용하여 다양한 입력 또는 이벤트에 throttle과 debounce를 적용할 수 있습니다. 이는 사용자 입력 처리, 스크롤 이벤트 처리, API 요청 제어 등 다양한 상황에서 유용하게 사용될 수 있습니다.</p>
<p>throttle-debounce 라이브러리는 다른 라이브러리와 함께 사용될 수도 있고, 개발자가 직접 구현할 수도 있지만, 일반적으로 라이브러리를 사용하는 것이 더 편리하고 코드를 간결하게 유지할 수 있습니다. 🙂</p>
<br />
<br />

<h3 id="lodash">lodash</h3>
<p><a href="https://github.com/lodash/lodash?source=post_page-----2335a9c426ff--------------------------------">lodash</a>는 자바스크립트 유틸리티 라이브러리로, 많은 개발자들이 프로젝트에서 사용하는 강력한 도구 중 하나입니다. Lodash는 다음과 같은 특징을 가지고 있습니다.</p>
<h4 id="특징">특징</h4>
<p><strong>1️⃣ 유틸리티 함수 제공</strong>
Lodash는 다양한 유틸리티 함수를 제공하여 개발자가 자주 사용하는 다양한 작업을 간편하게 처리할 수 있도록 도와줍니다. 예를 들어, 배열 및 객체 조작, 함수 작업, 문자열 조작, 숫자 처리 등 다양한 유틸리티 함수를 제공합니다.</p>
<p><strong>2️⃣ croll platform 호환성</strong>
Lodash는 크로스 플랫폼 호환성을 가지고 있어 브라우저 및 Node.js와 같은 서버 환경에서 모두 사용할 수 있습니다. 이는 프로젝트의 환경에 관계없이 일관된 코드를 작성할 수 있음을 의미합니다.</p>
<p><strong>3️⃣ 성능 최적화</strong>
Lodash는 내부적으로 성능 최적화가 잘 이루어져 있어, 많은 경우에 빠르고 효율적으로 동작합니다. 이는 대용량 데이터나 복잡한 작업을 처리할 때 유용합니다.</p>
<p><strong>4️⃣ method chaining</strong>
Lodash는 메서드 체이닝을 통해 여러 유틸리티 함수를 연속적으로 호출할 수 있도록 지원합니다. 이를 통해 코드를 간결하게 유지하고 가독성을 높일 수 있습니다.</p>
<p><strong>5️⃣ 모듈화</strong>
Lodash는 각 유틸리티 함수를 개별적으로 제공하므로 필요한 함수만 선택적으로 가져와서 사용할 수 있습니다. 이는 번들 크기를 최소화하고 프로젝트의 성능을 향상시킬 수 있습니다.</p>
<br />
<br />

<h5 id="code-sample-1">code sample</h5>
<pre><code class="language-javascript">
  // 일반적인 input 이벤트 처리
  const [normalInputValue, setNormalInputValue] = useState(&quot;&quot;);
  const handleNormalInputChange = (event) =&gt; {
    setNormalInputValue(event.target.value);
  };

  // Throttle를 적용한 input 이벤트 처리
  const [throttledInputValue, setThrottledInputValue] = useState(&quot;&quot;);
  const handleThrottledInputChange = throttle((event) =&gt; {
    setThrottledInputValue(event.target.value);
  }, 500);

  const [debouncedInputValue, setDebouncedInputValue] = useState(&quot;&quot;);

  // Debounce를 적용한 input 이벤트 처리
  const handleDebouncedInputChange = debounce((event) =&gt; {
    setDebouncedInputValue(event.target.value);
  }, 500);</code></pre>
<br />
<br />

<h3 id="rxjs">RxJS</h3>
<p><a href="https://github.com/ReactiveX/rxjs?source=post_page-----2335a9c426ff--------------------------------">RxJS</a>는 Reactive Extensions for JavaScript의 약어로, JavaScript를 위한 반응형 프로그래밍 라이브러리입니다. RxJS는 비동기적이고 이벤트 기반의 프로그래밍을 다루는데 사용되며, 데이터 스트림과 데이터 시퀀스를 다루는데 주로 사용됩니다. </p>
<p>RxJS는 비동기적인 작업을 다루는데 효과적이며, 복잡한 비동기 코드를 간결하고 읽기 쉽게 작성할 수 있도록 도와줍니다. 또한 RxJS는 프론트엔드 및 백엔드에서 모두 사용될 수 있으며, 다양한 애플리케이션에서 상태 관리, 이벤트 처리, HTTP 요청 등 다양한 용도로 활용됩니다.</p>
<br />
<br />

<h4 id="특징-1">특징</h4>
<p><strong>1️⃣ Observables(옵저버블)</strong>
옵저버블은 비동기적인 데이터 스트림을 나타내는 객체입니다. 이러한 데이터 스트림은 시간에 따라 변할 수 있으며, 옵저버블은 데이터 스트림을 생성하고 이를 관찰할 수 있는 메서드를 제공합니다.</p>
<p><strong>2️⃣ Observers(옵저버)</strong>
옵저버는 옵저버블의 데이터 스트림을 관찰하고, 이벤트를 처리하는 콜백 함수를 가지고 있는 객체입니다. 옵저버는 옵저버블에서 발생하는 이벤트에 대응하여 특정 동작을 수행합니다.</p>
<p><strong>3️⃣ Operators(연산자)</strong>
연산자는 옵저버블의 데이터 스트림을 변형하거나 필터링하는 함수형 프로그래밍 기법을 제공합니다. RxJS에는 다양한 연산자가 제공되며, 이를 사용하여 옵저버블의 데이터를 변형하거나 조작할 수 있습니다.</p>
<p><strong>4️⃣ Subscription(구독)</strong>
구독은 옵저버블과 옵저버 간의 연결을 나타냅니다. 구독은 옵저버블의 데이터 스트림을 구독하고, 옵저버블에서 발생하는 이벤트를 옵저버에게 전달합니다.</p>
<p><strong>5️⃣ Subjects(서브젝트)</strong>
서브젝트는 옵저버블과 옵저버의 역할을 모두 수행할 수 있는 특별한 종류의 객체입니다. 서브젝트는 데이터를 발행하고 구독할 수 있으며, 다른 옵저버블과 마찬가지로 연산자를 적용할 수 있습니다.</p>
<br />
<br />

<h4 id="code-sample-2">code sample</h4>
<pre><code class="language-javascript">import { fromEvent } from &#39;rxjs&#39;;
import { throttleTime } from &#39;rxjs/operators&#39;;

const button = document.querySelector(&#39;button&#39;);

// 버튼 클릭 이벤트를 옵저버블로 변환
const buttonClick$ = fromEvent(button, &#39;click&#39;);

// 버튼 클릭 이벤트를 1초 간격으로 방출하도록 throttle 적용
const throttledButtonClick$ = buttonClick$.pipe(
  throttleTime(1000)
);

// throttle이 적용된 버튼 클릭 이벤트 구독
throttledButtonClick$.subscribe(event =&gt; {
  console.log(&#39;Button clicked with throttle:&#39;, event);
});
</code></pre>
<pre><code class="language-javascript">import { fromEvent } from &#39;rxjs&#39;;
import { debounceTime } from &#39;rxjs/operators&#39;;

const input = document.querySelector(&#39;input&#39;);

// 입력 이벤트를 옵저버블로 변환
const inputEvent$ = fromEvent(input, &#39;input&#39;);

// 입력 이벤트를 1초 간격으로 디바운스 적용
const debouncedInputEvent$ = inputEvent$.pipe(
  debounceTime(1000)
);

// debounce가 적용된 입력 이벤트 구독
debouncedInputEvent$.subscribe(event =&gt; {
  console.log(&#39;Input debounced:&#39;, event.target.value);
});
</code></pre>
<p>위의 예시에서 throttleTime은 일정 시간 동안에 한 번만 이벤트를 방출하도록 하고, debounceTime은 마지막 이벤트가 발생한 후 일정 시간이 지난 후에만 이벤트를 방출하도록 합니다.</p>
<br />
<hr />

<p><em>References.</em></p>
<p><a href="https://pks2974.medium.com/throttle-%EC%99%80-debounce-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-2335a9c426ff">https://pks2974.medium.com/throttle-%EC%99%80-debounce-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-2335a9c426ff</a>
<a href="https://webclub.tistory.com/607">https://webclub.tistory.com/607</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTP Cache]]></title>
            <link>https://velog.io/@55555-jyeon/HTTP-Cache</link>
            <guid>https://velog.io/@55555-jyeon/HTTP-Cache</guid>
            <pubDate>Sat, 30 Mar 2024 15:29:47 GMT</pubDate>
            <description><![CDATA[<h6 id="book-study-codinginside">Book Study, CodingInside</h6>
<h6 id="computer-science-note-chap03-section02">[Computer Science Note] chap03. section02.</h6>
<hr />
<br />

<h6 id="데이터-캐싱에-대해-알아보기-전-알아두면-좋은-기본적인-운영체제와-컴퓨터에-관한-간단한-정보를-상단에-추가해두겠습니다-🙂">데이터 캐싱에 대해 알아보기 전 알아두면 좋은 기본적인 운영체제와 컴퓨터에 관한 간단한 정보를 상단에 추가해두겠습니다. 🙂</h6>
<br />

<h2 id="basic-os">basic OS</h2>
<h3 id="운영체제의-역할">운영체제의 역할</h3>
<p>1️⃣ <strong>CPU 스케줄링과 프로세스 관리</strong>
CPU의 소유권을 어떤 프로세스에 할당할지, 프로세스의 생성과 삭제, 자원 할당 및 반환 관리</p>
<p>2️⃣ <strong>메모리 관리</strong>
한정된 메모리를 어떤 프로세스에 얼만큼 할당해야 하는지 관리</p>
<p>3️⃣ <strong>디스크 파일 관리</strong>
디스크 파일을 어떠한 방법으로 보관할지 관리</p>
<p>4️⃣ <strong>I/O 디바이스 관리</strong>
I/O 디바이스(마우스, 키보드)와 컴퓨터 간에 데이터를 주고받는 것을 관리</p>
<br />

<h3 id="운영체제의-구조">운영체제의 구조</h3>
<p align="center">
<img width="40%" src="https://velog.velcdn.com/images/dbfla0628/post/4930dd80-ab70-4c88-bb28-b191e612a792/image.png" />
</p>

<p><strong>| GUI</strong>
사용자가 전자장치와 상호 작용할 수 있도록 하는 사용자 인터페이스의 한 형태</p>
<pre><code>example → 마우스로 클릭하는 단순 동작으로 컴퓨터와 상호 작용할 수 있도록 해줌</code></pre><p><strong>| CUI</strong>
그래픽이 아닌 명령어로 처리하는 인터페이스
인터페이스 중 CUI만 있는 리눅스 서버도 존재</p>
<p><strong>| 드라이버</strong>
하드웨어를 제어하기 위한 소프트웨어</p>
<p><strong>| 시스템콜</strong>
운영체제가 커널에 접근하기 위한 인터페이스
유저 프로그램이 운영체제의 서비스를 받기 위해 커널 함수를 호출할 때 사용</p>
<p align="center">
<img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/a2b16a6f-552b-4a1e-b459-aeb6a36cf306" />
</p>

<p>① 유저 프로그램이 I/O 요청으로 트랩(trap)을 발동 
② 올바른 I/O 요청인지 확인
③ 유저 모드가 시스템콜을 통해 커널 모드로 변환되어 실행</p>
<br />
<hr />
<br />

<h2 id="basic-computer">basic Computer</h2>
<h3 id="컴퓨터의-요소">컴퓨터의 요소</h3>
<p align="center">
<img width="80%" src="https://github.com/inside-coding/cs-note/assets/134191817/8569804d-a7e0-4623-8696-5162702a40ed" />
</p>


<h3 id="⚙️-cpu">⚙️ CPU</h3>
<h6 id="central-processing-unit">Central Processing Unit</h6>
<p align="center">
<img width="40%" src="https://github.com/inside-coding/cs-note/assets/134191817/0a04cd20-fe0a-43b4-945e-8eb3b0e15127" />
</p>

<p>산술논리연산장치, 제어장치, 레지스터로 구성되어 있는 컴퓨터 장치
interupt에 의해 단순히 메모리에 존재하는 명령어를 해석해 실행</p>
<br />

<h4 id="cu">CU</h4>
<h6 id="control-unit">Control Unit</h6>
<p>제어장치
프로세스 조작을 지시하는 CPU의 부품 중 하나</p>
<p>1️⃣ 입출력장치 간 통신을 제어
2️⃣ 명령어들을 읽고 해석
3️⃣ 데이터 처리를 위한 순서를 결정</p>
<br />

<h4 id="레지스터">레지스터</h4>
<p>CPU 안에 있는 매우 빠른 임시기억장치
CPU와 직접 연결돼 있어 연산 속도가 메모리보다 수십 ~ 수백 배 빠름
CPU는 자체적으로 데이터를 저장할 방법이 없어 레지스터를 거쳐 데이터를 전달</p>
<br />

<h4 id="alu">ALU</h4>
<h6 id="arithmetic-logic-unit">Arithmetic Logic Unit</h6>
<p>산술논리연산장치
산술 연산과 배타적 논리 연산을 계산하는 디지털 회로</p>
<p align="center">
<img width="60%" src="https://github.com/inside-coding/cs-note/assets/134191817/25fa3341-63e1-4019-9d27-a5821b750731" />
</p>

<br />
<br />

<h3 id="⚙️-dma-controller">⚙️ DMA Controller</h3>
<p>I/O 디바이스가 메모리에 직접 접근할 수 있도록 하는 하드웨어 장치</p>
<p>CPU에만 너무 낳은 interupt 요청이 들어오기 때문에 CPU의 부하를 막아주기 위해 CPU의 일을 부담하는 <strong>보조 일꾼</strong></p>
<p>하나의 작업을 CPU와 DMA 컨트롤러가 동시에 하는 것을 방지</p>
<br />


<h3 id="⚙️-memory">⚙️ Memory</h3>
<p>CPU는 계산을, 메모리는 기억을 담당</p>
<p>전자회로에서 데이터나 상태, 명령어 등을 기록하는 장치
보통 <strong>RAM</strong>(Random Access Memory)을 일컬어 메모리라도고 함</p>
<pre><code>컴퓨터를 공장에 비유하자면...
CPU = 일꾼, memory = 작업장, memory의 크기 = 작업장의 크기

작업장이 클수록 창고에 물건을 많이 가져다놓고 많은 일을 할 수 있듯이
메모리가 크면 클수록 많은 일을 동시에 할 수 있음
</code></pre><br />


<h3 id="⚙️-timer">⚙️ Timer</h3>
<p>몇 초  안에는 작업이 끝나야 한다는 limit을 정하고 특정 프로그램에 시간 제한을 다는 역할
시간이 많이 걸리는 프로그램이 작동할 때 제한을 걸기 위해 존재</p>
<br />


<h3 id="⚙️-device-controller">⚙️ Device Controller</h3>
<p>컴퓨터와 연결돼 있는 IO 디바이스들의 작은 CPU를 말함
옆에 붙어 있는 로컬 버퍼는 각 디바이스에서 데이터를 임시로 저장하기 위한 작은 메모리</p>
<br />
<hr />
<br />

<h1 id="💰-caching">💰 Caching</h1>
<p>이전 웹의 성능 최적화에 대해 다룬 포스팅에서도 언급한 바 있지만 웹 사이트의 로딩 시간을 줄이는 것은 비즈니스에도 큰 영향을 미칩니다.
웹을 최적화하는 방법에는 여러 가지가 있는데 그 중에서 특히 중요한 개념들 중 하나에 <strong>캐싱</strong>이 포함됩니다.</p>
<h3 id="📝-memory">📝 MEMORY</h3>
<h4 id="메모리-계층">메모리 계층</h4>
<p align="center">
<img width="80%" src="https://github.com/inside-coding/cs-note/assets/134191817/0245d0e0-60c9-46db-bc59-d45ad1240fee" />
</p>

<br />


<h4 id="cache">cache</h4>
<p>데이터를 미리 복사해 놓는 임시 저장소이자 빠른 장치와 느린 장치에서 속도 차이에 따른 <strong>병목 현상을 줄이기 위한 메모리</strong>를 캐시라고 합니다.</p>
<p>그리고 캐싱은 어떤 데이터를 한 번 받아오게 되면 그 데이터를 처음에 불러온 저장소보다 가까운 곳에 임시로 저장해 필요 시 처음보다 빠르게 가져와 사용할 수 있는 프로세스를 의미합니다.</p>
<p align="center">
<img width="60%" src="https://github.com/inside-coding/cs-note/assets/134191817/66a0994c-6957-422e-92a6-0919270ebd3b" />
</p>


<p>메모리 계층 구조에서 cache(캐시)는 디스크나 메인 메모리보다 더 빠르게 데이터를 불러와서 사용해야 할 때 쓰입니다. 때문에 빠른 만큼 메모리당 비용이 비싼 편에 속합니다.</p>
<p>그래서 개발자 입장에서는 재사용의 가능성이 높은 데이터만 선별해 캐싱하여 성능과 비용, 두 가지의 균형을 잘 잡는 것이 중요합니다.</p>
<h4 id="http-cache-종류">HTTP Cache 종류</h4>
<p align="center">
<img width="80%" src="https://github.com/inside-coding/cs-note/assets/134191817/cbe7b549-a488-4886-9e47-7891265d33cd" />
</p>

<br />

<h2 id="web-cache">Web Cache</h2>
<p align="center">
<img width="80%" src="https://github.com/inside-coding/cs-note/assets/134191817/8d8dc576-eb6d-417f-a883-280dc8e0f9a7" />
</p>

<p>클라이언트는 서버로부터 HTTP 요청을 통해 필요한 데이터를 불러옵니다.
기본적으로 웹사이트가 실행될 때마다 client는 해당 웹사이트를 그리기 위해 필요한 데이터를 전부 다시 불러와야 합니다.</p>
<p>하지만 분명 재사용의 여지가 있는 데이터들이 있을텐데 굳이 모든 데이터를 다시 불러와야 할 필요가 있을까요?</p>
<p>이전에 한 번 불러왔던 데이터들 중 바뀔 가능성이 없는 데이터라면 캐싱을 고려해봐야 합니다. 페이지의 로고 이미지, sidebar, navbar 같이 여러 페이지에 동일하게 적용되는 부분들이 고려 대상에 해당될 것입니다.</p>
<h3 id="browser-cache">Browser Cache</h3>
<h6 id="browser-cache--http-cache--private-cache">Browser Cache === HTTP cache === Private Cache</h6>
<p>위와 같은 상황에 적용하는 캐시를 브라우저 캐시(Browser Cache)라고 합니다.
브라우저 캐시는 client app에 의해 내부 디스크에 이뤄지는 캐시로 HTTP cache라 불리기도 합니다.</p>
<p>브라우저 캐시는 단일 사용자를 대상으로 하는 사설 캐시(Private Cache)이므로 해당 사용자의 정보만을 저장합니다.</p>
<br />

<p>** browser cache 종류**</p>
<p>소프트웨어에서의 캐시는 대표적으로 쿠키, 로컬 스토리지, 세션 스토리지가 있으며 <strong><code>origin</code>에 종속</strong>됩니다. 보통 사용자의 커스텀 정보, 인증 모듈 관련 사항들을 웹 브라우저에 저장해 추후 서버 요청 시 아이덴티티 혹은 중복 요청 방지를 위해 쓰입니다.</p>
<br />

<h3 id="cookie">cookie</h3>
<p>만료기한이 있는 <code>key-value</code> 저장소입니다. </p>
<p>4KB까지 데이터를 저장할 수 있고 만료기한을 정할 수 있습니다.
만료기한은 클라이언트와 서버 둘 다 정할 수 있지만 보통 서버에서 정합니다.</p>
<p>쿠키를 설정할 때 <code>document.cookie</code>로 쿠키를 볼 수 없게 httponly 옵션을 거는 것이 중요합니다.</p>
<p>same site 옵션을 strict로 설정하지 않았을 경우 다른 도메인에서 요청했을 때 자동으로 전송됩니다.</p>
<p><strong>| usuage</strong></p>
<p>1️⃣ 세션 관리
사용자가 로그인한 상태를 유지하고, 사용자가 해당 세션 동안 접속하는 동안 사용자의 상태를 추적하는 데 사용</p>
<p>2️⃣ 개인화
사용자의 환경설정이나 선호도를 저장하여 웹 사이트를 개인화할 때 사용</p>
<p>3️⃣ 트래킹
사용자의 행동을 추적하고 분석하기 위해 사용</p>
<pre><code class="language-javascript">// 설정
document.cookie = &quot;key=value; expires=expiration_date; path=/&quot;;

// 가져오기
let cookieValue = document.cookie;

// 삭제
document.cookie = &quot;key=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;&quot;;</code></pre>
<p>쿠키는 보안 상 문제가 될 수 있으므로 개인 식별 정보와 같은 민감한 정보를 저장하지 않는 것이 좋습니다. </p>
<p>일부 브라우저는 클라이언트 당 쿠키의 최대 개수나 쿠키의 총 크기를 제한할 수 있기 때문에 브라우저의 쿠키 제한이 있는지 확인해야 합니다.</p>
<br />


<h3 id="local-storage">local storage</h3>
<p>만료기한이 없는 <code>key-value</code> 저장소입니다. </p>
<p>5MB까지 데이터를 저장할 수 있으며 웹 브라우저를 닫아도 데이터가 유지됩니다.
클라이언트에서만 수정이 가능하고 HTML5를 지원하지 않는 웹 브라우저에서는 사용할 수 없습니다.</p>
<p><strong>| usuage</strong></p>
<p>1️⃣ 사용자가 로그인 정보, 사용자 설정, 사용자 환경 등을 오랫동안 유지해야 할 때 
2️⃣ 데이터가 사용자 세션을 넘어서 영구적으로 보존되어야 할 때 </p>
<pre><code class="language-javascript">// 데이터 설정
localStorage.setItem(&#39;username&#39;, &#39;john_doe&#39;);

// 데이터 가져오기
var username = localStorage.getItem(&#39;username&#39;);
console.log(&#39;Username:&#39;, username);

// 데이터 삭제
localStorage.removeItem(&#39;username&#39;);</code></pre>
<br />

<h3 id="session-storage">session storage</h3>
<p>만료기한이 없는 <code>key-value</code> 저장소입니다. </p>
<p>5MB까지 데이터를 저장할 수 있습니다.
탭 단위로 세션 스토리지를 생성하므로 탭을 닫을 때 해당 데이터가 사라집니다.</p>
<p>클라이언트에서만 수정이 가능하고 HTML5를 지원하지 않는 웹 브라우저에서는 사용할 수 없습니다.</p>
<p><strong>| usuage</strong></p>
<p>1️⃣ 사용자가 페이지나 브라우저 창을 닫을 때까지만 데이터를 보존해야 할 때 
2️⃣ 일시적인 데이터 저장에 적합</p>
<pre><code class="language-javascript">// 데이터 설정
sessionStorage.setItem(&#39;language&#39;, &#39;english&#39;);

// 데이터 가져오기
var language = sessionStorage.getItem(&#39;language&#39;);
console.log(&#39;Language:&#39;, language);

// 데이터 삭제
sessionStorage.removeItem(&#39;language&#39;);</code></pre>
<br />
<br />

<h4 id="캐시-유효성-검증-및-조건부-요청">캐시 유효성 검증 및 조건부 요청</h4>
<p>브라우저에서 캐싱을 처리하는 속성 중 대표적인 것으로는 <code>ETag</code>와 <code>Cache-Control</code>이 있습니다.</p>
<p><strong>| ETag</strong></p>
<p>HTTP 헤더의 ETag는 특정 버전의 <strong>리소스를 식별</strong>합니다.</p>
<p>웹 서버가 내용을 확인하고 변경 사항이 없을 경우 ETag의 값도 변하지 않아 웹 서버로 전체 요청을 보내지 않게 됩니다. 반대로 해당 요청의 리소스가 변경되었다면 새로운 ETag가 생성됩니다.</p>
<p><code>If-Match</code> 프로퍼티를 사용해 캐싱된 리소스가 불러온 리소스와 일치하는지 확인할 수도 있습니다. 확인한 두 리소스의 결과 값에 따라 상태코드를 보내줍니다.</p>
<h6 id="etag가-불일치할-경우-412-상태코드precondition-failed-전제조건-실패">ETag가 불일치할 경우 412 상태코드(Precondition Failed, 전제조건 실패)</h6>
<p>반대로 변경되지 않은 리소스의 캐시를 해야할 경우, 대표적으로 ETag가 오래되어 사용할 수 없는 경우, HTTP 헤더에 <code>If-None-Match</code> 프로퍼티에 ETag 값을 넣어줄 수 있습니다. 서버에서는 클라이언트의 ETag를 현재 버전 리소스의 ETag와 비교 후 결과에 해당하는 상태코드를 보내줍니다.</p>
<h6 id="일치-시-현재-etag가-유효하다는-의미이기-때문에-304not-modified">일치 시 현재 ETag가 유효하다는 의미이기 때문에 304(Not-Modified)</h6>
<br />

<p><strong>| Cache-Control</strong></p>
<blockquote>
<p>가장 빠른 코드는 실행하지 않는 코드다.</p>
</blockquote>
<p>요청을 보낼지 말지 여부를 판단할 때 HTTP 헤더의 <code>cache-control</code> 요소를 통해 캐싱을 제어할 수 있습니다.</p>
<pre><code class="language-HTTP">HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Cache-Control: max-age=604800  ✅

&lt;!doctype html&gt;
…</code></pre>
<p>** <code>no-cache</code>**
이름만 보면 cache를 하지 않는다는 의미일 것 같지만 그렇지 않습니다.
no-cache 속성은 캐시를 먼저 사용하기 전에 서버에 해당 캐시를 사용해도 되는지 검증을 요청하는 속성입니다.</p>
<p>no-cache 속성이 없는 경우 캐시가 있다면 그 캐시를 바로 사용합니다.
하지만 no-cache 속성이 있는 경우 캐시가 있다 하더라도 서버에게 그 캐시를 써도 되는지 허락을 맡고 쓰게 됩니다. 따라서 요청에 대한 시간이 소요될 수 있습니다.</p>
<br />

<p>** <code>no-store</code>**
no-store 속성을 사용하게 되면 반환된 응답에 대해 브라우저가 캐싱을 하지 않게 됩니다. 이 속성이 cache를 하지 않는다는 의미에 더 가깝다고 볼 수 있습니다.
캐싱을 하지 않기 때문에 매번 요청을 보낼 때마다 전체 데이터를 받아오게 됩니다.
개인정보와 같은 사적인 데이터의 경우 이 속성을 사용하게 됩니다.</p>
<br />

<p>** private &amp; public**
private과 public은 cache-control의 키워드입니다.
public은 캐싱이 가능하다는 의미입니다. <strong>private</strong>은 응답을 캐싱하는 과정에서 <strong>엔드 유저만 캐싱</strong>이 가능하고, 캐싱하는 과정에서 거치게 되는 매개체에서는 캐싱할 수 없는 속성입니다.</p>
<p align="center">
<img width="60%" src="https://github.com/inside-coding/cs-note/assets/134191817/6e5eea42-05b4-49d6-8579-18974ad3c34a" />
</p>


<br />
<br />
<hr />

<h3 id="proxy-cache">Proxy Cache</h3>
<h6 id="proxy-cache--shared-cache">Proxy Cache === Shared Cache</h6>
<p>웹 캐시에는 브라우저 캐시 외 프록시 캐시도 있습니다.
프록시 캐시는 공유 캐시(Shared Cache)로 한 명 이상의 사용자에 의해 재사용되는 응답을 저장합니다. 대표적으로 ISP에서 많이 조회되는 리소스를 재사용하기 위해 웹 프록시를 설치합니다.</p>
<p align="center">
<img width="80%" src="https://github.com/inside-coding/cs-note/assets/134191817/631def5a-d202-4c2f-bc30-452a63502318" />
</p>

<p>구글을 예로 들어보면 이해하기가 한결 수월해집니다.
구글 사이트에 접속할 때마다 미국에 있는 구글 서버에서 웹 사이트의 데이터를 가져온다면 시간이 꽤 걸릴 것입니다. 이때 프록시 캐시를 사용해 구글 웹사이트에 관한 리소스를 한국 서버에 둘 수 있게 하는 겁니다.</p>
<br />
<br />
<hr />

<h2 id="network-cache">Network Cache</h2>
<h3 id="cdn">CDN</h3>
<h6 id="content-delivery-network">Content Delivery Network</h6>
<p>CDN은 분산 노드로 구성된 네트워크입니다.
CDN은 성능 향상을 위해 클라이언트의 요청이 같은 서버로 가는 것을 막습니다.
즉, 각 지역의 엔드 유저에 따라 요청을 origin 서버가 아닌 다른 서버로 가도록 분산시키는 역할을 하며 이 과정에서 캐싱이 사용됩니다.</p>
<p>최초 한 번은 origin 서버에서 데이터를 받아와야 하므로 느릴 수 있지만, 그 이후부터는 CDN을 통해 해당 콘텐츠를 전보다 빠르게 받아올 수 있습니다.
만약 엔드 유저의 요청이 CDN 노드에서 가져올 수 없는 경우라면 origin 서버로 요청을 전송합니다.</p>
<p align="center">
<img width="80%" src="https://github.com/inside-coding/cs-note/assets/134191817/1dfc2436-805d-483b-950f-95a319ca2a61" />
</p>

<p>CDN을 서비스하는 대표적인 회사로 Cloudflare가 있습니다. </p>
<br />
<br />
<hr />




<h2 id="db의-캐싱-계층">DB의 캐싱 계층</h2>
<p>데이터베이스 시스템을 구축할 때도 메인 데이터베이스 위에 레디스(redis) 데이터 베이스 계층을 캐싱 계층으로 두어 성능을 향상시키기도 합니다.</p>
<p align="center">
<img width="70%" src="https://github.com/inside-coding/cs-note/assets/134191817/99617473-045e-42ec-a1a2-fbd3137c7f1f" />
</p>


<br />
<br />
<hr />

<p><em>References.</em></p>
<p>면접을 위한 CS 전공지식노트 책
<a href="https://hudi.blog/http-cache/">https://hudi.blog/http-cache/</a>
<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Caching">https://developer.mozilla.org/ko/docs/Web/HTTP/Caching</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React, 성능 최적화 (feat. DevTools)]]></title>
            <link>https://velog.io/@55555-jyeon/React-optimise</link>
            <guid>https://velog.io/@55555-jyeon/React-optimise</guid>
            <pubDate>Wed, 20 Mar 2024 02:59:25 GMT</pubDate>
            <description><![CDATA[<h2 id="웹의-성능-최적화">웹의 성능 최적화</h2>
<h4 id="왜-웹의-성능을-최적화해야-하는-걸까">왜 웹의 성능을 최적화해야 하는 걸까?</h4>
<p>웹 성능 최적화(개선)은 웹페이지를 효율적으로 동작하게 하는 작업입니다. 
성능을 최적화함으로써 사용자에게 좋은 사용자 경험을 제공할 수 있기 때문에 이는 결국 비즈니스적인 성공과 직결되는 문제이기도 합니다. </p>
<br />

<h4 id="좋은-사용자-경험">좋은 사용자 경험?</h4>
<p>예를 들어, 사용자가 웹 사이트에 접속했을 때 하얀 화면(빈 화면)을 노출시키거나 웹 사이트 로딩 및 렌더링에 지연이 발생하면 사용자는 자연스레 이탈을 하게 됩니다. 그리고 동시에 해당 웹 서비스는 방문 사용자에 대한 비즈니스 기회를 잃어버리게 됩니다.</p>
<br />

<h4 id="1️⃣-로딩-속도">1️⃣ 로딩 속도</h4>
<h6 id="2017년-google의-모바일-부문-글로벌-제품-리드인-daniel-an이-말한-think-with-google의-기사에서-발췌한-내용">2017년 Google의 모바일 부문 글로벌 제품 리드인 Daniel An이 말한 Think with Google의 기사에서 발췌한 내용</h6>
<p>웹 페이지 로딩 시간과 사용자 이탈률은 밀접한 관계를 갖고 있습니다.</p>
<p>아래 자료에 따르면 페이지 로딩 시간이 1초에서 3초로 증가하면 페이지 이탈률이 32%로 증가한다고 하고, 10초가 되면 123%나 된다고 합니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/f238e18c-a764-47ab-826b-b1b9ad7f720a/image.png" alt=""></p>
<p>즉, 웹 사이트가 사용자에게 빨리 로딩되면 <strong>좋은 사용자 경험</strong>(UX, User Experince)을 제공할 수 있고 초반 이탈률도 감소시킬 수 있습니다.</p>
<br />

<h4 id="2️⃣-load-순서">2️⃣ Load 순서</h4>
<p>UX를 위해 사용자의 뷰(view), 즉 사용자 시선에 따라 콘텐츠가 어떻게 로드되어 보여지는지는 것도 신경을 써주는 것이 좋습니다.</p>
<p>일반적으로 사용자의 시선은 <strong>위에서 아래</strong>로 이동합니다.</p>
<p>좌우의 경우에는 나라마다 차이가 존재합니다. </p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/6390729f-9e1c-4708-ad0f-72eef026503e/image.png" alt=""></p>
<p>한국과 같은 LTR(Left to Right) 국가들을 기준으로 개발을 할 때에는 콘텐츠의 로드 순서가 위부터, 왼쪽부터 되도록 신경을 쓴다면 자연스러운 사용자 경험을 제공할 수 있습니다.</p>
<p>콘텐츠의 로딩 순서가 웹 성능 점수에 영향을 미치지 않지만, 사용성에 영향을 끼치므로 웹 성능 작업을 하면서 콘텐츠 로딩 되는 순서를 되짚어 보고 개선하는 것이 좋을 것 같습니다.</p>
<p>예를 들어, 웹 사이트 표출 시, 사이트 윗부분인 Heder 부분이 늦게 뜨고 아래서부터 페이지가 로딩 된다면 어색한 사용자 경험을 제공하게 됩니다. 🙃</p>
<br />

<h3 id="개선-포인트">개선 포인트</h3>
<p>그렇다면 프론트엔드 단에서 할 수 있는 최적화에는 어떤 것들이 있을까요?
크게 로딩 성능과 렌더링 성능으로 나눌 수 있을 것 같습니다.</p>
<h4 id="1️⃣-로딩-성능loading-performance">1️⃣ 로딩 성능(Loading Performance)</h4>
<blockquote>
<p>얼마나 빠르게 리소스를 로드하는가</p>
</blockquote>
<p>웹 사이트의 로딩 성능은 서버에서 웹 페이지에 필요한 HTML, CSS, Javascript, 미디어 소스(Image, Video) 등의 리소스를 다운로드할 때의 성능을 말합니다.</p>
<h4 id="2️⃣-렌더링-성능rendering-performance">2️⃣ 렌더링 성능(Rendering Performance)</h4>
<blockquote>
<p>얼마나 빠르게 화면을 렌더링하고 있는가</p>
</blockquote>
<p>웹 사이트의 렌더링 성능은 페이지 화면에 주요 리소스가 페이지에 그려질 때의 성능을 말합니다.</p>
<br />
다양한 성능 최적화 방법이 있지만, 그 중에서도 크롬 개발자도구를 활용하여 웹 사이트의 로딩 성능과 렌더링 성능과 관련된 지표들을 살펴보고 이를 통해 어떻게 성능을 개선할 수 있는지 살펴보겠습니다.🙂



<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/2910ae80-2fed-4e28-a0e3-cb9294082051/image.png" alt=""></p>
<p>위 이미지는 Google이 만든 필수적인 웹 성능 지표인 Core Web Vital입니다.
LCP, CLS는 개발자 도구의 Lighthouse에서 정량적인 수치로 확인할 수 있습니다. </p>
<br />
<hr />

<h3 id="🩺-analysis">🩺 Analysis</h3>
<p>분석은 개발자 도구의 탭을 활용해 할 수 있습니다.</p>
<p>자주 사용되는 탭들은 총 네 가지, lighthouse(별도 설치 필요), profiler, performances, network 입니다.</p>
<h4 id="💡-lighthouse">💡 Lighthouse</h4>
<p>현재 만들고 있는 개인 포트폴리오 웹 페이지로 테스트해보겠습니다.
개발자 도구에서 lighthouse 탭에 들어가 페이지 로드 분석하기 버튼을 누르면
분석이 시작됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/97082846-2ca5-434e-80cc-aa044f5d914d/image.png" alt=""></p>
<p>로드되는 순서대로 검사를 진행해주며 프로젝트의 크기에 따라 로딩 시간이 다소 걸릴 수도 있습니다. </p>
<p>분석이 완료되면  최상단에서 현재 웹 페이지를 <code>Performance</code>, <code>Accessibility</code>, <code>Best Practices</code>, <code>SEO</code>, <code>PWA</code> 총 다섯 가지 기준에 따라 분석 점수를 확인할 수 있습니다. 스크롤을 좀 더 내리면 세세한 항목도 확인이 가능합니다. </p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/8eeced85-3da8-4131-b200-bdb7b2b939fc/image.png" alt=""></p>
<p>여기에 분석된 내용을 토대로 최적화를 진행해보려고 했는데 점수가 상당히 높게 나왔네요.😅</p>
<h6 id="performances">Performances</h6>
<p>Performance의 점수는 현재 페이지의 성능을 측정한 점수이며, 이는 Metrics 지표의 세부 항목을 기준으로 측정됩니다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/a2e0282d-f281-489a-98ab-6b65d75fd71a/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/1bb301a5-38d5-4840-ba8a-79b3acb97341/image.png" alt=""></th>
</tr>
</thead>
</table>
<pre><code>1. First Contentful Paint (첫 번째 콘텐츠 렌더링)
2. Time to Interactive (상호 작용 가능 시간)
3. Speed Index (속도 지수)
4. Total Blocking Time (총 차단 시간)
5. Largest Contentful Paint (가장 큰 콘텐츠 렌더링)
6. Commulative Layout Shift (누적 레이아웃 변경)</code></pre><p><code>Oppertunities</code>와 <code>Dignostics</code>는 현재 웹페이지의 문제점과 성능 최적화를 위한 가이드를 제시해주는 부분입니다.</p>
<p><code>Opportunities</code>는 로딩 성능과 관련된 내용으로 어떻게 리소스를 더 빠르게 로딩할 수 있는지의 관점에서 개선 포인트를, <code>Dignostics</code>는 렌더링 성능과 관련된 내용으로 그 개선점을 진단해줍니다.</p>
<p align="center">
<img width="80%" src="https://velog.velcdn.com/images/55555-jyeon/post/da946cfd-1491-4226-80a2-abfb68c4245c/image.png" />
</p>


<p>tree map 버튼을 누르면 파일별 차지하는 크기도 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/3a2e0ce8-d895-428a-af97-d594fa1405e1/image.png" alt=""></p>
<br />

<h4 id="🎥-profiler">🎥 Profiler</h4>
<p>Profiler는 성능 데이터를 기록하고 측정을 해줍니다. </p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/5754b3c1-061a-4708-994c-3c29e63c18f3/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/70d1ffa7-1ef4-4cf4-a580-fe45ebb792a3/image.gif" alt=""></th>
</tr>
</thead>
</table>
<p>그리고 프로파일링은 개발 환경에서만 확인이 가능합니다. 즉,  배포가 된 사이트에서는 확인이 불가합니다. 우측 gif와 같이 프로파일링을 시작할 수 있습니다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/406fb65d-f7ba-4bf5-8b7a-d78bad2361ea/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/93fa5d4b-6b2a-4522-9b11-f81dd0c26c4d/image.png" alt=""></th>
</tr>
</thead>
</table>
<h6 id="좌-flamegraph--우-ranked">좌 Flamegraph | 우 Ranked</h6>
<p>Flamegraph 차트를 보면 App 컴포넌트는 렌더링하는데 어느 정도의 시간이 걸렸는지 알 수 있습니다. 
Ranked 차트에서는 파일의 어떤 컴포넌트의 렌더링 시간이 오래 걸린 순서를 확인할 수 있습니다.</p>
<br />

<h4 id="👩🏻🎨-performance">👩🏻‍🎨 Performance</h4>
<p>Performance 패널에서는 Timeline을 기준으로 페이지가 로드되면서 실행되는 작업들에 관한 정보를 그래프와 화면들의 스냅샷으로 확인할 수 있습니다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/4e6a486f-ca2e-4b66-adf6-f5bd1d491fd4/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/bfe8eb84-114e-468d-8ea3-9eb508aacb3c/image.png" alt=""></th>
</tr>
</thead>
</table>
<h6 id="개인적으로-record-버튼을-눌렀을-경우-끝날-기미가-보이지-않아-reload로-했습니다🥹">개인적으로 record 버튼을 눌렀을 경우 끝날 기미가 보이지 않아 reload로 했습니다.🥹</h6>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/344dc2a8-5ec8-4211-8cf5-e1ef88d4618c/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/700cab93-b8e9-4ca0-bdd9-aea3a8641347/image.png" alt=""></th>
</tr>
</thead>
</table>
<h5 id="frames">Frames</h5>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/3e19d2dd-26dc-4e08-8015-9ab0362affe5/image.png" alt=""></p>
<p>Screenshots 옵션을 활성화 한 경우 확인 가능하며, Timeline에 따른 렌더링 과정을 스냅샷을 통해 확인할 수 있습니다.</p>
<h5 id="timings">Timings</h5>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/daadea29-10bc-4061-b5a2-8f3b20e40dde/image.png" alt=""></p>
<p>DCL, FP, FCP, LCP, L 등의 순서를 확인할 수 있습니다.</p>
<pre><code>DCL (DOMContentLoaded event)
HTML과 CSS parsing이 완료되는 시점
렌더 트리를 구성할 준비가 된 (DOM 및 CSSOM 구성이 끝난) 상황을 의미

FP (First Paint)
화면에 무언가 처음으로 그려지기 시작하는 순간

FCP (First Contentful Paint)
화면에 텍스트나 이미지가 출력되기 시작하는 순간

FMP (First Meaningful Paint) ⭐️
사용자에게 의미있는 콘텐츠가 그려지기 시작하는 첫 순간
콘텐츠 노출에 필요한 리소스(css, JavaScript file) 로드가 시작되고 스타일이 적용된 시점

L (onload event)
HTML 상에 필요한 모든 리소스가 로드된 시점</code></pre><p>이 중 FMP의 시점은 사용자에게 필요한 컨텐츠가 노출되는 시점, 즉 웹 사이트에 대한 사용자의 첫 인상이 결정되는 순간이기 때문에 주의 깊게 살펴볼 필요가 있습니다. </p>
<p>FMP 시점을 앞당기는 것을 사용자 기준의 성능 최적화의 지표로 삼을 수도 있습니다. 이 과정에서 어떤 컨텐츠가 가장 먼저 노출되어야 하는가에 대한 논의가 필요하며 개발 과정에 반영되어야 합니다.</p>
<h5 id="main">Main</h5>
<p>Timeline에 따른 이벤트와 그에 따른 부작업을 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/f2681eb6-ecb2-4f17-9607-5fe46ec1401b/image.png" alt=""></p>
<p>각각의 막대는 이벤트를 나타내며, 폭이 넓을 수록 오래 걸린 이벤트입니다. 각 이벤트 아래쪽의 이벤트들은 상단의 이벤트로부터 파생된 이벤트입니다.</p>
<p>마우스 휠로 확대와 축소가 가능하므로 보고 싶은 부분을 확대해 면밀히 살펴볼 수 있습니다.</p>
<br />

<h4 id="💻-network">💻 Network</h4>
<p>Network는 Performance 패널과 함께 레코딩되며, 웹 페이지가 로딩되는 동안 요청된 리소스 정보들을 확인할 수 있습니다. </p>
<p>이 때 리소스 목록은 시간순으로 정렬되며, 아래와 같이 각 리소스의 서버 요청 대기 시간을 확인할 수 있습니다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/96e5b3bb-f048-4f33-a421-94965073d4e5/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/368be293-6830-4f50-8cdd-21e6e0b3f964/image.png" alt=""></th>
</tr>
</thead>
</table>
<pre><code>Queuing
대기열에 쌓아둔 시간

Stalled
요청을 보내기 전의 대기 시간 (서버와 커넥션을 맺기까지의 시간)

Waiting (TTFB)
초기 응답(Time To First Byte)을 받기까지 소비한 시간(서버 왕복 시간)

Content Download
리소스 다운에 소요된 시간</code></pre><br />
<hr />

<h3 id="💊-optimization">💊 Optimization</h3>
<p>저는 lighthouse에서 진단받은 내용을 토대로 몇 가지 고쳐보도록 하겠습니다.</p>
<p>아까 lighthouse에서 performance 점수가 90/100 이었는데 그 중 세 가지 항목에서 빨간색 세모 표시(🔺)를 받았습니다.</p>
<br />

<h4 id="handle-resources">handle resources</h4>
<p>1️⃣ <a href="https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources/?utm_source=lighthouse&amp;utm_medium=devtools">eliminate render-blocking resources</a> | 렌더링 차단 리소스 제거하기</p>
<p>렌더링 차단 리소스란, 페이지의 렌더링을 차단하는 리소스를 의미합니다. 이러한 리소스를 최적화하면 페이지의 로딩 속도를 개선할 수 있습니다.  </p>
<p>렌더링 차단 리소스를 제거하기 위해서는 우선 렌더링 차단 URL을 파악해야 합니다. Lighthouse나 Page Speed Index와 같은 사이트 퍼포먼스 테스트 진단 결과를 확인하면 FCP(First Contentful Paint)를 차단하는 모든 URL이 나열됩니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/82933e95-6f8e-4787-afc5-f788f0c490e0/image.png" alt=""></p>
<p>렌더링 차단 URL을 파악한 후, 다음과 같은 방법으로 렌더링 차단 리소스를 제거할 수 있습니다. </p>
<p><strong>중요한 리소스를 인라인으로 전달하기</strong>
중요한 CSS나 JS 파일을 HTML 문서에 직접 포함시켜 인라인으로 전달할 수 있습니다. 이를 통해 브라우저가 별도의 리소스를 요청하지 않아도 되므로 로딩 속도를 개선할 수 있습니다. 하지만 이 방법은 HTML 문서의 크기를 증가시키므로, 불필요한 리소스는 인라인으로 전달하지 않도록 주의해야 합니다.</p>
<p><strong>중요하지 않은 리소스를 지연하기</strong>
중요하지 않은 CSS나 JS 파일은 페이지 로딩이 완료된 후 지연시켜 로딩 속도를 개선할 수 있습니다. 이를 위해 defer나 async 속성을 사용하거나, JavaScript를 사용하여 리소스를 동적으로 로딩하도록 구현할 수 있습니다.</p>
<p><strong>사용되지 않는 리소스 제거하기</strong>
사용되지 않는 CSS나 JS 파일은 제거하여 로딩 속도를 개선합니다. 이를 위해 불필요한 코드를 제거하거나, 사용되지 않는 라이브러리를 제거할 수 있습니다.</p>
<pre><code>❗️주의사항❗️

1️⃣ 인라인으로 전달하는 리소스가 너무 많으면 안 돼요!
HTML 문서의 크기가 커져 로딩 속도가 느려질 수 있습니다.

2️⃣ 중요하지 않은 리소스를 지연시키면 안 돼요!
페이지의 로딩이 완료되기 전까지 해당 리소스를 사용할 수 없으므로, 페이지의 기능이 동작하지 않거나 깨질 수 있습니다.

3️⃣ 사용되지 않는 리소스를 제거할 때 백업을 남겨주세요!
코드의 유지보수나 확장성을 고려하여, 필요할 때 다시 추가할 수 있도록 백업을 남겨두는 것이 좋습니다.</code></pre><br />

<p>현재 제 페이지에서 렌더링을 차단시키는 리소스들은 <code>app/layout.css</code>와 <code>app/page.css</code>, 총 두 개가 있습니다.</p>
<p><code>app/layout.css</code>에는 nextJS로 프로젝트 폴더와 함께 자동 생성된 내용으로 다크모드 등 사용하지 않는 코드가 많이 적혀 있습니다. </p>
<p>현재 제 포트폴리오 디자인과 상관 없는 코드들을 전부 삭제하니 transfer size가 조금 줄어들었습니다. (performance도 5점 올랐습니다. 😃)</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/6f2b603c-b945-48e0-9f24-2fa5ce493163/image.png" alt=""></p>
<br />


<h4 id="resize-image">resize image</h4>
<p>다음 2, 3번 항목은 메인 페이지에 들어가는 이미지의 사이즈와 관련된 항목입니다. 가져오는 이미지의 용량이 현재 보여지는 화면의 용량보다 크기 때문에 과도하게 많은 용량을 가져온다는 의미로 이미지의 사이즈를 줄이라고 권고한다고 보면 됩니다. 🙂</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/4b6c5463-e993-426f-b9e2-5541f745def6/image.png" alt=""></p>
<p>2️⃣ <a href="https://web.dev/articles/lcp-lazy-loading?utm_source=lighthouse&amp;utm_medium=devtools">Largest Contentful Paint image was lazily loaded</a></p>
<blockquote>
<p>이미지 요소를 지연 로드하는 경우 브라우저에 이 이미지의 우선 순위를 해제하도록 명시적으로 지시합니다.</p>
</blockquote>
<p>지연 로드된 이미지는 훨씬 나중에 지연되지 않은(non-lazy) 이미지를 다운로드하기 위해 대기열에 추가됩니다. 이로 인해 이미지가 나중에 렌더링되고 콘텐츠가 포함된 최대 페인트 측정 항목이 지연됩니다.</p>
<p>이는 지연 로드된 이미지가 아닌 다른 모든 이미지가 지연 로드될 이미지보다 먼저 다운로드되도록 예약된다는 의미입니다. 따라서 지연 로드 이미지가 LCP 요소인 경우 LCP가 지연될 수 있습니다.</p>
<p><code>Lazysizes.js</code>와 같은 자바스크립트 기반 지연 로딩 라이브러리를 사용하면 상황이 더욱 악화됩니다. 이제 브라우저는 LCP 이미지 요소를 지연시킬 뿐만 아니라 자바스크립트가 다운로드되어 실행될 때까지 기다려야 합니다.</p>
<p>LCP 이미지에서 <code>loading=&quot;lazy&quot;</code> 속성을 제거하거나 LCP 이미지에 대한 지연 로딩을 우회하도록 플러그인의 필터를 업데이트하여 lighthouse의 경고를 없앨 수 있습니다.</p>
<p>*<em>기본 지연 로딩을 사용하는 경우 *</em></p>
<ul>
<li>LCP 요소에서 loading=&quot;lazy&quot;를 제거</li>
<li>loading=&quot;eager&quot;로 변경</li>
</ul>
<p>*<em>JavaScript 기반 지연 로딩을 사용하는 경우 *</em></p>
<ul>
<li>더 빠른 기본 지연 로딩으로 전환</li>
<li>지연 로딩에서 LCP 이미지를 생략하는 것을 고려</li>
</ul>
<p><strong>이미지 구성 요소를 사용하는 경우</strong> (ex. next/image)</p>
<ul>
<li>strategy=&quot;eager&quot;를 설정</li>
<li>loading=&quot;eager&quot; 를 설정</li>
</ul>
<br />

<p>저는 NextJS에서 Image 태그를 사용했기 때문에 <code>loading=&quot;eager&quot;</code> 설정을 추가했습니다. <code>strategy</code>의 경우 타입과 관련된 에러가 발생해 loading로 설정했습니다.</p>
<pre><code class="language-typescript">// page.tsx의 return 문

&lt;AnimatePresence mode=&quot;wait&quot;&gt;
      &lt;main className={style.main}&gt;
        &lt;div className={style.ImageContainer}&gt;
          &lt;motion.div whileHover={{ scale: 1.1 }}&gt;
            &lt;Image
              onClick={() =&gt; router.push(&quot;/Amy&quot;)}
              src={profile}
              className={style.profile}
              loading=&quot;eager&quot; ✅
              alt=&quot;profile image&quot;
            /&gt;
          &lt;/motion.div&gt;
        &lt;/div&gt;
        &lt;motion.div exit={{ opacity: 0 }} className= {style.textbox}&gt;
          &lt;p&gt;JUYEON OH&lt;/p&gt;
          &lt;p&gt;FE DEVELOPER&lt;/p&gt;
        &lt;/motion.div&gt;
      &lt;/main&gt;
&lt;/AnimatePresence&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/4f44f32c-c452-48df-9a66-8939a02b6b8e/image.png" alt=""></p>
<p>performance 점수가 오르진 않았지만 경고가 사라진 것을 확인할 수 있었습니다.</p>
<br />

<p>3️⃣ <a href="https://developer.chrome.com/docs/lighthouse/performance/uses-responsive-images">properly size images</a></p>
<p align="center">
<img width="70%" src="https://velog.velcdn.com/images/55555-jyeon/post/1a05910f-9f91-4600-8087-53fe99b21b80/image.gif" />
</p>

<h6 id="이미지의-크기와-렌더링된-이미지의-크기는-요소-편집기에서-확인할-수-있습니다">이미지의 크기와 렌더링된 이미지의 크기는 요소 편집기에서 확인할 수 있습니다.</h6>
<p>이미지의 용량은 아래와 같은 방법으로 줄일 수 있습니다.</p>
<p><strong>| 이미지 최적화</strong></p>
<p>이미지 최적화 도구를 사용하여 이미지를 압축하고 최적화합니다. 이를 통해 이미지의 파일 크기를 줄이고 페이지 로드 속도를 개선할 수 있습니다. 예를 들어, ImageMagick, TinyPNG, JPEG Optimizer 등의 도구를 사용할 수 있습니다.</p>
<p><strong>| image cdn</strong></p>
<p>이미지를 사용자에게 보내기 전에 jpg의 포맷을 바꾸거나, 용량을 줄여서 사용자에게 전송할 수 있는 방법입니다. 
예를 들어, 1200짜리를 120으로 줄여서 사용자에게 전달하고자 할 때 <code>http://cdn.image.com?src=img.src&amp;width=200&amp;height=100</code> 와 같은 방법으로 표시하는 겁니다.</p>
<p>단, 이미지를 가져오는 매체 (unsplash, aws s3)에서 image cdn을 자체 제공해주면 굳이 사제 이미지 cdn을 사용 안해도 됩니다.</p>
<p><strong>| Responsively size images</strong></p>
<p>반응형 웹 디자인을 사용하여 이미지 크기를 디바이스 및 화면 크기에 맞게 조절합니다. Next.js에서는 <code>&lt;Image&gt;</code> 컴포넌트를 사용하여 이미지를 반응형으로 처리할 수 있습니다. 이미지의 너비와 높이를 잘 조절하여 필요 이상으로 큰 이미지를 피할 수 있습니다.</p>
<p>나아가 Next.js는 자동으로 다양한 이미지 포맷을 지원하며, srcset 속성을 생성하여 브라우저가 지원하는 최적의 이미지를 선택하도록 합니다.</p>
<p>srcset 속성은 아래와 같이 사용할 수 있습니다.</p>
<pre><code class="language-javascript">import Image from &#39;next/image&#39;;

const MyImage = () =&gt; {
  return (
    &lt;Image
      src=&quot;/images/example.jpg&quot;
      alt=&quot;Example Image&quot;
      width={500}
      height={300}
      srcSet={{
        &#39;/images/example-400.jpg&#39;: 400,
        &#39;/images/example-800.jpg&#39;: 800,
        &#39;/images/example-1200.jpg&#39;: 1200,
      }}
    /&gt;
  );
};

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

<p>저는 이미지가 크기 별로 존재하는 것도 아니고 외부 사이트에서 가져오는 이미지도 아니기 때문에 Next.js에서는 <code>&lt;Image&gt;</code> 컴포넌트의 속성을 활용해 이미지 최적화를 진행했습니다.</p>
<p>현재 제 페이지에 렌더링된 이미지의 크기는 위의 1/2 이지만 화질이 덩달아 낮아지는 것을 확인해 2배 크기로 불러오도록 설정했습니다.</p>
<pre><code class="language-javascript">&lt;Image src={profile} loading=&quot;eager&quot; width={400} height={482} /&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/407b3399-5c10-447a-9ad8-e430607bf8d1/image.png" alt=""></p>
<p>점수에는 변화가 없었지만 마찬가지로 경고문이 사라졌습니다.</p>
<br />

<h6 id="번외">번외</h6>
<h4 id="콘텐츠가-포함된-최대-paint-image-미리-로드">콘텐츠가 포함된 최대 paint image 미리 로드</h4>
<p>이미지를 최대한 빠르게 로드하기 위해선 먼저 이미지 크기를 최적화하고, 모바일에서도 빠르게 로드되도록 이미지를 압축해야 합니다.
이미지 크기의 최적화는 이미지 해상도를 줄이는 것 뿐만 아니라 이미지의 포맷도 고려해야 합니다. </p>
<p>또한, 이미지를 미리 로드하는 것도 페이지의 로드 시간을 단축할 수 있는 한 방법입니다. 이미지를 미리 로드하게 되면 브라우저가 이미지를 로드하는 시간동안 다른 요소들의 로드와 렌더링을 진행할 수 있게 되기 때문입니다.</p>
<p><strong>| rel=&quot;preload&quot;</strong></p>
<p><code>&lt;Link rel=&quot;preload&quot; /&gt;</code> 
Link 태그의 속성을 사용하여 이미지를 미리 로드할 수 있습니다.
이 방법은 브라우저가 페이지를 로드하기 전에 이미지를 미리 로드하도록 하는 설정입니다. </p>
<p><strong>| IntersectionObserver</strong></p>
<p><code>IntersectionObserver</code>를 사용해 이미지가 브라우저의 뷰포트 안에 들어왔을 때 로드할 수 있도록 합니다. 이를 활용할 경우 불필요한 이미지 로드를 방지할 수 있습니다.</p>
<p><strong>| lazy-loading</strong></p>
<p><code>&lt;img loading=&quot;lazy&quot; /&gt;</code> 
이미지 태그의 속성을 사용해 위와 동일한 효과를 볼 수 있습니다. 하지만 lazy-loading의 경우 모든 브라우저에서 지원되는 기능이 아니기 때문에 둘 중에서는 Intersection Observer의 사용을 권장합니다.</p>
<br />


<h4 id="page-prevented-backforward-cache-restoration">Page prevented back/forward cache restoration</h4>
<p>위 경고(페이지가 뒤로/앞으로 캐시 복원을 방해했습니다)는 사용자가 이전 또는 다음 페이지로 이동할 때 브라우저 캐시에서 페이지를 복원하는 것을 방해하는 페이지의 정책이 있음을 나타냅니다.</p>
<p>해당 경고는 아래와 같은 부분을 검토함으로써 해결할 수 있습니다 : </p>
<pre><code>1️⃣ Cache-Control 헤더 검토

    - 페이지의 HTTP 응답 헤더에서 Cache-Control 헤더를 확인
    - &quot;no-store&quot; 또는 &quot;no-cache&quot;와 같은 값이 있는지 확인
    - 브라우저 캐시를 비활성화/새로 고침 → 항상 새로운 콘텐츠를 요청하도록 강제
    - 필요에 따라 적절한 캐싱 헤더를 설정

2️⃣ Service Worker 확인

    - 페이지에서 사용 중인 Service Worker가 캐시 동작을 제어하는지 확인
    - 페이지의 캐싱 및 오프라인 지원 담당 가능 → 캐시 관련 동작 확인

3️⃣ History API 사용 검토

    - 페이지가 History API를 사용하여 페이지 이동을 관리하는 경우, 페이지 전환에 대한 캐싱 동작을 방해 가능성 존재 
    - story API를 사용하여 페이지 전환을 구현하는 경우, 캐싱 동작을 적절히 처리하도록 수정

4️⃣ 브라우저 지원 정책 검토

    - 페이지 전환에 대한 캐싱 동작을 제어하는 정책 존재
    - 브라우저의 지원 문서 → 페이지 전환에 대한 캐싱 동작을 이해하고, 필요한 조치 취하기

5️⃣ 레거시 코드 확인

    - 페이지에 오래된 레거시 코드가 있는 경우, 페이지 캐시 동작을 방해 가능성 존재
    - 레거시 코드를 수정/업데이트 → 최신 캐시 관련 규약을 준수</code></pre><p>저는 총 네 개의 항목에서 걸려 이런 경고를 받았습니다.
하지만 네 가지 모두 localhost:3000 일 때 받는 경고이기 때문에 확인만 하고 넘어갈 예정입니다. (배포가 된 사이트에서는 해당 경고가 없습니다😃)</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/a3a7bb24-eefc-42c7-8d79-d7967f8196fa/image.png" alt=""></p>
<p><code>WebSocket 사용</code>
WebSocket을 사용하는 페이지가 뒤로/앞으로 캐시에 들어갈 수 없다는 것을 의미
WebSocket은 기본적으로 브라우저의 기존 캐시 기능과 호환되지 않을 수 있습니다. 이 경우, WebSocket을 사용하는 대신에 다른 통신 방식을 고려해보거나, WebSocket이 필요한지 다시 검토할 필요가 있습니다.</p>
<p><code>cache-control:no-store</code>
페이지의 주 리소스가 cache-control:no-store로 설정되어 있다는 것을 의미
이 설정은 브라우저가 해당 리소스를 캐시하지 않도록 합니다. 따라서 이 설정을 변경하여 브라우저가 페이지를 캐시할 수 있도록 해야 합니다.</p>
<p><code>JsNetworkRequestReceivedCacheControlNoStoreResource</code>
JavaScript 네트워크 요청에서 cache-control:no-store 리소스를 수신했다는 것을 나타냅니다. 이 경우, 해당 리소스의 cache-control 값을 수정하여 브라우저가 해당 리소스를 캐시할 수 있도록 변경해야 합니다.</p>
<p><code>WebSocketSticky</code>
이 항목은 WebSocketSticky가 존재한다는 것을 의미합니다. WebSocketSticky는 브라우저 캐시와 관련된 문제를 발생시킬 수 있는 추가적인 설정이므로, 필요한 경우 해당 설정을 검토하고 변경해야 합니다.</p>
<br />

<h4 id="reduce-unused-js">reduce unused JS</h4>
<p>이 경고는 웹 페이지의 성능을 저하시킬 수 있는 중요한 문제 중 하나로 웹 페이지에서 불필요한 JavaScript 코드가 발견되었을 때 나타납니다. 불필요한 JavaScript 코드는 페이지의 다운로드 시간을 증가시키고 실행 시간을 늘릴 수 있어, 사용자 경험을 저하시키고 페이지의 로드 속도를 느리게 할 수 있습니다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/24711259-50c5-4cc2-8321-b241cfda8f2e/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/55555-jyeon/post/3523814b-1d6b-44c7-96d4-c4528f678098/image.png" alt=""></th>
</tr>
</thead>
</table>
<p><strong>Detect unused JavaScript</strong></p>
<p>사용되지 않는 JS 코드는 <code>Coverage</code> 탭에서 리스트를 확인할 수 있습니다.
그리고 각 코드/파일마다 아래 세 가지 방법 중 적합한 것으로 처리하면 경고를 해결할 수 있습니다.</p>
<p>1️⃣ Code Splitting
2️⃣ Unused Code Elimination
3️⃣ Unused Imported Code</p>
<p><code>Coverage</code> 탭에서 항목 클릭 시 어떤 코드가 문제인지 정확히 짚어줍니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/ae29ffa4-b7f6-4d31-bcc6-aae5a3be2eab/image.png" alt=""></p>
<p>혹시 몰라 사용하게 될 수 있어 남겨두었던 미사용 파일(애니메이션 관련)들을 전부 제거했습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/e0df5527-b1f0-4cda-b0ae-01408c4a6f84/image.gif" alt=""></p>
<br />
<hr />

<p>최종적으로 현재 제작 중인 포트폴리오 사이트의 성능은 아래와 같습니다. 🥳</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/73cdc58d-2f34-4b2f-bc46-d384405c285d/image.gif" alt=""></p>
<p>100점이어도 진단 시 경고 받은 것들이 있어서 아래 부분들은
남은 포트폴리오 진행하면서 함께 해결 예정입니다.🙂</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/1a98d7d0-53fa-432d-a10b-6889b79ef8ac/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/910f29b1-8cb7-4954-8197-6b5817134344/image.png" alt=""></p>
<br />
<hr />

<p><em>References</em></p>
<p><a href="https://devocean.sk.com/blog/techBoardDetail.do?ID=164863&amp;boardType=techBlog">웹 프론트엔드 개발자가 웹 성능 최적화를 해야 하는 이유</a></p>
<p><a href="https://medium.com/wantedjobs/react-profiler%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-%EC%84%B1%EB%8A%A5-%EC%B8%A1%EC%A0%95%ED%95%98%EA%B8%B0-5981dfb3d934">React Profiler를 사용하여 성능 측정하기</a>
<a href="https://yohanpro.com/posts/react/%EB%A6%AC%EB%A0%8C%EB%8D%94%EB%A7%81%EA%B3%BC-%EC%84%B1%EB%8A%A5">React 리렌더링과 성능</a>
<a href="https://wikidocs.net/197632#_2">React 성능 최적화</a>
<a href="https://chanmi-lee.github.io/articles/2021-01/website-spped-and-performance-optimization#google_vignette">웹 성능 분석 및 최적화 기법 (with Chrome Developer Tools)</a></p>
<p><a href="https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources/?utm_source=lighthouse&amp;utm_medium=devtools">렌더링을 방해하는 리소스 제거하기</a>
<a href="https://web.dev/articles/lcp-lazy-loading?utm_source=lighthouse&amp;utm_medium=devtools">Largest Contentful Paint image was lazily loaded</a>
<a href="https://www.corewebvitals.io/pagespeed/fix-largest-contentful-paint-image-was-lazily-loaded-lighthouse">Largest Contentful Paint image was lazily loaded solution</a>
<a href="https://developer.chrome.com/docs/lighthouse/performance/uses-responsive-images">properly size images</a>
<a href="https://dongwookit.tistory.com/253#2.%20%EC%B0%A8%EC%84%B8%EB%8C%80%20%ED%98%95%EC%8B%9D%EC%9D%84%20%EC%82%AC%EC%9A%A9%ED%95%B4%20%EC%9D%B4%EB%AF%B8%EC%A7%80%20%EC%A0%9C%EA%B3%B5%ED%95%98%EA%B8%B0-1">콘텐츠가 포함된 최대 paint image 미리 로드</a>
<a href="https://developer.chrome.com/docs/lighthouse/performance/unused-javascript/?utm_source=lighthouse&amp;utm_medium=devtools">reduce unused JS</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[the important stuff:                  
Software Architecture]]></title>
            <link>https://velog.io/@55555-jyeon/Software-Architecture</link>
            <guid>https://velog.io/@55555-jyeon/Software-Architecture</guid>
            <pubDate>Sat, 16 Mar 2024 12:43:18 GMT</pubDate>
            <description><![CDATA[<h5 id="architecture-pattern">Architecture Pattern?</h5>
<p>아키텍처 패턴은 소프트웨어 시스템을 위한 검증된 구조적 도해(a pictorial, an illustrated)입니다.</p>
<p>아키텍처 패턴(표준 아키텍처)는 패턴보다 덜 정제된 컨셉으로서 사용됩니다.
여러 패턴은 동일한 아키텍처 스타일에 속할 수 있습니다.</p>
<h5 id="pattern">Pattern?</h5>
<p>패턴은 서브 시스템과 그들의 역할을 사전 정의해 놓은 하나의 Set입니다.
Client-server pattern의 시스템 구조에 의하면 두 개의 서브 시스템이 식별되는데 클라이언트와 서버가 이에 해당합니다.
클라이언트 시스템의 주요 역할은 사용자에게 UI를 보여주는 역할일 수 있으며, 서버의 역할은 여러 질의를 프로세싱하고, 결과를 클라이언트에 제공함에 있을 것이다.</p>
<p>패턴은 시스템들 사이의 관계를 정리하기 위한 규칙과 지침을 설명합니다.
클라이언트와 서버 사이의 관계는 클라이언트가 질문을 하고 이를 서버가 응답한다는 것입니다.
패턴은 한 사람에 의해 구성되지 않고, 많은 개발자들의 경험의 산물로 이러한 명세화는 다른 사람에게 그 경험을 배울 수 있게 도와줍니다.
이는 소프트웨어 개발에서 기존의 잘 검증된 솔루션을 선택하고, 좋은 디자인 사례를 전파할 수 있게 해줍니다.</p>
<br />
<hr />

<h2 id="-what-is-architecture"><strong>|</strong> What is Architecture?</h2>
<p>아키텍처는 본래 건설, 건축 분야에서 가져온 단어로 소프트웨어 분야에서 사용되는 의미와 차이가 있습니다.
그럼 소프트웨어 분야에서 사용되는 &quot;architecture(아키텍처)&quot;는 어떤 의미로 해석할 수 있을까요?</p>
<p>먼저 아키텍처의 사전적 정의는 다음과 같습니다. (from [Wikipedia] (<a href="https://en.wikipedia.org/wiki/Software_architecture#:~:text=Software%20architecture%20is%20the%20set,of%20both%20elements%20and%20relations">https://en.wikipedia.org/wiki/Software_architecture#:~:text=Software%20architecture%20is%20the%20set,of%20both%20elements%20and%20relations</a>.))</p>
<blockquote>
<p>Software architecture is t<strong>he set of structures needed to reason about a software system and the discipline of creating such structures and systems.</strong> Each structure comprises software elements, relations among them, and properties of both elements and relations.</p>
</blockquote>
<blockquote>
<p>아키텍처는 소프트웨어 시스템의 구성, 구조적 엘리먼트와 시스템을 구성할 인터페이스의 선택, 그러한 엘리먼트들간 협업에 지정된 것으로서 작동과 함께, 그러한 엘리먼트를 점진적으로 더 큰 하위 시스템으로의 구성, 이러한 조직을 이끄는 아키텍처 스타일, 이러한 엘리먼트와 인터페이스, 협업, 구성에 대한 중요한 결정 세트이다.</p>
</blockquote>
<h4 id="ieee에서는">IEEE에서는</h4>
<p>아키텍처를 컴포넌트로 구체화된 시스템의 기본적인 조직이며, 환경에 대한 관계이며, 디자인과 진화를 이끄는 원리라고 정의하고 있습니다. 시스템은 특정 기능이나 기능 세트를 달성하도록 조직된 컴포넌트의 컬렉션으로 이 환경에서 한 개 이상의 미션을 수행하기 위해 존재한다고 설명합니다. </p>
<p>Martin Fowler(마틴 파울러)와 Ralph Johnson(랄프 존슨)은 아키텍처를 아래와 같은 결론을 내립니다.</p>
<h3 id="architecture-is">architecture is...</h3>
<ol>
<li>shared understanding (지식을 공유하는 것)
 전문 개발자들은 시스템 디자인에 대한 지식을 공유한다.</li>
</ol>
<ol start="2">
<li>hard to change (바꾸기 어려운 것)
 아키텍처 디자인은 우선적으로 진행되어야 하며, 올바른 결정은 더 빨리 내려지길 원한다.
 그리고 한 번 내린 결정은 변경하기 어렵다.</li>
</ol>
<h3 id="-the-important-stuff-whatever-it-is">... the important stuff whatever it is.</h3>
<p>두 사람이 내린 아키텍처에 대한 정의은 &quot;아키텍처가 무엇이든 간에 어쨌든 중요한 것&quot;이란 거였습니다.</p>
<p>그럼 아키텍처는 왜 중요한 것일까요? 
이 질문에 대한 답을 내리려면 경제 개념을 도입해와야 합니다.</p>
<p>&quot;<strong>quality</strong>(품질)<strong>과 cost</strong>(비용)&quot;</p>
<p>품질이란 내가 비용을 지불할 수 있는 어떤 것이라는 생각에 근거한 개념으로 우리는 뭔가를 구매할 때마다 품질과 비용의 상관관계를 분석합니다. 하지만 소프트웨어에서의 품질은 의미가 조금 다르게 적용됩니다. 가장 큰 차이점은 품질의 평가자가 외부 사람들(이용자, users, clients)이라는 것입니다. </p>
<p>그럼 이용자들은 어떻게 품질 평가를 할 수 있을까요? 
하지만 그들은 눈으로 볼 수 없기 때문에 내부 소프트웨어가 좋은 아키텍처를 갖고 있는지 혹은 좋은 모듈 디자인을 갖고 있는지에 대한 여부를 알 수 없습니다. </p>
<p>따라서 소프트웨어에서의 품질은 이용자들에게 외부적으로 보여지는 품질과 내부적인 품질로 나눌 수 있습니다.</p>
<p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/cd31f220-e332-4d18-8943-269a0e1cad9a/image.png" />
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/d536e86c-520a-4e19-92a5-35d982fbc65c/image.png" />
</p>
소프트웨어에서의 내부 품질은 어떻게 평가할 수 있을까요?

<p>예를 들어서 완전히 같은 기능을 하는 소프트웨어 두 개 중 높은 품질과 낮은 품질의 제품의 가격 차이가 $100라고 가정해봅시다. 
여기서 $100가 더 비싼 소프트웨어를 구매해야 하는 이유는 무엇일까요?
같은 기능을 하는 제품을 더 비싸게 구매해야할 필요가 있을까요?</p>
<p>소프트웨어의 내부 품질은 장기적인 관점에서 중요합니다.</p>
<p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/5e876a8a-165f-4e23-9613-b2ac666b8a83/image.png" />
</p>


<p>저품질의 소프트웨어는 미래에 새로운 기능을 추가할 때마다 어려움을 겪게 될 것입니다. 기능을 추가할 때마다 이미 존재하는 소스코드들을 변경하는데 시간이 다소 소요되기 때문입니다.</p>
<p>향후 기능을 추가하는 등의 버전 관리를 좀 더 용이하고 빠르게 하기 위해서 개발자는 좋은 아키텍처를 가져가기 위해 관심을 기울이고 소스코드를 리팩터링하면서 더 나은 방향으로 나아가려고 노력해야 합니다. 
컴포넌트화가 잘 된 소스코드는 개발 속도를 감소시켜 결과적으로 개발 비용을 절약시켜줄 수 있습니다. </p>
<p>현재 비슷한 기능을 하고 있는 사이트나 에플리케이션이 너무나 많습니다. 이러한 소프트웨어 시장 속에서 빠르게 기능을 개선하고 개발하기 위해서는 반드시 좋은 아키텍처를 기반으로 해야할 것입니다. </p>
<p>소프트웨어 아키텍처란 유연성, 확장성, 실행가능성, 재사용성, 보안성과 같은 소프트웨어의 특성들을 기술적, 사업적 기대에 부응하는 구조화된 해법으로 바꾸는 과정입니다. 좋은 아키텍처는 확장성 있고, 모듈화를 통한 유지보수가 용이하며 실행 가능성이 있어야 합니다.</p>
<br />
<hr />
<br />

<h2 id="-architecture-pattern"><strong>|</strong> architecture pattern</h2>
<p>그렇다면 내가 설계한 아키텍처가 좋은 아키텍처인지는 어떻게 알 수 있을까요?</p>
<p>이때 판단 기준이 되어 주는 것이 바로 아키텍처 패턴입니다.
아키텍처 패턴은 주어진 상황에서의 소프트웨어 아키텍쳐에서 일반적으로 발생하는 문제점들에 대한 일반화되고 재사용 가능한 솔루션으로 소프트웨어 디자인 패턴과 유사하지만 더 큰 범주에 속한다고 볼 수 있습니다.</p>
<p>아래 10가지가 대표적인 소프트웨어 아키텍처 패턴입니다 :</p>
<h3 id="01-계층화-패턴-layered-pattern">01. 계층화 패턴 (Layered pattern)</h3>
<p>n-티어 아키텍쳐 패턴이라고도 불리는 계층형 아키텍처는 목적이 같은 코드들을 계층으로 그룹화하는 패턴입니다. </p>
<p align="center">
<img width="20%" src="https://velog.velcdn.com/images/55555-jyeon/post/59c611ca-d307-4263-bc78-0c294295d97e/image.png" />
</p>

<p>각 계층은 바로 아래 계층에서 제공하는 기능과 서비스에만 의존하는 형태로 계층적인 접근은 시스템의 점증적 개발 지원이 가능하다는 장점이 있습니다. 계층이 수정돼도, 인접한 계층만 영향을 받게 되고 인터페이스가 변경되지 않으면, 확장 기능을 가지는 새로운 계층으로 기존의 계층 대체 가능합니다.
이렇게 관심사에 따른 분리를 하게 되면 연쇄적인 참조 관계가 되므로 각 계층은 의존성을 갖게 됩니다. 한 가지를 바꾸려면 다른 부분들도 건들이게 되므로 테스트를 하는데 어려움이 있고 유지보수하기 불편한 패턴입니다.</p>
<p>계층화 패턴이 갖는 의존성 문제를 보완하기 위해 나온 것이 <strong>클린 아키텍처</strong> 입니다.
아키텍처가 무엇을 보호하고 무엇에 집중해야 하는가에 대한 고민 끝에 나온 아키텍처로 이는 도메인과 업무 정책을 보호하고 집중한다는 특징을 갖고 있습니다. </p>
<p align="center">
<img width="50%" src="https://velog.velcdn.com/images/55555-jyeon/post/6aaa37a9-e987-4bee-9733-335ad8c9a060/image.png" />
</p>

<p>기본적인 원리는 종속성 규칙(Dependency Rule)을 지키는 것입니다. 각 코드의 종속성은 외부에서 내부로 안쪽으로만 가리킬 수 있고, 고수준 정책(High level policy)이 저수준 정책(Low level policy)의 변경에 영향을 받지 않도록 하는 것입니다. 안쪽에 위치할수록 고수준 정책이며, 바깥쪽에 위치할 수록 저수준 정책을 의미합니다. 단방향의 의존성은 서로에게 주는 영향을 감소시킴으로써 유지보수의 용이성이 향상되어 덕분에 낮은 비용으로 새로운 기능을 추가할 수 있게 됩니다.</p>
<p>클린 아키텍처를 좀 더 구체화한 버전인 <strong>헥사고날 아키텍처</strong>도 있습니다. 헥사고날 아키텍처는 포트와 어댑터아키텍처라고도 불리며 외부의 변화로부터 저수준의 정책을 보호하기 위한 구조로 외부를 인터페이스가 보호하는 형태를 띄고 있습니다.</p>
<p align="center">
<img width="50%" src="https://velog.velcdn.com/images/55555-jyeon/post/8edfda32-1491-451b-9777-fe8259b8a250/image.png" />
</p>


<p>도메인 코드가 바깥쪽 코드에 의존하지 않게 함으로써 외부로 부터의 도메인 로직의 결합을 제거하기 때문에 변경할 사항이 적을수록 유지보수성이 높은 코드가 됩니다.</p>
<br />

<h3 id="02-클라이언트-서버-패턴-client-server-pattern">02. 클라이언트-서버 패턴 (Client-server pattern)</h3>
<pre><code>    클라이언트 : 서버에 서비스를 요청하는 객체
    서버 : 클라이언트에 서비스를 제공하는 객체</code></pre><p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/a49ec8e0-1b64-48d6-b0e2-1bd768c2b859/image.png" />
</p>

<p>C-S 패턴은 다수의 클라이언트와 하나의 서버로 구성됩니다. 서버는 클라이언트에 서비스를 제공하며 데이터를 관리하는 역할을 합니다.</p>
<h6 id="사용-예시">사용 예시</h6>
<pre><code>- 이메일, 문서 공유 등 온라인 애플리케이션
- 일반적인 웹 프로그램 등</code></pre><br />

<h3 id="03-마스터-슬레이브-패턴-master-slave-pattern">03. 마스터-슬레이브 패턴 (Master-slave pattern)</h3>
<p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/96643045-221b-4059-83e0-c92da4d3b9f4/image.png" />
</p>

<p>이 패턴은 마스터 컴포넌트가 동등한 구조의 슬레이브 컴포넌트로 작업을 분산하고, 슬레이브가 결과값을 반환하면 최종 결과값을 계산하는 구조입니다.</p>
<h6 id="사용-예시-1">사용 예시</h6>
<pre><code>- 컴퓨터 시스템에서 버스와 연결된 주변장치</code></pre><br />

<h3 id="04-파이프-필터-패턴-pipe-filter-pattern">04. 파이프-필터 패턴 (Pipe-filter pattern)</h3>
<p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/f64723c9-87e2-4e9d-b133-66b4c5655c10/image.png" />
</p>

<p>데이터 스트림을 생성하고 처리하는 시스템에서 사용할 수 있습니다.
필터 컴포넌트에서 각 처리과정을 실행하며, 처리된 데이터는 파이프를 통해 전송됩니다.
파이프는 버퍼링 또는 동기화 목적으로도 사용될 수 있습니다.</p>
<h6 id="사용-예시-2">사용 예시</h6>
<pre><code>- Unix의 쉘 방식
- 컴파일러의 어휘 분석, 파싱, 의미 분석</code></pre><br />

<h3 id="05-브로커-패턴-broker-pattern">05. 브로커 패턴 (Broker pattern)</h3>
<p>분리된 컴포넌트로 구성된 분산 시스템에서 사용되는 패턴입니다.
각 컴포넌트들은 원격 서비스를 통해 서로 상호작용을 할 수 있으며 브로커 컴포넌트가 컴포넌트 간의 통신을 조절합니다.</p>
<p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/535849bd-6917-4b44-bebf-a289770bcb26/image.png" />
</p>

<h5 id="작동방식">작동방식</h5>
<p>서버가 자신의 서비스를 브로커에 넘기고(publish), 클라이언트가 브로커에 서비스를 요청하면 브로커가 자신의 레지스트리에 있는 적합한 서비스로 리디렉션 합니다.</p>
<h6 id="사용-예시-3">사용 예시</h6>
<pre><code>- 메시지 브로커 소프트웨어</code></pre><br />

<h3 id="06-피어-투-피어-패턴-peer-to-peer-pattern">06. 피어 투 피어 패턴 (Peer-to-peer pattern)</h3>
<p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/973ccf45-a8de-47fb-b482-dd99b7fda47b/image.png" />
</p>

<p>피어라 부르는 각 컴포넌트 간에 서비스를 주고 받는 패턴입니다.
피어는 클라이언트로서 각 피어에게 서비스를 요청할 수 있고, 서버로서 각 피어에게 서비스를 제공할 수도 있습니다.
피어 객체 하나가 클라이언트, 서버의 역할을 모두 수행하는 구조입니다.</p>
<h6 id="사용-예시-4">사용 예시</h6>
<pre><code>- 파일 공유 네트워크(P2P)
- 멀티미디어 애플리케이션</code></pre><br />

<h3 id="07-이벤트-버스-패턴-event-bus-pattern">07. 이벤트-버스 패턴 (Event-bus pattern)</h3>
<pre><code>이벤트 소스 : 이벤트 버스를 통해 특정 채널로 메시지를 발행(publish)
이벤트 리스너 : 특정 채널에서 메시지를 구독(subscribe)</code></pre><p>이벤트 소스(event source), 이벤트 리스너(~ listener), 채널(channel), 이벤트 버스(~ bus) 4가지 컴포넌트를 갖는 패턴입니다.</p>
<p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/01ae32ff-a835-467f-bade-b5e2bd5fb426/image.png" />
</p>

<p>리스너가 구독한 채널에 소스가 서비스를 제공하면 채널이 리스너에게 서비스를 제공해 주는 구조입니다.</p>
<h6 id="사용-예시-5">사용 예시</h6>
<pre><code>- 안드로이드 개발
- 알림 서비스</code></pre><br />


<h3 id="08-mvc-패턴-model-view-controller-pattern">08. MVC 패턴 (Model-view-controller pattern)</h3>
<pre><code>모델 : 도메인의 기능과 자료를 저장, 보관
뷰 : 사용자에게 결과를 표시(하나 이상 정의 가능)
컨트롤러 : 사용자로부터 입력과 상호작용을 처리</code></pre><p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/e6fe3fe7-89af-4a02-985e-d9a6397e7834/image.png" />
</p>

<p>3개의 각 컴포넌트는 각자의 역할을 갖고 사용자에게 서비스를 제공합니다.</p>
<p>기능마다 컴포넌트를 나눈 이유는 사용자 인터페이스(뷰)가 모델과 컨트롤러 보다 더욱 자주 변경되기 때문입니다.
또한 자료의 저장, 제어 기능과 표현 기능을 분리하여 재사용을 증진시키기 위함입니다.</p>
<h6 id="사용-예시-6">사용 예시</h6>
<ul>
<li>일반적인 웹 애플리케이션 설계 아키텍처</li>
</ul>
<br />

<h3 id="09-블랙보드-패턴-blackboard--pattern">09. 블랙보드 패턴 (Blackboard- pattern)</h3>
<pre><code>블랙보드 : 중앙 데이터 저장소
지식 소스(knowledge source) : 특수한 문제를 해결하는 독립 서브시스템
제어 컴포넌트(control component) : 변경을 모니터링하고, 다음 동작을 결정</code></pre><p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/6b324131-d897-41ff-ae16-f86e23ff4d7b/image.png" />
</p>

<p><strong>명확히 정의된 해결 전략이 알려지지 않은 문제에 대해서 유용한 패턴</strong>입니다.</p>
<p>부분적인 해법, 대략적인 해법을 수립하기 위한 서브시스템의 지식을 조합하는 방법입니다.</p>
<p>모든 컴포넌트는 블랙보드에 접근하여 새로운 데이터 객체를 생성할 수 있습니다.
공유 데이터 구조 위에서 종합적으로 동작하는 독립적인 프로그램을 모은 방법입니다.
각 프로그램은 전체 중 특정한 부분을 해결하기 위해 특수화 되어있습니다.
제어 컴포넌트는 현재 처리 과정을 평과하여 특수화 된 프로그램을 조율합니다.</p>
<h6 id="사용-예시-7">사용 예시</h6>
<ul>
<li>음성 인식</li>
<li>차략 식별 및 추적</li>
<li>수중 음파 탐지기 신호 해석</li>
</ul>
<br />

<h3 id="10-인터프리터-패턴-interpreter-pattern">10. 인터프리터 패턴 (Interpreter pattern)</h3>
<p align="center">
<img width="60%" src="https://velog.velcdn.com/images/55555-jyeon/post/0ec4fab4-b933-4a79-8041-39fea512887e/image.png" />
</p>

<p>특정 언어로 작성된 프로그램을 해석하는 컴포넌트를 설계할 때 사용되는 패턴입니다.</p>
<h6 id="사용-예시-8">사용 예시</h6>
<ul>
<li>DB 쿼리 언어</li>
<li>통신 프로토콜 정의 언어</li>
</ul>
<br />
<hr />
<br />


<h4 id="국내에서-주로-많이-사용하는-다섯-가지의-아키텍처-패턴">국내에서 주로 많이 사용하는 다섯 가지의 아키텍처 패턴</h4>
<p>Layer 패턴
Broker 패턴
MVC 패턴
State-Logic-Display(3-tier) 패턴
Sense-Compute-Control 패턴</p>
<br />
<hr />

<p><em>reference</em></p>
<ul>
<li><a href="https://dataonair.or.kr/db-tech-reference/d-lounge/technical-data/?mod=document&amp;uid=235426">소프트웨어 아키텍처란 무엇인가</a></li>
<li><a href="https://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf">who needs architect?</a></li>
<li><a href="https://martinfowler.com/architecture/">소프트웨어 아키텍처의 중요성</a></li>
<li><a href="https://goofcode.github.io/architecture-vs-design">아키텍처와 디자인의 차이</a></li>
<li><a href="https://the-boxer.tistory.com/26">아키텍처 설명 요약</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[디자인 패턴과 프로그래밍 패러다임]]></title>
            <link>https://velog.io/@55555-jyeon/cs-note-01</link>
            <guid>https://velog.io/@55555-jyeon/cs-note-01</guid>
            <pubDate>Sat, 16 Mar 2024 12:30:04 GMT</pubDate>
            <description><![CDATA[<h6 id="📖-면접을-위한-cs-전공지식노트-내용과-관련된-포스팅">📖 면접을 위한 CS 전공지식노트 내용과 관련된 포스팅</h6>
<h2 id="디자인-패턴">디자인 패턴</h2>
<p>프로그램을 설계할 때 발생했던 문제점들을 해결할 수 있도록 하나의 <strong>규약</strong> 형태로 만들어 놓은 것</p>
<h3 id="싱글톤-패턴">싱글톤 패턴</h3>
<h6 id="singleton-pattern">singleton pattern</h6>
<p align="center">
<img width="70%"  src="https://github.com/inside-coding/cs-note/assets/134191817/ac3c6024-3b28-47c2-b6e7-5f2007bba126">
</p>

<ul>
<li>하나의 클래스에 하나의 인스턴스 <br /></li>
<li>하나의 인스턴스를 다른 모듈들이 공유하며 사용하는 형태 <br /></li>
<li>보통 데이터베이스 연결 모듈이 많이 사용</li>
</ul>
<h5 id="🟢-pros">🟢 PROS</h5>
<p>인스턴스 생성 비용 절감 <br />
실용적 <br /></p>
<h5 id="🔴-cons">🔴 CONS</h5>
<p>의존성이 높음 <br />
모듈 간의 결합을 강하게 함 → 의존성 주입으로 해결 가능 <br />
TDD의 걸림돌 <br /></p>
<h6 id="tdd">TDD?</h6>
<pre><code>Test Driven Development.
주로 단위 테스트를 하는데 이때 테스트는 서로 독립적이어야 하며 테스트를 어떤 순서로든 실행 가능해야 함.</code></pre><h6 id="의존성-주입">의존성 주입?</h6>
<p><strong>원칙</strong> <br />
&quot;상위 모듈은 하위 모듈에서 어떠한 것도 가져오지 않아야 한다. 또한 둘 다 추상화에 의존해야 하며, 이때 추상화는 세부 사항에 의존하지 말아야 한다.&quot;</p>
<p align="center">
<img width="60%" src="https://github.com/inside-coding/cs-note/assets/134191817/1c12691c-1335-4565-bf4b-8930e1deb180" />
</p>

<pre><code>DI, Dependency Injection.
&quot;의존성이 떨어진다&quot; === &quot;디커플링 된다&quot;</code></pre><h6 id="🟢-pros-1">🟢 PROS</h6>
<p>테스팅에 용이 <br />
수월한 마이그레이션 <br />
일관된 애플리케이션의 의존성 방향 <br />
애플리케이션의 쉬운 추론 <br />
모듈 간 관계들의 명확성 보장</p>
<h6 id="🔴-cons-1">🔴 CONS</h6>
<p>분리된 모듈들로 복잡성 증가 <br />
약간의 런타임 패널티</p>
<br />

<h5 id="example">example</h5>
<p>JS에서는 리터럴(&#39;{}&#39;) 또는 new Object로 객체 생성만으로도 싱글톤 패턴 구현이 가능 → 다른 어떤 객체와도 같지 않으므로</p>
<pre><code class="language-javascript">const obj1 = { a: 27 };
const obj2 = { a: 27 };

console.log(obj1 === obj2); // false</code></pre>
<p>실제 싱글톤은 아래와 같은 코드로 구성</p>
<pre><code class="language-javascript">class Singleton {
  constructor() {
    if (!Singleton.instance) {
      Singleton.instance = this;
    }
    return Singleton.instance;
  }
  getInstance() {
    return this.instance;
  }
}

const a = new Singleton();
const b = new Singleton();
console.log(a === b); // true</code></pre>
<br />

<h3 id="팩토리-패턴">팩토리 패턴</h3>
<h6 id="factory-pattern">factory pattern</h6>
<p align="center">
<img width="70%"  src="https://github.com/inside-coding/cs-note/assets/134191817/6a32e896-3963-4548-ad9e-aaaea86eb7c9">
</p>

<ul>
<li>객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴</li>
<li>상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대, 하위 클래스에서 구체적인 내용을 결정하는 패턴</li>
<li>클래스가 상위, 하위로 분리되므로 느슨한 결합으로 인해 유연성 ⬆️</li>
</ul>
<h5 id="🟢-pros-2">🟢 PROS</h5>
<p>유지 보수성 용이 <br /></p>
<h5 id="🔴-cons-2">🔴 CONS</h5>
<br />

<h6 id="example-1">example</h6>
<pre><code class="language-javascript">const num = new Object(123);
const str = new Object(&quot;abc&quot;);
num.constructor.name; // Number
str.constructor.name; // String</code></pre>
<br />

<h3 id="전략-패턴-정책-패턴">전략 패턴 (정책 패턴)</h3>
<h6 id="strategy-pattern-policy-pattern">strategy pattern (policy pattern)</h6>
<p align="center">
<img width="70%" src="https://github.com/inside-coding/cs-note/assets/134191817/425e9a53-0226-420b-bae2-a568fc43f22b">
</p>

<ul>
<li>객체의 행위를 변경하고 싶은 경우 직접 수정 ❌</li>
<li>전략(캡슐화한 알고리즘)으로 컨텍스트 안에서 바꿔주며 상호 교체가 가능하도록 설계</li>
<li>ex) 결제 시 네이버페이, 카카오페이 등 다양한 방법으로 결제하는 것</li>
</ul>
<br />

<h4 id="passport의-전략-패턴">passport의 전략 패턴</h4>
<p>전략 패턴을 활용한 라이브러리</p>
<br />

<h3 id="옵저버-패턴">옵저버 패턴</h3>
<h6 id="observer-pattern">observer pattern</h6>
<ul>
<li>어떤 객체의 상태 변화를 관찰 → 변화 시 옵저버들에게 변화 알리기</li>
</ul>
<p align="center">
<img width="45%" src="https://github.com/inside-coding/cs-note/assets/134191817/d97af49f-3aaf-4a76-9a33-88c7da9bc322">
<img width="36%" src="https://github.com/inside-coding/cs-note/assets/134191817/a7a6bb87-19eb-4f03-b3ec-fe1925b63c25">
</p>

<ul>
<li><p>주체 : 객체의 상태 변화를 보고 있는 관찰자</p>
</li>
<li><p>옵저버 : 객체의 상태 변화에 따라 전달되는 것을 기반으로 <strong>추가 변경 사항</strong>이 생기는 객체들</p>
</li>
<li><p>주체와 객체를 따로 두지 않고 상태가 변경되는 객체를 기반으로 구축되기도 함</p>
</li>
<li><p>ex) 트위터</p>
</li>
</ul>
<p align="center">
<img width="50%" src="https://github.com/inside-coding/cs-note/assets/134191817/baf358ab-fcbf-4785-8440-419a241236ae">
</p>

<br />

<h5 id="-mvc-pattern">| MVC pattern</h5>
<p>옵저버 패턴은 주로 이벤트 기반 시스템에 사용하며 MVC 패턴에도 사용됨</p>
<p align="center">
<img width="70%" src="https://github.com/inside-coding/cs-note/assets/134191817/ec4633df-3ba1-4846-8f40-0b764a7fe393">
</p>

<br />

<h5 id="-proxy">| Proxy</h5>
<p>자바스크립트에서의 옵저버 패천은 프록시 객체를 통해 구현 가능</p>
<p><strong>| proxy 객체</strong>란?</p>
<p>어떠한 대상의 기본적인 동작(속성 접근, 할당, 순회, 열거 함수 호출 등)의 작업을 가로챌 수 있는 객체로, 자바스크립트에서 프록시 객체는 두 개의 매개변수를 가진다.</p>
<p>1️⃣ target: 프록시할 대상 <br />
2️⃣ handler: target 동작을 가로채 어떤 동작을 할 것인지 설정돼 있는 함수</p>
<p>[함수]</p>
<ul>
<li>get( ) : 속성과 함수에 대한 접근을 가로챈다.</li>
<li>has( ) : in 연산자의 사용을 가로챈다.</li>
<li>set( ) : 속성에 대한 접근을 가로챈다.</li>
</ul>
<pre><code class="language-javascript">// 프록시 객체
const handler = {
  get: function(target, name){
    ...
  }
}
const intercept = new Proxy({}, handler)</code></pre>
<br />

<h3 id="프록시-패턴">프록시 패턴</h3>
<h6 id="proxy-pattern">proxy pattern</h6>
<p>대상 객체에 접근 전 접근에 대한 흐름을 가로채 필터링하거나 수정하는 등의 역할을 하는 계층이 있는 디자인 패턴</p>
<p align="center">
<img width="70%" src="https://github.com/inside-coding/cs-note/assets/134191817/6a4d55e2-f4ac-4615-995e-31d4dc3342cf">
</p>

<p>객체의 속성, 변환 등을 보완 <br />
보안, 데이터 검증, 캐싱, 로깅에 사용 <br />
프록시 객체로도 프록시 서버로도 쓰임 <br /></p>
<h5 id="프록시-서버">프록시 서버</h5>
<p>서버와 클라이언트 사이에서 클라이언트가 자신을 통해 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템이나 응용 프로그램 <br />
CORS 에러 해결책 중 하나이며 다양한 API 서버와의 매끄러운 통신 가능</p>
<ul>
<li><p>nginx</p>
</li>
<li><p><strong>CloudFlare</strong></p>
<p>CDN(Content Delivery Network) 서비스 <br />
DDOS 공격 방어 및 HTTPS 구축에 사용</p>
</li>
</ul>
<br />

<h3 id="이터레이터-패턴">이터레이터 패턴</h3>
<h6 id="iterator-pattern">iterator pattern</h6>
<p>이터레이터를 사용해 컬렉션의 요소들에 접근하는 디자인 패턴 <br /></p>
<p>순회할 수 있는 여러 가지 자료형의 구조와는 상관 없이 이터레이터라는 하나의 인터페이스로 순회 가능</p>
<p align="center">
<img width="60%" src="https://github.com/inside-coding/cs-note/assets/134191817/85a4c4ab-3f42-4111-9f38-a454918aaac1">
</p>

<h6 id="example-2">example</h6>
<p>다른 자료구조인 set, map 임에도 <strong>for ~ of ~</strong> 로 순회 가능</p>
<pre><code class="language-javascript">const mp = new Map();
mp.set(&quot;a&quot;, 1);
mp.set(&quot;b&quot;, 2);
mp.set(&quot;c&quot;, 3);

const st = new Set();
st.add(1);
st.add(2);
st.add(3);

for (let a of mp) console.log(a); // [&#39;a&#39;, 1] [&#39;b&#39;, 2] [&#39;c&#39;, 3]
for (let a of st) console.log(a); // 1 2 3</code></pre>
<br />

<h3 id="노출모듈-패턴">노출모듈 패턴</h3>
<h6 id="revealing-module-pattern">revealing module pattern</h6>
<p>즉시 실행 함수를 통해 접근 제어자를 만드는 패턴</p>
<p>자바스크립트는 접근 제어자가 존재하지 않고, 전역 범위에서 스크립트가 실행 <br />
따라서 노출모듈 패턴을 통해 접근 제어자를 구현하기도 한다. <br />
자바스크립트 모듈 방식 👉 [CJS(CommonJS)]</p>
<h5 id="접근-제어자">접근 제어자</h5>
<table>
  <tr>
    <td rowspan="2">접근 제어자</td>
    <td rowspan="2">접근 가능 위치</td>
    <td colspan="2">접근 범위</td>
  </tr>
  <tr>
    <td>자식 클래스</td>
    <td>외부 클래스</td>
  </tr>
  <tr>
    <td>Public</td>
    <td rowspan="3">클래스에 정의된 함수에서 접근 가능</td>
    <td>O</td>
    <td>O</td>
  </tr>
  <tr>
    <td>Protected</td>
    <td>O</td>
    <td>X</td>  
  </tr>
  <tr>
    <td>Private</td>
    <td>X</td>
    <td>X</td>
  </tr>
</table>

<br />

<h3 id="mvc-패턴">MVC 패턴</h3>
<p>Model, View, Controller로 이뤄진 디자인 패턴</p>
<p align="center">
<img width="70%" src="https://github.com/inside-coding/cs-note/assets/134191817/c83b41d7-70cb-4100-a102-fe4b6898aaf3">
</p>

<p>애플리케이션의 구성 요소를 세 가지 역할로 구분해 개발 프로세스에서 각각의 구성 요소에만 집중해 개발 가능</p>
<h5 id="구성요소-설명">구성요소 설명</h5>
<p><strong>| Model (모델)</strong></p>
<pre><code>View에서 데이터를 생성/수정하면 컨트롤러를 통해 모델을 생성/갱신

애플리케이션의 데이터인 데이터베이스, 상수, 변수 등</code></pre><p><strong>| View(뷰)</strong></p>
<pre><code>Model이 가지고 있는 정보를 따로 저장 X
단순한 화면 표시 정보만 O
변경이 일어나면 컨트롤러에 이를 전달

모델을 기반으로 사용자가 볼 수 있는 화면으로 inputbox, checkbox, textarea 등 사용자 인터페이스 요소가 이에 해당</code></pre><p><strong>| Controller(컨트롤러)</strong> <br /></p>
<pre><code>하나 이상의 Model과 하나 이상의 View를 잇는 다리 역할
이벤트 등 메인 로직을 담당
Model과 View의 생명주기를 관리
Model이나 View의 변경 통지 → 해석 → 각각의 구성 요소에 해당 내용 전달</code></pre><br />

<h5 id="🟢-pros-3">🟢 PROS</h5>
<ul>
<li>재사용성과 확장성이 용이</li>
</ul>
<h5 id="🔴-cons-3">🔴 CONS</h5>
<ul>
<li>애플리케이션이 복잡해질수록 Model과 View의 관계도 함께 복잡해짐</li>
</ul>
<h6 id="example-3">example</h6>
<p>MVC 패턴을 이용한 대표적인 프레임워크는 자바 플랫폼을 위한 오픈 소스 애플리케이션 프레임워크인 <strong>Spring(스프링)</strong></p>
<br />

<h3 id="mvp-패턴">MVP 패턴</h3>
<p>MVC 패턴으로부터 파생된 패턴으로 Controller가 Presenter(프레젠터)로 교체된 패턴</p>
<p align="center">
<img width="70%" src="https://github.com/inside-coding/cs-note/assets/134191817/093a0a0c-0059-4d09-81da-e8819a5f1f5b" />
</p>

<p>View와 Presenter가 1:1 관계이므로 MVC 패턴보다 더 강한 결합을 지닌 패턴</p>
<br />

<h3 id="mvvm-패턴">MVVM 패턴</h3>
<p>MVC의 C에 해당하는 컨트롤러가 뷰모델(View Model)로 바뀐 패턴</p>
<p align="center">
<img width="80%" src="https://github.com/inside-coding/cs-note/assets/134191817/840ba454-a9c7-4a4d-8eac-4716e1b9cd1f" />
</p>

<p>뷰모델은 뷰를 더 추상화한 계층으로 MVC 패턴과는 다르게 커맨드와 데이터 바인딩을 가진다는 특징을 갖고 있다.</p>
<h5 id="🟢-pros-4">🟢 PROS</h5>
<ul>
<li>뷰와 뷰 모델 사이의 양방향 데이터 바인딩을 지원</li>
<li>UI를 별도의 코드 수정없이 재사용 가능</li>
<li>쉬운 단위 테스팅</li>
</ul>
<h6 id="example-4">example</h6>
<p>MVVM 패턴을 가진 대표적인 프레임워크로 <strong>Vue.js(뷰)</strong>가 있다.</p>
<br />

<br />
<hr />
<br />

<h2 id="02-프로그래밍-패러다임">02. 프로그래밍 패러다임</h2>
<p>프로그래밍 패러다임은 프로그래머에게 프로그래밍의 관점을 갖게 해주는 역할을 하는 개발 방법론</p>
<p align="center">
<img width="70%" src="https://github.com/inside-coding/cs-note/assets/134191817/792371f8-fb54-46c5-9a29-7e8a0b4ea669">
</p>

<p>자바스크립트는 단순하고 유연한 언어이며 함수가 일급 객체이므로 객체지향 프로그래밍보다는 함수형 프로그래밍 방식이 선호됨</p>
<br />

<h3 id="선언형과-함수형-프로그래밍">선언형과 함수형 프로그래밍</h3>
<h4 id="선언형-declarative">선언형 (declarative)</h4>
<p>&#39;무엇을&#39; 풀어내는가에 집중한 패러다임 <br />
&quot;프로그램은 함수로 이뤄진 것이다.&quot; 라는 명제가 담긴 패러다임 <br /></p>
<h4 id="함수형-functional">함수형 (functional)</h4>
<p>선언형 패러다임의 일종 <br />
순수 함수들을 쌓아 로직을 구현 → &#39;고차 함수&#39;를 통해 재사용성을 높인 패러다임 <br /></p>
<h5 id="특징">특징</h5>
<ul>
<li>커링(Currying)</li>
<li>불변성(Unmodifiable)</li>
<li>...</li>
</ul>
<br />

<h3 id="객체지향-프로그래밍-oop">객체지향 프로그래밍 (OOP)</h3>
<h6 id="object-oriented-programming">Object-Oriented Programming</h6>
<p>객체들의 집합으로 프로그램이 상호 작용을 표현 <br />
데이터를 객체로 취급해 객체 내부에 선언된 메서드를 활용하는 방식 <br /></p>
<h5 id="특징-1">특징</h5>
<ul>
<li><p>추상화 (abstraction)</p>
<p>복잡한 시스템으로부터 핵심적인 개념 또는 기능을 간추린 것을 의미</p>
</li>
<li><p>캡슐화 (encapsulation)</p>
<p>객체의 속성과 메서드를 하나로 묶고 일부를 은닉시키는 것을 의미</p>
</li>
<li><p>상속성 (inheritance)</p>
<p>상위 클래스를 하위 클래스가 상속받아 재사용/추가/확장 하는 것 <br />
코드의 재사용 측면, 계층적인 관계 생성, 유지보수측에서 중요</p>
</li>
<li><p>다형성 (polymorphism)</p>
<p>하나의 메서드나 클래스가 다양한 방법으로 동작하는 것 <br />
대표적으로 오버로딩과 오버라이딩</p>
<p>오버로딩 (overloading) <br />
같은 이름을 가진 메서드를 여러 개 두는 것 <br />
타입, 매개변수 유형이나 개수 등으로 차이를 두지만 동일한 이름 <br />
👉 &#39;정적 다형성&#39;</p>
<p>오버라이딩(overriding) <br />
주로 메서드 오버라이딩을 말하며
상위 클래스로부터 상속받은 메서드를 하위 클래스가 재정의하는 것을 의미 <br />
👉 &#39;동적 다형성&#39;</p>
</li>
</ul>
<h5 id="🔴-cons-4">🔴 CONS</h5>
<ul>
<li>설계에 많은 시간이 소요</li>
<li>처리 속도가 다른 프로그래밍 패러다임에 비해 상대적으로 느림</li>
</ul>
<br />

<h3 id="solid">SOLID</h3>
<h6 id="설계-원칙solid원칙">설계 원칙(SOLID원칙)</h6>
<p>객체지향 프로그래밍을 설계할 때 지켜야 하는 원칙 <br /></p>
<p align="center">
<img width="70%" src="https://github.com/inside-coding/cs-note/assets/134191817/91354061-bb37-43d2-a2b4-bcb8c69e0bf4">
</p>

<h4 id="s">S</h4>
<h6 id="srpsingle-responsibility-principle--단일-책임-원칙">SRP(Single Responsibility Principle) : 단일 책임 원칙</h6>
<p>모든 클래스는 하나의 책임만 가져야 한다.</p>
<h4 id="o">O</h4>
<h6 id="ocpopen-closed-principle--개방-폐쇄-원칙">OCP(Open Closed Principle) : 개방-폐쇄 원칙</h6>
<p>기존 코드는 잘 변경하지 않으면서도 확장은 쉽게 할 수 있어야 한다.</p>
<h4 id="l">L</h4>
<h6 id="lspliskov-substitution-principle--리스코프-치환-원칙">LSP(Liskov Substitution Principle) : 리스코프 치환 원칙</h6>
<p>프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다. <br />
상속 관계에서 부모와 자식의 위치를 바꾸어도 시스템이 문제없이 돌아가야 한다.</p>
<h4 id="i">I</h4>
<h6 id="ispinterface-segregation-principle--인터페이스-분리-원칙">ISP(Interface Segregation Principle) : 인터페이스 분리 원칙</h6>
<p>하나의 일반적인 인터페이스보다 구체적인 여러 개의 인터페이스를 만들어야 한다.</p>
<h4 id="d">D</h4>
<h6 id="dipdependency-inversion-principle--의존-역전-원칙">DIP(Dependency Inversion Principle) : 의존 역전 원칙</h6>
<p>자신보다 변하기 쉬운 것에 의존하던 것을 추상화된 인터페이스나 상위 클래스를 두어 변하기 쉬운 것의 변화에 영향 받지 않게 하는 원칙. <br />
즉, 상위 계층은 하위 계층의 변화에 대한 구현으로부터 독립해야 한다.</p>
<br />

<h3 id="절차형-프로그래밍">절차형 프로그래밍</h3>
<p>로직이 수행되어야 할 연속적인 계산 과정으로 이루어져 있다. <br />
계산이 많은 작업에 주로 사용됨. <br />
ex) 포트란(fortran)을 이용한 대기 과학 관련 연산 작업, 머신 러닝의 배치 작업 등</p>
<h5 id="🟢-pros-5">🟢 PROS</h5>
<p>코드를 구현하기만 하면 되서 코드의 가독성이 좋으며 실행 속도가 빠르다.</p>
<h5 id="🔴-cons-5">🔴 CONS</h5>
<p>모듈화하기가 어렵고 유지보수성이 떨어진다.</p>
<br />

<h3 id="패러다임의-혼합">패러다임의 혼합</h3>
<p>어떠한 패러다임이 가장 좋다는 정답은 ❌ <br />
비즈니스 로직이나 서비스의 특징을 고려해서 적재적소에 맞는 패러다임을 정하는 것이 좋다.</p>
<p>하나의 패러다임을 기반으로 통일하여 서비스를 구축하는 것도 좋은 생각이지만 여러 패러다임을 조합하여 상황과 맥락에 따라 패러다임 간의 장점만 취해 개발하는 것이 좋다.</p>
<br />
]]></description>
        </item>
        <item>
            <title><![CDATA[모아서 해? 나눠서 해?]]></title>
            <link>https://velog.io/@55555-jyeon/react-improve-performance</link>
            <guid>https://velog.io/@55555-jyeon/react-improve-performance</guid>
            <pubDate>Tue, 12 Mar 2024 20:20:59 GMT</pubDate>
            <description><![CDATA[<p>성능의 향상을 위해서는 코드를 잘 처리해야 합니다. 
내가 작성한 코드들을 전달할 때 모아서 한꺼번에 처리를 하는게 좋을까요, 아니면 쪼개서 작은 단위로 처리하는 것이 좋을까요?</p>
<h2 id="한-번에-처리할까">한 번에 처리할까?</h2>
<h5 id="batching">batching</h5>
<p>batching은 react의 성능 향상을 위해 여러 개의 state 업데이트를 한 번의 re-rendering으로 묶어서 진행하는 것을 말합니다.
이를 통해 불필요한 render 함수의 호출을 방지하여 렌더링 성능을 향상시킬 수 있습니다.</p>
<p>예를 들어 문서를 출력할 때 낱장으로 하는 것보다 한꺼번에 출력하는 것이 시간과 과정을 단축시키는 것과 같이 리액트의 batching도 이와 비슷한 원리로 동작합니다.</p>
<blockquote>
<p>👨‍🍳 더 재미있는 예시로는 
<a href="https://nukw0n-dev.tistory.com/33">레스토랑에서 종업원이 손님이 주문하는 첫번째 메뉴를 듣자마자 주방으로 달려가지 않듯이 Batching은 반드시 필요한 하나의 리렌더링을 수행한다.</a>
가 있을 것 같습니다.</p>
</blockquote>
<h3 id="automatic-batching">automatic batching</h3>
<h4 id="batching과의-차이점">batching과의 차이점</h4>
<p>React 18 버전 이하에서는 리액트의 이벤트 핸들러 내부의 state update 작업에 대해서만 batching이 가능했습니다. 브라우저의 이벤트가 실행되는 중에만 batching을 수행했기 때문에 이벤트가 종료된 후에 실행되는 경우는 batching이 불가능했습니다.</p>
<pre><code class="language-javascript">// Before React 18 only React events were batched

function handleClick() {
  setCount(c =&gt; c + 1);
  setFlag(f =&gt; !f);
  // React will only re-render once at the end (that&#39;s batching!)
}

setTimeout(() =&gt; {
  setCount(c =&gt; c + 1);
  setFlag(f =&gt; !f);
  // React will render twice, once for each state update (no batching)
}, 1000);</code></pre>
<p>하지만 React 18 버전 이후부터는 18 이전에 포함되지 않았던 작업에 대해서도 batching을 자동으로 수행될 수 있도록 변경되었습니다.</p>
<pre><code class="language-javascript">// After React 18 updates inside of timeouts, promises,
// native event handlers or any other event are batched.

function handleClick() {
  setCount(c =&gt; c + 1);
  setFlag(f =&gt; !f);
  // React will only re-render once at the end (that&#39;s batching!)
}

setTimeout(() =&gt; {
  setCount(c =&gt; c + 1);
  setFlag(f =&gt; !f);
  // React will only re-render once at the end (that&#39;s batching!)
}, 1000);</code></pre>
<p>React18에서 제공하는 <code>ReactDOM.createRoot</code> 메서드를 기반으로 렌더링을 진행할 경우 모든 state update 작업은 자동으로 batching 처리되는데 이 기능을 Automatic Batching 이라고 합니다.</p>
<pre><code class="language-javascript">// before React18
ReactDOM.render(
  &lt;React.StrictMode&gt;
    &lt;App /&gt;
  &lt;/React.StrictMode&gt;,
  document.getElementById(&#39;root&#39;)
);</code></pre>
<pre><code class="language-javascript">// after React18
import { createRoot } from &quot;react-dom/client&quot;; 
const root = createRoot(document.getElementById(&quot;root&quot;)); 

root.render(
  &lt;React.StrictMode&gt;
    &lt;App /&gt;
  &lt;/React.StrictMode&gt;
);</code></pre>
<br />

<h6 id="example">example</h6>
<p>react의 예시 말고 다른 걸 예시로 들자면...</p>
<pre><code class="language-javascript">// before react18
import { useEffect } from &#39;react&#39;;

const UserList = ({ userIds }) =&gt; {
  useEffect(() =&gt; {
    // 일반적인 방법: 각각의 사용자 정보를 순차적으로 로드하고 처리
    userIds.forEach(userId =&gt; {
      const user = loadUserInfo(userId);
      processUserInfo(user);
    });
  }, [userIds]);

  return &lt;div&gt;User List&lt;/div&gt;;
};</code></pre>
<p>위 코드에서는 useEffect를 사용하여 컴포넌트가 렌더링될 때마다 각 사용자의 정보를 순차적으로 로드하고 처리합니다.</p>
<p>아래 코드에서는 useEffect 내에서 Automatic Batching을 구현하여 정의된 batchSize에 따라 자동으로 데이터를 묶어주고 각 batch에 대해 작업을 수행합니다. 이렇게 하면 자동으로 batching이 이루어지므로 코드가 간결해지고 성능 향상이 가능합니다.</p>
<pre><code class="language-javascript">// after react18
import { useEffect } from &#39;react&#39;;

const UserList = ({ userIds }) =&gt; {
  useEffect(() =&gt; {
    // Automatic Batching을 사용한 경우
    const batchSize = 3;
    for (let i = 0; i &lt; userIds.length; i += batchSize) {
      const batch = userIds.slice(i, i + batchSize);
      const users = batch.map(userId =&gt; loadUserInfo(userId));
      processUserInfos(users);
    }
  }, [userIds]);

  return &lt;div&gt;User List&lt;/div&gt;;
};</code></pre>
<p>batchSize는 한 번에 처리할 데이터의 묶음 크기를 나타냅니다. Automatic Batching에서 사용되는 개념으로, 데이터를 미리 정의된 크기의 작은 묶음으로 나누어 처리함으로써 성능을 향상시킬 수 있습니다.</p>
<br />

<h5 id="🚫-automatic-batching">🚫 automatic batching</h5>
<h3 id="flushsync">flushSync</h3>
<p>react-dom 라이브러리에 추가된 <code>ReactDOM.flushSync()</code> 메서드는 Auto Batching 을 무시하고 즉시 DOM을 렌더링해줍니다.
React에서는 공식적으로 해당 메서드의 사용을 추천하진 않으며 (de-opt case), 필요한 상황이 있을 경우에만 사용할 것을 강조했습니다.</p>
<pre><code class="language-javascript">import { flushSync } from &quot;react-dom&quot;;

  // handleClick 시 총 두 번의 리렌더링을 수행
function handleClick() {
    // flushSync 메서드가 실행되는 즉시 DOM을 업데이트
    flushSync(() =&gt; setCounter((c) =&gt; c + 1));
    flushSync(() =&gt; setFlag((f) =&gt; !f));
}</code></pre>
<br />
<hr />

<h2 id="나눠서-처리할까">나눠서 처리할까?</h2>
<p>SPA(Single Page Application)의 특성상 첫 페이지 진입 시 웹팩(webpack)에서 압축한 bundle file을 다운받게 됩니다.</p>
<p>즉, 전체 리소스를 한번에 다운받게 되므로 결과적으로 client는 전체 리소스의 bundle file 을 다운받기 전에는 화면을 볼 수 없습니다. 이는 인터넷 속도가 빠른 환경에서는 큰 차이를 느낄 수 없지만 인터넷 환경이 느린 경우에 사용자 경험을 저하시키는 요인이 될 수 있으므로 사이트의 상황에 따라 신경을 써줘야 하는 경우가 생길 수 있습니다.</p>
<h3 id="code-splitting">code splitting</h3>
<p>코드분할(code splitting)을 통해 위 문제를 해결할 수 있습니다. </p>
<p>코드분할을 하면 필요한 값들을 미리 제공하는 데 필요한 최소한의 코드를 전송할 수 있어 페이지의 로드 시간 단축을 할 수 있습니다. 당장 필요하지 않은 나머지 값들은 요청 시 로드할 수 있습니다.</p>
<p>코드 양을 줄이지 않고도 사용자가 필요하지 않은 코드를 불러오지 않게 적절한 사이즈의 코드가 적절한 타이밍에 동적으로 load되도록 해줍니다.</p>
<p>코드 분할은 <code>react.lazy</code>와 <code>suspense</code>로 구현할 수 있습니다.</p>
<h4 id="lazy-loading">lazy loading</h4>
<p>웹페이지에는 데이터 사용량과 페이지 로드 속도에 영향을 미치는 많은 이미지가 포함되어 있는 경우가 많습니다. lazy loading은 페이지를 읽어들이는 시점에 중요하지 않은 리소스 로딩을 추 후에 하는 기술 입니다. 대신에 이 중요하지 않은 리소스들은 필요할 때 로드가 되어야 합니다.</p>
<p>lazy loading을 사용하면 페이지가 placeholder 콘텐츠로 작성되며, 사용자가 필요할 때만 실제 콘텐츠로 대체 됩니다.</p>
<p><strong>1️⃣ 글꼴</strong></p>
<p>본적으로 글꼴 요청은 렌더링 트리가 구성될 때까지 지연되므로 텍스트 렌더링이 지연될 수 있습니다.</p>
<p><code>&lt;link rel=&quot;preload&quot;&gt;</code>, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display">CSS 글꼴 표시 속성</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Font_Loading_API">글꼴 로딩 API</a> 등을 사용하여 기본 동작을 재정의하고 웹 글꼴 리소스를 미리 load할 수 있습니다.</p>
<br />


<p><strong>2️⃣ 이미지와 동영상</strong></p>
<p><code>&lt;img&gt;</code>과 <code>&lt;iframe&gt;</code>의 loading 속성을 사용하면 사용자가 화면 근처에 스크롤할 때까지 화면 밖에 있는 이미지/동영상의 load를 연기하도록 브라우저에 지시할 수 있습니다. 이를 통해 중요하지 않은 리소스는 필요한 경우에만 로드할 수 있으므로 잠재적으로 초기 페이지 로드 속도가 빨라지고 네트워크 사용량이 줄어듭니다.</p>
<pre><code class="language-javascript">&lt;img loading=&quot;lazy&quot; src=&quot;image.jpg&quot; alt=&quot;...&quot; /&gt;
&lt;iframe loading=&quot;lazy&quot; src=&quot;video-player.html&quot; title=&quot;...&quot;&gt;&lt;/iframe&gt;</code></pre>
<p>이미지가 많은 사이트에서 자주 사용되며 <a href="https://unsplash.com/">unsplash.com</a>을 예시로 들 수 있습니다. 페이지의 해당 부분을 스크롤하면 placeholder image가 full-res 사진으로 대체됩니다. </p>
<p>일반적인 로직은 이와 같습니다.</p>
<pre><code>1) 이미지 태그에 src값을 넣지 않고 data-src와 같은 data 어트리 뷰트를 사용하여 해당 data 어트리 뷰트에 실제 로드할 이미지 주소를 기입합니다.

2) 이미지들을 모두 읽어서 객체에 담습니다.

3) 해당 이미지가 로드가 완료되면(onload) data-src(data 어트리뷰트)에 있는 주소 값을 src값으로 셋팅을 하고 data-src어트리 뷰트는 삭제합니다.</code></pre><br />

<p><strong>3️⃣ component</strong></p>
<p>React.lazy 함수와 Suspense 컴포넌트를 사용하여 컴포넌트를 지연 로딩하는 방법은 아래와 같습니다.</p>
<p>먼저, MyLazyComponent.js라는 파일을 생성하고 지연 로딩할 컴포넌트를 정의합니다.</p>
<pre><code class="language-javascript">// MyLazyComponent.js
import React from &#39;react&#39;;

const MyLazyComponent = () =&gt; {
  return (
    &lt;div&gt;
      &lt;p&gt;This is a lazily loaded component!&lt;/p&gt;
    &lt;/div&gt;
  );
};

export default MyLazyComponent;</code></pre>
<p>그런 다음, 메인 애플리케이션 파일에서 React.lazy를 사용하여 위에서 만든 MyLazyComponent를 지연 로딩합니다.</p>
<pre><code class="language-javascript">// App.js
import React, { lazy, Suspense } from &#39;react&#39;;

// MyLazyComponent를 React.lazy를 사용하여 지연 로딩
const MyLazyComponent = lazy(() =&gt; import(&#39;./MyLazyComponent&#39;));

const App = () =&gt; {
  return (
    &lt;div&gt;
      &lt;h1&gt;Lazy Loading Example&lt;/h1&gt;
      {/* Suspense 컴포넌트를 사용하여 로딩 중에 표시할 내용 정의 */}
      &lt;Suspense fallback={&lt;div&gt;Loading...&lt;/div&gt;}&gt;
        {/* 지연 로딩된 컴포넌트 렌더링 */}
        &lt;MyLazyComponent /&gt;
      &lt;/Suspense&gt;
    &lt;/div&gt;
  );
};

export default App;</code></pre>
<p>이제 App.js 파일에서 MyLazyComponent를 가져올 때 React.lazy를 사용하여 동적으로 로딩합니다. Suspense 컴포넌트는 해당 컴포넌트가 로딩되는 동안 표시할 내용을 정의합니다.</p>
<p>이 예제에서는 &quot;Loading...&quot; 텍스트를 사용했지만, 실제 프로덕션 환경에서는  스피너나 로딩 애니메이션 혹은 직접 제작한 loading 페이지 등으로 대체하는 것을 권장합니다.</p>
<br />

<h4 id="intersection-observer">Intersection observer</h4>
<p>최신 브라우저는 intersection observer api를 통해 요소가 화면에 표시 되는 것을 검사하는 작업을 보다 효율적이고 수행할 수 있습니다.
(일부 브라우저에서는 Intersetion observer가 지원되지 않습니다. 지원되지 않는 브라우저에서는 비교적 성능은 떨어지지만 호환성을 더 높은 scroll, resize 이벤트 핸들러 사용이 가능합니다.</p>
<p>Intersection event observer는 요소가 화면에 표시하는 것을 계산하는 코드를 작성하는 대신 관찰자를 등록하기만 하면 되기 때문에 다양한 이벤트 핸들러에 의존하는 코드보다 사용하고 읽는 것이 더 쉽습니다.</p>
<br />
<br />

<h2 id="🍻-성능-향상을-위하여">🍻 성능 향상을 위하여</h2>
<p>두 기술은 각각의 상황에서 성능 향상을 위해 사용되며, Lazy Loading은 초기 로딩 속도를 개선하고, Automatic Batching은 불필요한 렌더링을 방지하여 React 애플리케이션의 효율성을 높이는 데 기여합니다.</p>
<p><strong>lazy loading</strong></p>
<ul>
<li><p>대규모 애플리케이션에서 초기 로딩 속도를 최적화하려는 경우</p>
</li>
<li><p>특정 페이지나 컴포넌트가 사용자의 상호작용에 따라 동적으로 로딩되어야 하는 경우</p>
<p>  [사례]
  라우팅을 통해 페이지 간 전환 시 필요한 컴포넌트를 지연 로딩
  특정 이벤트에 응답하여 필요한 기능을 동적으로 로딩</p>
</li>
</ul>
<p><strong>automatic batching</strong></p>
<ul>
<li><p>여러 개의 상태 업데이트가 발생하는 상황에서 최적의 렌더링 성능을 추구할 때</p>
</li>
<li><p>다수의 UI 업데이트를 특정 프레임에 일괄 처리하여 렌더링을 최소화하고 성능을 향상시킬 때</p>
<p>  [사례]
  이벤트 핸들러에서 여러 번의 setState 호출이 있는 경우, 자동으로 이를 일괄 처리하여 최적화</p>
</li>
</ul>
<p><strong>Together?</strong></p>
<p>대규모의 복잡한 React 애플리케이션에서는 두 가지가 함께 사용될 수도 있습니다.</p>
<p>1️⃣ 페이지 기반 지연 로딩</p>
<p>특정 페이지로 이동할 때 해당 페이지의 컴포넌트를 지연 로딩하여 초기 로딩 속도를 향상시키는 경우가 많습니다.
예를 들어, 사용자가 특정 페이지에 접근했을 때 해당 페이지의 기능을 로드하도록 Lazy Loading을 적용할 수 있습니다.</p>
<br />

<p>2️⃣ 대규모 어플리케이션에서의 자동 일괄 처리</p>
<p>대규모 애플리케이션에서는 많은 수의 상태 업데이트가 발생할 수 있습니다. 이때 자동 일괄 처리를 통해 불필요한 렌더링을 최소화하고 성능을 향상시킬 수 있습니다.
여러 상태를 업데이트하는 경우, 일괄 처리를 통해 한 번의 렌더링만 발생하도록 할 수 있습니다.</p>
<br />

<p>3️⃣ 컴포넌트 기반 로딩</p>
<p>특정 컴포넌트가 사용자 상호작용에 의해 동적으로 로딩되어야 하는 경우가 있습니다.
이런 상황에서는 지연 로딩과 함께 해당 컴포넌트의 로딩 시점을 최적화하여 필요한 시점에만 로드할 수 있습니다.</p>
<br />

<p>4️⃣ 성능 최적화의 필요성</p>
<p>특히 모바일 환경이나 느린 네트워크 상황에서는 초기 로딩 속도와 성능 최적화에 대한 요구가 더 높아집니다.
Lazy Loading과 Batching은 이러한 상황에서 특히 유용하게 적용될 수 있습니다.</p>
<pre><code class="language-javascript">import React, { lazy, Suspense, useState } from &#39;react&#39;;

// Lazy Loading을 적용한 컴포넌트
const LazyComponent = lazy(() =&gt; import(&#39;./LazyComponent&#39;));

const App = () =&gt; {
  // 여러 상태 업데이트를 일괄 처리하기 위한 상태
  const [state1, setState1] = useState(&#39;&#39;);
  const [state2, setState2] = useState(&#39;&#39;);

  const handleClick = () =&gt; {
    // 여러 상태를 업데이트하고 일괄 처리됨
    setState1(&#39;New State 1&#39;);
    setState2(&#39;New State 2&#39;);
  };

  return (
    &lt;div&gt;
      &lt;h1&gt;Lazy Loading and Batching Example&lt;/h1&gt;

      {/* 지연 로딩된 컴포넌트를 Suspense로 감싸서 로딩 중에 표시할 내용 설정 */}
      &lt;Suspense fallback={&lt;div&gt;Loading...&lt;/div&gt;}&gt;
        {/* Lazy Loading된 컴포넌트 렌더링 */}
        &lt;LazyComponent /&gt;
      &lt;/Suspense&gt;

      &lt;button onClick={handleClick}&gt;Update States&lt;/button&gt;
      &lt;p&gt;State 1: {state1}&lt;/p&gt;
      &lt;p&gt;State 2: {state2}&lt;/p&gt;
    &lt;/div&gt;
  );
};

export default App;</code></pre>
<p>결과적으로 어떤 기술을 사용할지는 애플리케이션의 요구사항과 구조에 따라 다르며, 성능 최적화를 위해 두 기술을 조화롭게 사용하는 것이 중요할 것입니다.</p>
<br />
<hr />

<p><em>references.</em></p>
<p>officials&#39;
<a href="https://react.dev/blog/2022/03/29/react-v18">https://react.dev/blog/2022/03/29/react-v18</a>
<a href="https://react.dev/blog/2022/03/08/react-18-upgrade-guide#automatic-batching">https://react.dev/blog/2022/03/08/react-18-upgrade-guide#automatic-batching</a></p>
<p><a href="https://react.dev/reference/react/lazy#lazy">https://react.dev/reference/react/lazy#lazy</a>
<a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading">https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading</a></p>
<p>developer&#39;s 
<a href="https://nukw0n-dev.tistory.com/33">https://nukw0n-dev.tistory.com/33</a>
<a href="https://hwani.dev/react-automatic-batching/">https://hwani.dev/react-automatic-batching/</a>
<a href="https://velog.io/@rookieand/React-18%EC%97%90%EC%84%9C-%EC%B6%94%EA%B0%80%EB%90%9C-Auto-Batching-%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80">https://velog.io/@rookieand/React-18%EC%97%90%EC%84%9C-%EC%B6%94%EA%B0%80%EB%90%9C-Auto-Batching-%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</a></p>
<p><a href="https://hwani.dev/react-code-splitting/">https://hwani.dev/react-code-splitting/</a>
<a href="https://hwani.dev/react-real-code-splitting/">https://hwani.dev/react-real-code-splitting/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ React : 동작 가이드]]></title>
            <link>https://velog.io/@55555-jyeon/react-render-guide</link>
            <guid>https://velog.io/@55555-jyeon/react-render-guide</guid>
            <pubDate>Fri, 08 Mar 2024 21:54:13 GMT</pubDate>
            <description><![CDATA[<h6 id="본-게시글은-a-mostly-complete-guide-to-react-rendering-behavior-게시글을-바탕으로-씌여졌습니다">본 게시글은 A (Mostly) Complete Guide to React Rendering Behavior 게시글을 바탕으로 씌여졌습니다.</h6>
<br />

<h1 id="i-react의-개요와-필요성">I. React의 개요와 필요성</h1>
<p>React의 동작 가이드에 대해 알아보기에 앞서 왜 React를 사용해야 하는지에 대해 리액트의 렌더링 과정에 대해 간략히 짚고 넘어가보겠습니다.</p>
<br />

<h6 id="document-object-model">Document Object Model</h6>
<h4 id="dom">DOM</h4>
<p>DOM은 웹페이지에 대한 인터페이스로 브라우저가 웹페이지의 콘텐츠와 구조를 어떻게 보여줄 것인지에 대한 정보를 담고 있습니다.</p>
<h4 id="critical-rendering-path">Critical Rendering Path</h4>
<p>웹 브라우저의 동작 원리는 간략하게 정리하자면 아래와 같이 네 단계로 나눌 수 있습니다.</p>
<pre><code>① HTML은 DOM으로, CSS는 CSSOM으로 변환
② Render Tree 생성
③ Layout: Render Tree를 기반으로 요소 배치
④ Painting: 실제로 요소들을 화면에 그려내는 과정</code></pre><p>이 과정에서 DOM이 수정되면 전체 과정이 반복되며, 이때 발생하는 reflow와 repaint는 많은 연산을 필요로 하므로 성능에 영향을 미칩니다.</p>
<br />
<br />

<h3 id="🤷🏻♀️-why-react">🤷🏻‍♀️ Why React?</h3>
<p>위의 과정에서 DOM이 수정되면 브라우저는 전체 과정을 다시 수행해야 하며, 이때 발생하는 리플로우(reflow)와 리페인트(repaint)는 웹 성능에 부정적인 영향을 미칩니다. </p>
<p>이를 방지하기 위해 DOM 조작을 최소화해야 하는데, React는 개발자가 별도로 신경쓰지 않아도 DOM 업데이트를 효율적으로 관리하며 최소한의 렌더링만 수행할 수 있도록 도와줍니다.</p>
<br />
<hr />
<br />

<h1 id="ii-react의-아키텍처">II. React의 아키텍처</h1>
<h3 id="🥊-stack-vs-fiber">🥊 Stack vs Fiber</h3>
<p>React는 초기에는 Stack Reconciler 구조를 사용했으나, 대규모 애플리케이션에서 성능 이슈를 야기할 수 있었습니다. 이러한 재귀적으로 동작하는 재귀 호출 스택의 문제를 해결하기 위해 Fiber 아키텍처로 변경되었습니다.</p>
<br />

<pre><code>Stack Reconciler

모든 UI 업데이트를 한 번에 처리하므로, 
큰 작업이 메인 스레드를 오래 점유하게 됩니다.


Fiber Architecture

UI 업데이트를 작은 작업 단위로 나누어 처리하며, 
메인 스레드 점유 시간을 줄여 UI의 응답성을 향상시킵니다.</code></pre><br />

<h5 id="재귀적으로-동작하는-재귀-호출-스택">재귀적으로 동작하는 재귀 호출 스택?</h5>
<h6 id="재귀-함수-호출recursive-function-call">재귀 함수 호출(Recursive Function Call)</h6>
<p>재귀 함수는 자기 자신을 호출하는 함수입니다. 재귀 함수는 일반적으로 특정 조건이 만족될 때까지 계속 자신을 호출하며, 각 호출이 끝날 때마다 반환되는 것이 특징입니다.</p>
<h6 id="호출-스택call-stack">호출 스택(Call Stack)</h6>
<p>호출 스택은 프로그램이 함수 호출을 추적하는 데 사용하는 구조입니다. 
함수를 호출하면 그 함수의 정보가 스택에 추가되며, 함수가 종료되면 스택에서 제거됩니다. 스택은 LIFO(Last In, First Out) 구조이므로, 마지막에 호출된 함수가 가장 먼저 종료됩니다.</p>
<h6 id="재귀-호출-스택">재귀 호출 스택</h6>
<p>리액트의 초기 렌더링 알고리즘은 컴포넌트 트리를 순회하는 방식으로 동작했습니다. 
이 때 재귀 호출을 사용하여 부모 컴포넌트가 자식 컴포넌트를 렌더링하고, 자식 컴포넌트가 또 그 자식을 렌더링하는 방식으로 내려갑니다. 
이 과정에서 리액트는 재귀 호출 스택을 사용하여 각 컴포넌트의 렌더링 과정을 추적했습니다.</p>
<p>이러한 접근 방식은 작은 트리 구조에서는 잘 동작하지만, 컴포넌트 트리가 매우 깊거나 복잡해졌을 때 문제가 생기게 됩니다.</p>
<pre><code>① 스택 오버플로우
너무 깊은 재귀 호출은 호출 스택의 한계를 초과하여 스택 오버플로우를 발생시킴

② 비효율성
모든 작업이 한 번에 처리되기 때문에, 렌더링이 완료될 때까지 UI의 중단 불가
이러한 점은 대규모 애플리케이션에서 사용자 경험을 저하를 야기</code></pre><br />

<h5 id="fiber-아키텍처">Fiber 아키텍처</h5>
<p>이러한 문제를 해결하기 위해 리액트는 Fiber라는 새로운 구조를 도입했습니다.
Fiber는 재귀 호출을 사용하지 않고, 컴포넌트 트리의 각 노드를 순차적으로 탐색할 수 있도록 하여 작업을 작은 조각으로 나누어 처리합니다. 아키텍처의 변경으로 리액트는 더 복잡한 UI에서도 높은 성능을 유지할 수 있게 되었습니다.</p>
<br />

<h5 id="fiber-algorithm">Fiber Algorithm</h5>
<p>Fiber 알고리즘은 작업을 쪼개고 우선순위에 따라 효율적으로 스케줄링하는 방법을 정의하며, 이를 통해 리액트는 다음과 같은 기능을 제공합니다.</p>
<pre><code>1️⃣ 유연한 렌더링
렌더링 작업을 유연하게 관리하여 UI의 응답성을 높입니다.

2️⃣ 성능 최적화
작업을 작은 단위로 나누어 메인 스레드의 차단을 최소화합니다.

3️⃣ 비동기 작업 처리
비동기 작업을 효율적으로 처리하여 복잡한 애플리케이션에서도 성능을 유지합니다.</code></pre><br />
<hr />
<br />

<h1 id="iii-reconciler와-fiber">III. Reconciler와 Fiber</h1>
<h2 id="🧐-reconciler">🧐 Reconciler</h2>
<p>React의 Reconciler는 컴포넌트 트리를 탐색하여 어떤 자식 요소를 렌더링할지 결정하고, 가상 DOM과 실제 DOM을 비교해 최소한의 변경만 적용합니다. </p>
<p>이 과정을 재조정(Reconciliation)이라 하며, 성능을 최적화하고 불필요한 DOM 업데이트를 방지합니다.</p>
<pre><code>[Reconciler 단계]

1️⃣ Diffing 
- 이전 가상 DOM과 새로운 가상 DOM을 비교하여 변화된 부분을 찾는 단계 
- react는 이를 통해 변경된 요소만을 식별

2️⃣ Rendering
- 변화된 부분을 실제 DOM에 반영하는 단계
- react는 변경 사항을 최소화하여 성능을 최적화</code></pre><br />



<h4 id="stack-기반에서-fiber-기반으로-전환">Stack 기반에서 Fiber 기반으로 전환</h4>
<p>Stack 기반 Reconciler는 트리 전체를 한 번에 처리하므로 긴 작업을 중단할 수 없지만, Fiber Reconciler는 작업을 작은 단위로 나누어 처리하며 우선순위를 동적으로 관리할 수 있습니다. 이로 인해 사용자 인터페이스의 반응성을 유지할 수 있습니다.</p>
<ul>
<li><p><code>Abort</code>/<code>Stop</code>/<code>Restart</code>
  Fiber는 작업을 중단(abort)하거나 멈춤(stop)으로써 더 중요한 작업을 먼저 처리할 수 있습니다. 
  필요할 경우 중단된 작업을 다시 시작(restart)할 수 있습니다.</p>
</li>
<li><p>렌더링 우선순위 변경
  React는 작업의 우선순위를 동적으로 변경할 수 있으며, 이를 통해 사용자 인터페이스의 반응성을 유지합니다. 
  useTransition 훅이 이러한 기능을 활용하는 예입니다.</p>
</li>
</ul>
<br />

<h5 id="fiber의-작동-과정">Fiber의 작동 과정</h5>
<p>1️⃣ 단위 작업 분할</p>
<p>Time Slicing이라고도 하는 단위 작업 분할 과정은 렌더링 작업을 작은 단위로 나누어 처리하는 것을 말합니다. 나뉘어진 작은 작업 단위(chunk)들은 각각 독립적으로 실행되며, 단위 작업이 끝날 때마다 메인 스레드는 잠시 휴식 시간을 가집니다.</p>
<p>단위 작업 분할은 작은 단위로 나누어 일정한 시간을 두고 실행되며, UI가 반응성을 유지할 수 있도록 합니다. 따라서 이 방식은 긴 작업을 효율적으로 처리하면서도 사용자가 느끼는 지연을 최소화할 수 있도록 도와줍니다.</p>
<br />

<p>2️⃣ 작업 우선순위 관리</p>
<p>Fiber는 작업에 우선순위를 부여합니다. 
높은 우선순위 작업은 즉시 처리하고, 낮은 우선순위 작업은 나중으로 미룰 수 있습니다. 이렇게 작업을 관리함으로써 중요한 작업이 지연되지 않도록 할 수 있습니다.</p>
<pre><code>[우선순위 목록]

0    작업 없음 (작업 대기 중인 것이 없음)
1    동기적 우선순위 (제어된 텍스트 입력을 위한 동기적 부작용)
2    작업 우선순위 (현재 틱이 끝날 때 완료되어야 함)
3    애니메이션 우선순위 (다음 프레임 이전에 완료되어야 함)
4    높은 우선순위 (반응성을 느낄 수 있도록 빠르게 완료되어야 하는 상호작용)
5    낮은 우선순위 (데이터 가져오기 또는 스토어 업데이트 결과)
6    오프스크린 우선순위 (화면에 보이지 않지만 나중에 보일 가능성이 있어 작업 수행)</code></pre><br />

<p>3️⃣ 중단 및 재개</p>
<p>Fiber는 작업을 중단하고 나중에 재개할 수 있는 기능을 제공합니다. 
예를 들어, 애니메이션 프레임이 필요할 때 긴 렌더링 작업을 중단하고, 프레임이 끝난 후 작업을 재개할 수 있습니다.</p>
<br />
<hr />
<br />

<h2 id="🧩-fiber">🧩 Fiber</h2>
<h3 id="🌳-fiber-tree">🌳 Fiber Tree</h3>
<p>리액트에는 현재 상태를 나타내는 current tree와 작업 중인 workInProgress tree라는 두 개의 Fiber Tree가 존재합니다. 작업이 완료되면 React는 단순히 포인터를 변경해 workInProgress tree를 current tree로 바꾸는데, 이를 더블 버퍼링이라고 합니다.</p>
<pre><code>- Work-in-Progress: 현재 작업 중인 Fiber 트리
- Current: 현재 화면에 렌더링된 Fiber 트리
- Root Fiber: 트리의 루트 노드로, 보통 `ReactDOM.render`로 생성된 노드</code></pre><br />

<h4 id="1️⃣-current-dom">1️⃣ current DOM</h4>
<ul>
<li>DOM에 mount된 fiber</li>
</ul>
<p><code>npx create-react-app@latest</code>로 프로젝트 생성 후 파일을 살펴보면 id가 root인 element를 가져와 DOM의 root로 만드는 것을 확인할 수 있습니다.
아래가 바로 current tree를 만드는 코드입니다.</p>
<pre><code class="language-javascript">// 📂 src/index.tsx

const root = ReactDOM.createRoot(
    document.getElementById(&#39;root&#39;) as HTMLElement,
);
root.render(
    &lt;React.StrictMode&gt;
          &lt;App /&gt;
    &lt;/React.StrictMode&gt;
)</code></pre>
<pre><code class="language-html">// 📂 index.html
&lt;body&gt;
    &lt;noscript&gt; ... &lt;/noscript&gt;
    &lt;div id=&quot;root&quot;&gt;&lt;/div&gt; ✅
&lt;/body&gt;</code></pre>
<br />

<h4 id="2️⃣-workinprogress-dom">2️⃣ workInProgress DOM</h4>
<ul>
<li>render phase에서 작업 중인 fiber</li>
<li>commit phase를 지나면서 current tree가 되고, 자기 복제 후 new workInProgress가 재생성됨</li>
</ul>
<br />

<blockquote>
<p>📌 정리 <br />
컴포넌트를 호출 → react element를 반환(return) → 반환 값이 fiberNode로 확장 → 그 결과가 VDOM에 반영</p>
</blockquote>
<blockquote>
<p> 💡 <strong>component rendering</strong>  <br />
렌더링 과정 후 DOM에 mount되어 페인트(paint)가 되는 과정은 렌더링되지 않습니다.</p>
</blockquote>
<br />
<br />


<h3 id="🎪-fiber-nodes">🎪 Fiber Nodes</h3>
<p>Fiber Nodes는 컴포넌트의 상태, props, 렌더 결과 등을 저장하며, 컴포넌트 트리의 각 요소를 나타냅니다. 이를 통해 컴포넌트 트리의 변화를 효율적으로 관리할 수 있습니다.</p>
<br />

<h5 id="fiber-node-구조">Fiber Node 구조</h5>
<ul>
<li><code>type</code> :컴포넌트 타입 (함수, 클래스, 호스트 컴포넌트 등)</li>
<li><code>stateNode</code> : 컴포넌트 인스턴스 또는 DOM 노드</li>
<li><code>return</code> : 부모 Fiber 노드</li>
<li><code>child</code> : 첫 번째 자식 Fiber 노드</li>
<li><code>sibling</code> : 형제 Fiber 노드</li>
</ul>
<br />


<h4 id="⚙️-usetransition">⚙️ useTransition</h4>
<p>Fiber 아키텍처는 React 18에서 도입된 useTransition 훅을 통해 비동기 작업을 처리하고 우선순위를 낮출 수 있습니다. 이를 통해 UI의 응답성을 유지하면서도 백그라운드에서 상태 업데이트를 수행할 수 있습니다.</p>
<pre><code class="language-javascript">import React, { useState, useTransition } from &#39;react&#39;;

function MyComponent() {
  const [isPending, startTransition] = useTransition();
  const [count, setCount] = useState(0);

  const handleClick = () =&gt; {
    startTransition(() =&gt; {
      setCount(prevCount =&gt; prevCount + 1);
    });
  };

  return (
    &lt;div&gt;
      &lt;button onClick={handleClick}&gt;
        Increment
      &lt;/button&gt;
      {isPending ? &lt;p&gt;Loading...&lt;/p&gt; : &lt;p&gt;Count: {count}&lt;/p&gt;}
    &lt;/div&gt;
  );
}</code></pre>
<br />
<br />

<h3 id="🔗-metadata--fiber">🔗 metaData &amp; Fiber</h3>
<p>Fiber 객체는 현재 렌더링되는 컴포넌트의 유형, 현재 Props와 State, 부모, 형제, 자식 컴포넌트에 대한 포인터, 그리고 렌더링 추적을 위한 메타데이터를 포함합니다. 이 구조를 통해 React는 컴포넌트를 효율적으로 렌더링하고 업데이트할 수 있습니다.</p>
<br />

<p>Render Pass 동안 React는 fiber tree를 순회하며 새로운 렌더링 결과물을 계산하여 업데이트된 트리를 생성합니다. Fiber 객체들은 컴포넌트의 실제 Props와 State 값을 저장하며, React는 이러한 값을 이용해 렌더링을 수행합니다. 다만, React는 값을 &quot;복제하여&quot; 사용하는 것이 아니라, fiber tree에 저장된 값을 기반으로 새로운 상태나 props를 계산하고 이를 렌더링하는 과정에서 활용합니다.</p>
<br />

<p>React Hook이 동작하는 이유는 React가 각 컴포넌트에서 사용되는 모든 hook들을 컴포넌트의 fiber와 연결된 <strong>연결 리스트(Linked List)</strong>로 관리하기 때문입니다. React는 함수형 컴포넌트를 렌더링할 때 해당 컴포넌트의 fiber에서 이 리스트를 참조하여 hook의 상태를 관리하고 업데이트합니다.</p>
<br />
부모 컴포넌트가 자식 컴포넌트를 처음으로 렌더링할 때, React는 자식 컴포넌트의 인스턴스를 추적하기 위해 fiber 객체를 생성합니다.

<pre><code>1️⃣ 클래스형 컴포넌트

    const instance = new YourComponentType(props) 호출
    실제 컴포넌트 인스턴스를 fiber에 저장

2️⃣ 함수형 컴포넌트

    YourComponentType(props)를 함수로 호출</code></pre><br />


<blockquote>
<p>💡 <strong>Linked List</strong> <br />
<img src="https://velog.velcdn.com/images/55555-jyeon/post/25555409-ee1d-4d00-97d4-79598c39c53c/image.png" alt="">
node 안에 node.next 값이 다음 node를 가리키고 있습니다.
다음 node를 할당해 놓는다고도 할 수 있습니다. <br />
즉, next라는 값으로 다음 node를 연결한 목록을 linked list라고 합니다.</p>
</blockquote>
<br />
<hr />
<br />


<h1 id="iv-react의-주요한-개념">IV. React의 주요한 개념</h1>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/33ee1dd0-743b-437e-b301-a336adde056e/image.png" alt=""></p>
<p>React는 가상 DOM을 관리하며, Fiber 아키텍처를 통해 효율적인 렌더링을 수행합니다. 이를 통해 개발자는 복잡한 UI를 쉽게 관리하고 성능 최적화를 수행할 수 있습니다.</p>
<br />

<p>간략하게 리액트에서 주요한 패키지와 용어들을 정리하자면 아래와 같습니다.</p>
<br />

<h3 id="🎁-package">🎁 Package</h3>
<h5 id="react-core">react core</h5>
<ul>
<li>component 정의</li>
<li>다른 패키지에 의존하지 않으므로 다양한 플랫폼에 렌더 가능</li>
</ul>
<h5 id="renderer">renderer</h5>
<ul>
<li>호스트와 리액트를 연결하는 역할</li>
<li>의존 : 호스트 렌더링 환경, reconciler, legacy-events</li>
<li>호스트 렌더링 환경 예시 → react-dom, react-native-renderer</li>
</ul>
<h5 id="event-legacy-events">event (legacy-events)</h5>
<ul>
<li>react 내부적으로 개발된 이벤트 시스템으로 <strong>SyntheticEvent</strong>라고도 함</li>
<li>react 내부적으로 이벤트를 사용하는데 추가적인 기능(기존 웹의 event를 wrap)이 필요했고 이를 수행할 수 있도록 하기 위해 개발된 패키지</li>
</ul>
<blockquote>
<p>❓ <a href="https://legacy.reactjs.org/docs/events.html">event에 대한 더 자세한 내용 공식 문서에서 확인하기</a></p>
</blockquote>
<h5 id="scheduler">scheduler</h5>
<ul>
<li>react는 task를 비동기로 실행</li>
<li>각 task의 실행 타이밍을 관리하는(알고 있는) 패키지</li>
</ul>
<h5 id="reconciler">reconciler</h5>
<ul>
<li>fiber 아키텍처에서 VDOM을 재조정하는 역할 ⭐️</li>
<li>컴포넌트를 렌더링하는 공간</li>
</ul>
<br />

<h3 id="📖-term">📖 Term</h3>
<h5 id="rendering">rendering</h5>
<ul>
<li>컴포넌트를 호출해 react element를 반환하고 이를 토대로 VDOM 재조정</li>
</ul>
<h5 id="react-element">react element</h5>
<ul>
<li>컴포넌트 호출 시 return하는 값 </li>
<li>JSX → babel을 통해 <code>react.createElement</code> 함수로 호출</li>
<li>컴포넌트의 정보를 담은 객체</li>
</ul>
<h5 id="fiber">fiber</h5>
<ul>
<li>VDOM의 노드 객체</li>
<li>아키텍처와 이름 같으나 다름</li>
<li>react element가 DOM에 반영되기 위해 VDOM에 추가되는 과정에서 필요한 추가 정보를 제공하기 위해 확장한 객체 ⭐️</li>
<li>추가 정보의 종류 : 컴포넌트의 상태, life cycle, hook 등</li>
</ul>
<br />
<hr />
<br />


<h1 id="v-react의-렌더링-과정">V. React의 렌더링 과정</h1>
<h2 id="🎨-react의-렌더링">🎨 React의 렌더링</h2>
<h5 id="브라우저의-렌더링과-react의-렌더링">브라우저의 렌더링과 react의 렌더링</h5>
<p>브라우저에서의 렌더링이란 간단히 말하자면 HTML과 CSS 리소스를 기반으로 웹페이지에 필요한 UI를 그려내는 과정을 의미합니다.</p>
<p>리액트의 렌더링은 브라우저가 렌더링에 필요한 DOM 트리를 만드는 과정을 의미합니다. 리액트도 브라우저와 마찬가지로 이 렌더링 작업을 위한 자체적인 렌더링 프로세스가 있습니다.</p>
<p>그리고 프론트엔드 개발자는 최적화를 위해 이러한 렌더링 프로세스를 이해하고 과정을 최소화할 수 있도록 노력해야 합니다. 리액트에서 렌더링은 시간과 리소스를 소비해 수행되는 과정으로, 이 비용은 모두 웹 애플리케이션을 방문하는 사용자에게 청구되기 때문입니다. 
즉, 시간이 길어지고 과정이 복잡해질수록 사용자 경험(UX)은 저해될 수 있습니다.</p>
<p><strong>react의 렌더링은</strong> 정리하자면, 리액트 애플리케이션 트리 안에 있는 모든 컴포넌트들이 현재 자신들이 갖고 있는 props와 state의 값을 기반으로 어떻게 UI를 구성하고 이를 바탕으로 <strong>어떤 DOM 결과를 브라우저에 제공할 것인지 계산</strong>하는 일련의 과정을 의미합니다.</p>
<br />
<br />


<h2 id="렌더링-발생-시점">렌더링 발생 시점</h2>
<p>렌더링은 최초의 렌더링과 리렌더링(re-rendering)으로 나눌 수 있습니다.
최초의 렌더링은 사용자가 처음 애플리케이션에 진입했을 때 결과물을 보여주기 위한 과정입니다. 리액트는 브라우저에 결과물에 대한 정보를 제공하기 위해 최초 렌더링을 수행합니다.</p>
<p>리렌더링은 처음 애플리케이션에 진입했을 때 최초 렌더링이 발생한 이후에 발생하는 모든 렌더링을 지칭합니다. 리렌더링이 발생하는 경우는 아래와 같습니다 :</p>
<br />

<h5 id="re-rendering이-일어나는-경우">re-rendering이 일어나는 경우</h5>
<p>리액트에서 리렌더링이 발생하는 경우는 아래 7가지 상황 뿐입니다.
아래 상황에 해당하지 않는다면 어떤 경우라도 리렌더링이 일어나지 않기 때문에 변경된 값을 DOM에서 확인할 수 없습니다.</p>
<pre><code>1️⃣ 클래스 컴포넌트의 setState가 실행되는 경우

2️⃣ 클래스 컴포넌트의 forceUpdate가 실행되는 경우

3️⃣ 함수 컴포넌트의 useState의 두 번째 배열 요소인 setter가 실행되는 경우

4️⃣ 함수 컴포넌트의 useReducer의 두 번째 배열 요소인 dispatch가 실행되는 경우

5️⃣ 컴포넌트의 key props가 변경되는 경우

6️⃣ props가 변경되는 경우

7️⃣ 부모 컴포넌트가 렌더링될 경우</code></pre><br />
<br />

<h5 id="react의-렌더링-프로세스-재조정reconciliation">React의 렌더링 프로세스, 재조정(reconciliation)</h5>
<p>렌더링 프로세스가 시작되면 react는 컴포넌트의 루트(root)에서부터 위에서 아래 방향으로 내려가며 업데이트가 필요하다고 저장돼 있는 모든 컴포넌트를 찾습니다.</p>
<p>만약 여기서 업데이트가 필요하다고 지정돼 있는 컴포넌트를 발견하면
클래스 컴포넌트의 경우에는 클래스 내부의 <code>render()</code> 함수를 실행하게 되고, 
함수 컴포넌트의 경우에는 <code>FunctionComponent()</code> 자체를 호출한 뒤 결과물을 저장합니다.</p>
<p>이런 과정들을 거치며 각 컴포넌트의 렌더링 결과물을 수집한 다음, 리액트의 새로운 트리인 가상 DOM과 비교해 실제 DOM에 반영하기 위한 모든 변경 사항을 차례차례 수집합니다.</p>
<p>위의 일련의 과정을 리액트에서는 재조정(reconciliation)이라고 하며 과정이 모두 끝나면 모든 변경 사항을 하나의 동기 시퀸스(sequence)로 DOM에 적용해 변경된 결과물을 사용자에게 보여줄 수 있게 됩니다.</p>
<br />

<h6 id="vdom-가상-dom">(VDOM, 가상 DOM)</h6>
<h2 id="👭-virtual-dom">👭 Virtual DOM</h2>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/2ead07a3-8edd-4470-b884-f9515549529d/image.png" alt=""></p>
<p>VDOM은 메모리 상에 가상의 UI 관련 정보를 띄우고 라이브러리를 활용해 실제 DOM과 동기화되는 (재조정(reconciliation)) 프로그래밍 개념입니다.</p>
<p>굳이 가상으로 진행하는 이유는 실제로 <strong>mount를 paint할 경우 비용</strong>이 가상보다 <strong>많이 들기 때문</strong>입니다.</p>
<br />


<h2 id="🗄️-렌더링-단계">🗄️ 렌더링 단계</h2>
<p>리액트의 렌더링 단계는 렌더 단계(render phase)와 커밋 단계(commit phase)로 나눌 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/3173cf07-1d22-42c2-8534-898533d5b7fe/image.png" alt=""></p>
<h6 id="vdom-재조정reconciliation하는-단계">VDOM 재조정(reconciliation)하는 단계</h6>
<h3 id="✏️-render-phase">✏️ render phase</h3>
<p>렌더 단계(render phase)는 컴포넌트 트리가 어떻게 변경될지 결정하는 단계입니다. 
이 단계에서는 React가 새로운 UI 상태를 계산하고, 이를 위해 어떤 변화가 필요한지 알아냅니다. 실제 DOM을 변경하지 않으며, 이를 통해 변경이 필요한 요소들을 결정합니다. </p>
<p>여기에서 비교하는 것은 <strong>type, props, key</strong> 크게 세 가지입니다.
이 중 하나라도 변경된 것이 있다면 변경이 필요한 컴포넌트로 체크해 둡니다.</p>
<br />

<h4 id="과정">과정</h4>
<p>1️⃣ 재조정을 위해 Work를 scheduler에 등록</p>
<ul>
<li><p>Work 등록
React는 재조정(reconciliation) 작업을 위해 할 일(work)을 스케줄러에 등록합니다. 이는 React가 컴포넌트 트리를 순회하며 어떤 변경이 필요한지 확인하는 작업을 말합니다.</p>
</li>
<li><p>Scheduler
스케줄러는 작업의 우선순위를 관리하고, 긴 작업을 여러 프레임에 나누어 처리할 수 있도록 합니다. 이를 통해 React는 더 중요한 작업이 발생했을 때 즉시 대응할 수 있습니다.</p>
</li>
</ul>
<blockquote>
<p>❓ Work
Work란 reconciler가 컴포넌트 변경을 DOM에 적용하기 위해 수행하는 일을 뜻합니다.</p>
</blockquote>
<br />

<p>2️⃣ element 추가/수정/삭제 </p>
<ul>
<li><p>변경 사항 확인
스케줄러에 등록된 작업은 컴포넌트 트리를 순회하면서 각 컴포넌트의 상태와 요소의 변화를 확인합니다.</p>
</li>
<li><p>가상 DOM 업데이트
React는 가상 DOM(Virtual DOM)을 사용하여 변경된 요소를 추적하고, 이를 통해 어떤 요소가 추가되거나 수정되었는지, 삭제되어야 하는지를 기록합니다.</p>
</li>
<li><p>Fiber Nodes
각 컴포넌트와 그 자식 요소들은 Fiber 노드로 표현되며, 이러한 노드들이 트리 형태로 구성됩니다. Fiber 노드는 이전 렌더링과 새로운 렌더링을 비교하여 차이점을 기록합니다.</p>
</li>
</ul>
<br />

<p>3️⃣ reconciler가 담당</p>
<ul>
<li>Reconciler
Reconciler는 렌더 단계에서 가장 중요한 역할을 담당합니다. Reconciler는 컴포넌트 트리의 변화를 확인하고, 이를 기반으로 새로운 UI 상태를 계산합니다.</li>
</ul>
<br />




<br />

<h4 id="특징">특징</h4>
<p>1️⃣ 순수 계산</p>
<p>렌더 단계에서는 실제로 DOM을 변경하지 않습니다. 대신, 변경해야 할 사항을 계산합니다.</p>
<br />

<p>2️⃣ 비동기 가능</p>
<p>이 단계는 비동기적으로 실행될 수 있으며, 필요한 경우 작업을 중단하고 나중에 재개할 수 있습니다. 이는 React Fiber 아키텍처 덕분에 가능해졌습니다.</p>
<br />

<p>3️⃣ 부수 효과 없음</p>
<p>이 단계에서는 DOM에 접근하거나 변경하지 않으며, 부수 효과를 일으키지 않습니다. 따라서 이 단계는 순수 함수처럼 동작합니다.</p>
<br />

<p>4️⃣ 중간 상태 저장</p>
<p>Fiber는 렌더링 과정에서 각 컴포넌트의 중간 상태를 저장하고, 이를 기반으로 최종 결과를 계산합니다.</p>
<br />
<br />


<h6 id="재조정한-vdom을-dom에-적용--lifecycle을-실행하는-단계">재조정한 VDOM을 DOM에 적용 + lifeCycle을 실행하는 단계</h6>
<h3 id="📤-commit-phase">📤 commit phase</h3>
<p>커밋 단계는 렌더 단계에서 계산된 변경 사항을 실제 DOM에 적용하는 단계입니다. 이 단계에서 React는 변경된 내용을 DOM에 반영하고, 필요한 경우 부수 효과
(side effects)를 실행합니다.</p>
<h4 id="특징-1">특징</h4>
<p>1️⃣ 동기 실행</p>
<p>커밋 단계는 일관성을 위해 sync(동기적)로 실행됩니다. 
이 단계에서는 모든 작업이 한 번에 완료되어야 하기 때문에 중간에 중단될 수 없습니다. 따라서 DOM 조작 일괄처리 후 react가 callstack을 비워준 다음 browser가 paint를 시작하게 됩니다.</p>
<br />

<p>2️⃣ 부수 효과 실행</p>
<p>이 단계에서는 DOM 업데이트뿐만 아니라 <code>componentDidMount</code>, <code>componentDidUpdate</code>, <code>useEffect</code> 등과 같은 부수 효과도 실행됩니다.</p>
<br />

<p>3️⃣ DOM 업데이트</p>
<p>커밋 단계에서는 렌더 단계에서 계산된 변경 사항을 실제 DOM에 적용합니다.</p>
<br/>
<br />

<h5 id="📌-정리">📌 정리</h5>
<p>커밋 단계(commit phase)가 끝나야 비로소 브라우저의 렌더링이 발생하게 됩니다.</p>
<p>리액트가 먼저 DOM을 커밋 단계에서 업데이트한다면 이렇게 만들어진 모든 DOM node 및 인스턴스(instance)를 가리키도록 리액트 내부의 참조를 업데이트합니다.</p>
<p>그 다음, 생명주기 개념이 있는 클래스 컴포넌트에서는 <code>componentDidMount</code>, <code>componentDidUpdate</code> 메서드를 호출하고 함수 컴포넌트에서는 <code>useLayoutEffect</code> 훅을 호출합니다.    </p>
<p>여기에서 알 수 있는 사실 중 하나는 리액트의 렌더링이 일어난다고 해서 무조건 DOM 업데이트가 발생하는 것은 아니라는 겁니다.</p>
<p>레더링을 수행했으나 커밋 단계까지 갈 필요가 없다면, 즉 변경 사항을 계산했는데 변경 사항이 감지되지 않는다면 이 커밋 단계는 생략될 수 있기 때문입니다.</p>
<p>리액트의 렌더링은 꼭 가시적인 변경이 일어나지 않아도 발생할 수 있습니다.
그리고 렌더링 과정 중 첫 번째 단계인 렌더 단계에서 변경 사항을 감지할 수 없다면 커밋 단계가 생략되어 브라우저의 DOM 업데이트가 일어나지 않을 수 있습니다.</p>
<br />
<hr />
<br />

<h2 id="📋-react의-렌더링-기준">📋 React의 렌더링 기준</h2>
<blockquote>
<p>⭐️ <strong>React의 렌더링 기준</strong> <br />
React는 기본적으로 부모 컴포넌트가 렌더링되면, 
그 안에 있는 모든 자식 컴포넌트를 재귀적으로 렌더링합니다.</p>
</blockquote>
<br />

<h5 id="example">example</h5>
<p>아래와 같은 component tree를 예시로 들어보겠습니다.</p>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/58ca4f2e-c84a-4e1d-80ce-2e03331d7e70/image.svg" alt=""></p>
<p>B 컴포넌트 안에는 버튼이 하나 있는데, 누르면 숫자가 1 증가합니다. 
유저가 이 버튼을 한번 클릭하게 됐을 때 어떻게 동작하게 될까요?</p>
<br />

<p>이미 페이지에 보여지고 있는 상황이라고 가정했을 때 아래와 같은 순서로 동작하게 됩니다. </p>
<p>1️⃣ <code>&lt;B /&gt;</code> 
setState()가 호출되어 B의 리렌더링이 큐(Queue)에 들어갑니다.</p>
<p>2️⃣ <code>React</code>
tree의 최상단부터 렌더 패스(Render Pass)를 시작합니다.</p>
<p>3️⃣ <code>&lt;A /&gt;</code> 
update inneed mark <strong>X</strong>
업데이트가 필요하다는 마크가 없는 것을 확인 후 pass 합니다.</p>
<p>4️⃣ <code>&lt;B /&gt;</code> 
React는 B에 업데이트가 필요하다는 마크가 있는 것을 보고 렌더링합니다. 
B return C </p>
<p>5️⃣ <code>&lt;C /&gt;</code>
update inneed mark <strong>X</strong>
하지만 B의 child이기 때문에 C는 렌더링됩니다. 
C return D </p>
<p>6️⃣ <code>&lt;D /&gt;</code>
update inneed mark <strong>X</strong>
하지만 C의 child이기 때문에 D는 렌더링됩니다.</p>
<br />

<p>일반적으로 컴포넌트가 렌더링되면 그 안에 있는 모든 컴포넌트 역시 렌더링 됩니다. 
또한 일반적인 렌더링 과정에서, React는 <strong>Props의 변경 유무</strong>는 신경쓰지 않습니다. 
렌더링의 기준은 그저 <strong>부모 컴포넌트가 렌더링되었는가</strong> 뿐입니다.</p>
<p>나아가 이는 <code>&lt;App&gt;</code> 컴포넌트에서 setState()를 호출하면 컴포넌트 트리 안에 있는 모든 컴포넌트가 렌더링된다는 것을 의미합니다. 결과적으로 React는 매번 업데이트를 할 때마다 어플리케이션 전체를 다시 그리는 것처럼 동작한다고 볼 수 있습니다.</p>
<br />

<blockquote>
<p>💡 <strong>React&#39;s Render Rules</strong> <br />
제일 핵심적인 규칙 중 하나는 바로 렌더링은 <strong>순수</strong>해야만 하며 <strong>부수 효과를 만들어내서는 안된다</strong>는 것입니다.</p>
</blockquote>
<blockquote>
<p>❓ <a href="https://gist.github.com/sebmarkbage/75f0838967cd003cd7f9ab938eb1958f">React의 렌더링 규칙에 대한 더 자세한 설명 보러 가기</a></p>
</blockquote>
<br />
<br />

<h2 id="📚-렌더링-순서">📚 렌더링 순서</h2>
<p>최초의 렌더가 끝난 이후, React가 리렌더링을 Queue에 넣도록 하는 방법은 여러가지가 있습니다.</p>
<p>1️⃣ 클래스형 컴포넌트</p>
<pre><code>this.setState()
this.forceUpdate()</code></pre><p>2️⃣ 함수형 컴포넌트</p>
<pre><code>useState setters
useReducer dispatches</code></pre><p>3️⃣ 그 외</p>
<pre><code>ReactDOM.render(&lt;App&gt;) 을 다시 호출
루트 컴포넌트에서 forceUpdate()를 호출하는 것과 동일</code></pre><br />
<hr />
<br />


<h1 id="vi-렌더링-최적화">VI. 렌더링 최적화</h1>
<p>React는 컴포넌트 렌더링을 생략할 수 있도록 3개의 API를 제공하며 모두 <strong>얕은 비교</strong> 기법을 사용합니다. JS 엔진 입장에서 얕은 비교는 일치 비교(===)에 비해 매우 심플한 동작이기 때문에 빠른 작업으로 분류됩니다.</p>
<p>즉, <code>const shouldRender = !shallowEqual(newProps, prevProps)</code> 와 같은 방법론을 사용하고 있다고 볼 수 있습니다.</p>
<blockquote>
<p>💡 <strong>얕은 비교</strong> <br />
얕은 비교란 서로 다른 2개 객체를 각각 모두 조사해서 <strong>내용물 중에 차이가 있는지 여부를 검사</strong>하는 것입니다.</p>
</blockquote>
<br />
<br />

<h3 id="1️⃣-불필요한-렌더링-방지">1️⃣ 불필요한 렌더링 방지</h3>
<br />

<h5 id="①-reactcomponentshouldcomponentupdate">① <code>React.Component.shouldComponentUpdate</code></h5>
<pre><code>    - Optional 클래스 컴포넌트의 라이프사이클 메소드
    - 렌더링 과정 초반에 호출
    - if return false, pass component render 
    - 컴포넌트의 props와 state가 마지막에 변경 여부 검사 가능</code></pre><blockquote>
<p>❓ <a href="https://legacy.reactjs.org/docs/react-component.html#shouldcomponentupdate">공식문서에서 더 자세한 내용 보기</a></p>
</blockquote>
<br />

<h5 id="②-reactpurecomponent">② <code>React.PureComponent</code></h5>
<pre><code>- shouldComponentUpdate의 가장 일반적인 사용법은 props와 state의 업데이트 여부를 검사
- PureComponent의 클래스 컴포넌트는 shouldComponentUpdate 메소드를 기본적으로 탑재
- Component + shouldComponentUpdate와 동일</code></pre><blockquote>
<p>❓ <a href="https://legacy.reactjs.org/docs/react-api.html#reactpurecomponent">공식문서에서 더 자세한 내용 보기</a></p>
</blockquote>
<br />

<h5 id="③-reactmemo">③ <code>React.memo()</code></h5>
<pre><code>- React에 내장된 &quot;고차 컴포넌트 (Higher Order Component)&quot; 
- 컴포넌트 타입을 인수로 받고, 새로운 Wrapper 컴포넌트를 반환
- Wrapper 컴포넌트의 기본 동작: Props 변경 유무 확인
- if false, prevent re-rendering
- 함수형 컴포넌트와 클래스형 컴포넌트 모두 사용 가능</code></pre><blockquote>
<p>❓ <a href="https://legacy.reactjs.org/docs/react-api.html#reactmemo">공식문서에서 더 자세한 내용 보기</a></p>
</blockquote>
<br />

<h5 id="④-props-reference">④ props reference</h5>
<p>⑴ 클래스형 컴포넌트</p>
<p>항상 동일한 참조 갖고 있는 인스턴스 메소드를 가질 수 있기 때문에 새로운 콜백 함수 참조를 실수로 생성하는 일을 걱정할 필요가 없습니다.</p>
<p>하지만 상황에 따라 새로운 참조가 생성될 수 있습니다. 하지만 React는 이러한 케이스를 최적화하기 위한 수단을 갖고 있지 않습니다.</p>
<blockquote>
<p>💡 새로운 참조가 생성될 수 있는 특수 상황이란? <br />
① 여러 개의 자식들에게 각각 다른 고유한 콜백 함수를 생성해서 적용할 필요가 있거나
② 익명 함수에서 값을 가져와서 자식에게 넘겨줄 필요가 있거나</p>
</blockquote>
<br />

<p>⑵ 함수형 컴포넌트</p>
<p>같은 참조를 재사용하기 위한 Hook을 2개 제공(메모이제이션)</p>
<pre><code>- useMemo : 객체 생성 또는 복잡한 연산과 관련된 일반적인 데이터를 다루는 경우
- useCallback : 새로운 콜백 함수를 생성하는 경우</code></pre><br />
<br />

<h3 id="2️⃣-memoization">2️⃣ Memoization</h3>
<p>메모이제이션은 값비싼 함수 호출의 <strong>결과를 캐싱</strong>하고 동일한 입력이 다시 발생했을 때 캐싱된 결과를 반환하는 프로그래밍 기술입니다.</p>
<p>동일한 입력으로 여러 번 호출되는 함수, 컴포넌트에 주로 사용되며 React에서는 useCallback, useMemo와 같은 memoization hook을 사용해 성능을 향상시킴과 동시에 코드의 복잡성을 줄일 수 있습니다.</p>
<p>하지만 메모이제이션은 메모리에 특정한 값을 저장하기 때문에 <strong>남용 시 오히려 성능을 저하</strong>시킬 수 있습니다.</p>
<h4 id="functional-programming">functional programming</h4>
<h6 id="함수형-프로그래밍은-동일한-입력에-대해-동일한-출력을-생성하고-부작용이-없는-함수순수-함수의-사용을-강조하는-프로그래밍">함수형 프로그래밍은 동일한 입력에 대해 동일한 출력을 생성하고 부작용이 없는 함수(순수 함수)의 사용을 강조하는 프로그래밍</h6>
<p>메모이제이션은 함수형 프로그래밍과 밀접한 관련이 있습니다. 주로 순수 함수의 실행 최적화를 위해 함수형 프로그래밍에서 일반적으로 사용되기 때문입니다.</p>
<p>메모이제이션은 캐싱된 결과 반환 시 부작용이나 변경 가능한 상태를 고려하지 않기 때문에 함수형 프로그래밍의 원칙과 부합한다고 볼 수 있습니다.
즉, 메모이제이션은 순수 함수 호출을 최적화하고 중복 계산을 줄이며 성능을 향상시키는 방법을 제공함으로써 함수형 프로그래밍 패러다임을 보완하는 강력한 기술 중 하나로 볼 수 있습니다.</p>
<blockquote>
<p>🤔 React는 왜 기본적으로 React.memo()로 모든걸 감싸지 않는걸까?</p>
</blockquote>
<p>모든 컴포넌트를 자동으로 <code>React.memo()</code>로 감싸는 것이 항상 옳은 방법이 되지 않을 수 있습니다. 렌더링이 빈번하지 않거나 컴포넌트 자체가 간단하거나, 부모 컴포넌트에서의 리렌더링이 거의 없는 경우에는 이러한 최적화가 불필요할 수 있습니다.</p>
<p>또한, <code>React.memo()</code>를 사용하면 컴포넌트가 props의 얕은 비교(shallow comparison)를 통해 업데이트 여부를 결정하므로, props 내부의 객체나 함수 등이 자주 변경되는 경우에는 주의가 필요합니다. 이 경우에는 적절한 최적화를 고려해야 합니다.</p>
<p>각 컴포넌트에 대해 최적한 성능 최적화를 적용하는 것이 중요하며 무조건적으로 감싸는 것은 오히려 성능 저하를 야기할 수 있습니다.</p>
<blockquote>
<p>🔥 <strong>React Issue</strong> 
 <a href="https://github.com/facebook/react/issues/14463">React.memo를 언제 사용하지 말아야될까?</a></p>
</blockquote>
<br />
<br />

<h6 id="immutable-and-re-rendering">immutable and re-rendering</h6>
<h3 id="3️⃣-불변성과--리렌더링">3️⃣ 불변성과  리렌더링</h3>
<p>React에서 상태 업데이트는 항상 불변성을 지켜야 하는 이유는 무엇일까요?</p>
<pre><code>- 수정한 내용을 또 어디서 수정하느냐에 따라서, 컴포넌트가 개발자의 의도대로 렌더링되지 않을 수 있습니다.
- 데이터가 언제 그리고 왜 업데이트 되었는지를 파악하기 어려울 수 있습니다.</code></pre><p>조금 더 자세히 알아보자면 : </p>
<p>1️⃣ <strong>성능 최적화</strong></p>
<p>React는 상태 불변성을 유지할 때 효과적으로 리렌더링을 최적화할 수 있습니다. 불변한 상태로 업데이트하면 React는 새로운 객체가 이전 상태와 다르다는 것을 쉽게 감지할 수 있게 되고 결과적으로 변경된 부분만 업데이트를 진행해 불필요한 렌더링을 방지할 수 있습니다.</p>
<p>2️⃣ <strong>참조 동등성</strong>(Reference Equality)</p>
<p>React는 상태를 업데이트할 때 이전 상태와 새로운 상태의 참조 동등성을 비교합니다. 만약 상태가 불변하지 않고 같은 참조를 가진다면 React는 변경되지 않은 것으로 간주하여 리렌더링이 발생하지 않게 됩니다.</p>
<p>3️⃣ <strong>컴포넌트 생명주기 메서드 최적화</strong></p>
<p>React의 PureComponent나 shouldComponentUpdate 메서드를 사용하여 성능을 최적화할 때, 불변한 상태를 사용하면 이전 상태와의 비교가 간편해집니다. 이를 통해 렌더링 필요 여부를 효과적으로 결정할 수 있습니다.</p>
<p>5️⃣ <strong>예측 가능한 상태 변화</strong></p>
<p>불변한 상태를 유지하면 상태의 변경이 항상 새로운 상태로 이어지며, 이로써 코드의 예측 가능성이 높아집니다. 변화가 예측 가능하면 디버깅이 쉬워지고 코드 유지보수가 간편해집니다.</p>
<p>6️⃣ <strong>Undo/Redo와 같은 기능 구현 용이</strong></p>
<p>이전 상태를 변경하지 않고 복제하여 새로운 상태를 만들 수 있기 때문에 불변한 상태를 사용하면 이전 상태를 보존하거나 롤백하는 등의 작업이 더 쉬워집니다.</p>
<p>React에서는 상태 업데이트 시 불변성을 지키기 위해 주로 spread 연산자나 불변성을 유지하는 라이브러리(<code>Immutable.js</code>)가 활용되곤 합니다.</p>
<br />

<h3 id="4️⃣-이벤트-처리-최적화">4️⃣ 이벤트 처리 최적화</h3>
<h5 id="①-debounce">① Debounce</h5>
<p>Debounce는 사용자가 연속적으로 발생시키는 이벤트를 제어하는 기법입니다. </p>
<p>예를 들어, 사용자가 입력 필드에 빠르게 타이핑할 때, 입력이 끝난 후 일정 시간이 지나기 전까지 이벤트 핸들러를 호출하지 않도록 할 수 있습니다. 이처럼 Debounce는 주로 사용자가 작업을 완료한 후에만 특정 작업을 실행하고 싶을 때 사용됩니다.</p>
<h5 id="②-throttle">② Throttle</h5>
<p>Throttle은 이벤트가 반복적으로 발생하더라도 일정 시간 간격으로만 이벤트 핸들러를 호출하는 기법입니다. 주로 스크롤이나 리사이즈와 같은 고빈도 이벤트에서 사용됩니다. 이벤트가 자주 발생하더라도 성능을 유지하면서 일부 이벤트만 처리하고 싶을 때 유용합니다.</p>
<br />

<blockquote>
<p>🧐 더 자세한 내용 알아보기
<a href="https://velog.io/@55555-jyeon/debounce-throttle">Debounce? Throttle?</a></p>
</blockquote>
<br />

<h3 id="5️⃣-렌더링-성능-향상">5️⃣ 렌더링 성능 향상</h3>
<h5 id="automatic-batching">Automatic Batching</h5>
<p>Automatic Batching은 React 18부터 도입된 기능으로, 여러 상태 업데이트를 하나의 렌더링 사이클로 묶어서 처리하는 기법입니다. 해당 기능으로 불필요한 렌더링을 줄일 수 있기 때문에 리렌더링이 더 효율적으로 다룰 수 있고 나아가 성능을 향상시킬 수 있습니다. </p>
<h5 id="code-splitting">Code Splitting</h5>
<p>Code Splitting은 애플리케이션을 작은 청크(chunk)로 나누어 필요한 코드만 로드하는 기법으로 초기 로딩 시간을 단축하고, 사용자가 필요할 때만 해당 모듈을 로드하여 성능을 최적화할 수 있습니다. React에서는 주로 <code>React.lazy</code>와 Suspense를 사용해 구현합니다.</p>
<br />

<blockquote>
<p>🧐 더 자세한 내용 알아보기
<a href="https://velog.io/@55555-jyeon/react-improve-performance">모아서 해? 나눠서 해?</a></p>
</blockquote>
<br />
<hr />
<br />

<h1 id="vii-렌더링-성능-측정">VII. 렌더링 성능 측정</h1>
<p><img src="https://velog.velcdn.com/images/55555-jyeon/post/2d6f4500-6d65-4ce7-ba1a-20bd0db70e2e/image.png" alt=""></p>
<p><a href="https://legacy.reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html">React DevTools Profiler</a>를 사용하면 컴포넌트가 각각의 커밋 단계에서 어떤 것을 렌더링하는지 확인할 수 있습니다.</p>
<p>어플리케이션을 개발 모드로 프로파일링하면 어떤 컴포넌트가 렌더링되는지와 그 이유를 확인할 수 있고 렌더링 시 필요한 상대적 시간을 컴포넌트끼리 서로 비교할 수도 있습니다.  </p>
<blockquote>
<p><strong>⚠︎ CAUTION ⚠︎</strong> <br />
<strong>React는 dev 빌드에서 더 느리게 동작</strong>
<strong>절대적인 횟수는 반드시 production 빌드에서만 사용</strong></p>
</blockquote>
<br />

<h3 id="🔎-react-devtools-profiler-사용-방법">🔎 React DevTools Profiler 사용 방법</h3>
<blockquote>
<p>🧐 더 자세한 내용 알아보기 
<a href="https://velog.io/@55555-jyeon/React-optimise">React, 성능 최적화 (feat. DevTools) 게시글 읽으러 가기</a></p>
</blockquote>
<br />
<hr />
<br />

<h1 id="viii-react의-고급-기능과-미래-방향">VIII. React의 고급 기능과 미래 방향</h1>
<h3 id="💂🏻♀️-concurrent-mode와-렌더링">💂🏻‍♀️ Concurrent Mode와 렌더링</h3>
<p>Concurrent Mode는 React 18에서 완전히 도입된 새로운 렌더링 패러다임입니다. 렌더링 작업을 작은 단위로 나누고, 우선순위를 지정하여 처리합니다.</p>
<h5 id="작동-방식">작동 방식</h5>
<p>1️⃣ 작업 단위 분할</p>
<p>기존의 React 렌더링 방식에서는 모든 작업이 하나의 단일 프로세스로 처리되었습니다. 
이 때문에 긴 작업이 발생하면 사용자의 인터랙션이 지연될 수 있었습니다. 
그러나 Concurrent Mode에서는 렌더링 작업을 여러 개의 작은 단위로 나누어 수행합니다. 이를 통해 긴 렌더링 작업 도중에도 사용자의 인터랙션이 중단되지 않고, 부드럽게 처리될 수 있습니다.</p>
<p>2️⃣ 우선순위 기반 처리</p>
<p>Concurrent Mode에서는 각 작업에 우선순위를 지정하여 처리합니다. 
예를 들어, 사용자의 입력이나 중요한 인터랙션은 높은 우선순위를 가지며, 이 작업은 즉시 처리됩니다. 
반면에, 덜 중요한 작업은 백그라운드에서 천천히 처리됩니다. 
이렇게 우선순위를 지정함으로써, 사용자가 느끼는 인터랙션의 지연이 최소화됩니다.</p>
<br />

<h5 id="사용-시-이점">사용 시 이점</h5>
<p>Concurrent Mode는 React 애플리케이션의 렌더링 성능을 크게 향상시키고, 특히 복잡한 UI를 가진 애플리케이션에서 사용자 경험을 최적화하는 데 큰 도움이 됩니다.</p>
<h5 id="고려-사항">고려 사항</h5>
<p>하지만 Concurrent Mode를 도입했을 때 고려해야 하는 부분도 존재합니다.
렌더링 프로세스가 더욱 유연해지고 강력해지지만, 동시에 애플리케이션의 복잡성도 증가할 수 있습니다. 모든 컴포넌트가 Concurrent Mode를 잘 활용하기 위해서는 추가적인 테스트와 최적화가 필요할 수 있습니다.</p>
<p>또한 일부 오래된 라이브러리나 컴포넌트는 Concurrent Mode와 호환되지 않을 수 있습니다. 따라서, 기존 코드베이스와의 호환성을 고려하면서 단계적으로 적용하는 것이 중요합니다.</p>
<br />


<pre><code>[핵심 API]

① useTransition → 우선순위가 낮은 상태 업데이트를 표시
② useDeferredValue → 값의 업데이트를 지연시켜 더 중요한 업데이트를 먼저 처리</code></pre><br />
<br />

<h3 id="🪖-suspense와-error-boundaries">🪖 Suspense와 Error Boundaries</h3>
<h4 id="suspense">Suspense</h4>
<p>suspense는 컴포넌트가 렌더링을 하기 전에 무언가를 기다려야 할 때 사용합니다.
Suspense 경계 내의 컴포넌트가 아직 렌더링할 준비가 되지 않았다고 React에 알려주는 방식으로 작동합니다.</p>
<pre><code>    [주요 사용 사례]

    1️⃣ 데이터 페칭
    API 응답을 기다리는 동안 대체 UI를 보여줄 수 있습니다.

    2️⃣ 코드 스플리팅
    동적으로 임포트된 컴포넌트가 로드되는 동안 로딩 UI를 표시합니다.</code></pre><br />

<h4 id="error-boundaries">Error Boundaries</h4>
<p>error boundaries는 컴포넌트 트리의 어느 부분에서든 JavaScript 에러를 포착하고 처리합니다. </p>
<p><code>componentDidCatch</code> 생명주기 메서드나 <code>static  getDerivedStateFromError</code> 메서드를 사용해 구현 가능합니다.</p>
<br />

<pre><code>[주요 특징]

1️⃣ 에러 로깅
개발 중 에러를 쉽게 추적할 수 있습니다.

2️⃣ fallback UI
에러 발생 시 사용자에게 친화적인 메시지를 표시할 수 있습니다.</code></pre><br />

<blockquote>
<p>🧐 더 자세한 내용 알아보기
<a href="https://velog.io/@55555-jyeon/suspenseerrorBoundary">비동기 처리로 더 빠르고 부드러운 UX</a></p>
</blockquote>
<br />
<br />

<h3 id="💻-ssr과-ssg">💻 SSR과 SSG</h3>
<h4 id="서버-사이드-렌더링-ssr">서버 사이드 렌더링 (SSR)</h4>
<p>SSR은 서버에서 React 컴포넌트를 렌더링하여 HTML을 생성하고, 이를 클라이언트에 전송합니다. SSR을 사용할 경우 초기 페이지 로드 시간을 단축할 수 있고 검색 엔진 최적화(SEO) 향상이 가능하다는 장점이 있습니다.</p>
<p>Next.js, Gatsby 등의 프레임워크를 사용하면 SSR을 쉽게 구현할 수 있습니다.</p>
<blockquote>
<p>🧐 더 자세한 내용 알아보기 <br /></p>
</blockquote>
<ul>
<li><a href="https://velog.io/@55555-jyeon/whats-nextjs">NextJS 특징 톺아보기</a> </li>
<li><a href="https://velog.io/@55555-jyeon/lets-nextjs">quick start: NextJS</a></li>
<li><a href="https://velog.io/@55555-jyeon/SEO">왜 SEO해야 할까?</a></li>
</ul>
<br />

<h4 id="정적-사이트-생성-ssg">정적 사이트 생성 (SSG)</h4>
<p>SSG는 빌드(build) 시점에 모든 페이지의 HTML을 미리 생성시키기 때문에 
페이지의 로드(load) 시간이 매우 빠르고 서버의 부하를 감소시킬 수 있다는 장점이 있습니다. </p>
<pre><code>[정적인 사이트의 특징]

1️⃣ 빌드 시점에 HTML 생성
- SSG는 웹사이트의 모든 페이지를 빌드 시점에 미리 생성해 정적인 HTML 파일로 저장
- 정적 HTML 파일은 사용자가 요청할 때 서버에서 즉시 제공되므로 로드 속도가 매우 빠름


2️⃣ 빌드 과정 필요
- 콘텐츠가 변경될 때마다 build &amp; deploy 과정이 필요 
- 모든 변경 사항마다 사이트를 재빌드하는 것은 비효율적


2️⃣ 캐싱의 이점
- SSG는 서버나 CDN(Content Delivery Network)에서 쉽게 캐시 가능 
- 캐싱된 SSG는 서버 부하를 줄이고 사용자에게 매우 빠르게 제공
- 그러나 콘텐츠의 잦은 변경 시 캐싱된 페이지를 자주 무효화하고 다시 생성 → 캐싱의 장점 X</code></pre><p>따라서, 콘텐츠가 자주 변경되지 않는 웹사이트(예를 들어 포트폴리오, 블로그, 문서 사이트 등)에서는 SSG가 적합한 반면, 실시간 업데이트가 중요한 웹사이트에서는 다른 접근 방식(SSR 또는 CSR)이 더 적합할 수 있습니다.</p>
<br />
<br />

<h3 id="✨-react-18의-새로운-기능들">✨ React 18의 새로운 기능들</h3>
<p>React 18은 여러 새로운 hooks와 기능을 도입했습니다.
간략하게 소개하자면 아래와 같습니다.</p>
<h5 id="useid">useId</h5>
<ul>
<li>서버와 클라이언트에서 일관된 고유 ID를 생성</li>
<li>특히 접근성 속성에 유용</li>
</ul>
<h5 id="usesyncexternalstore">useSyncExternalStore</h5>
<ul>
<li>외부 데이터 소스와의 동기화를 단순화</li>
<li>Redux와 같은 상태 관리 라이브러리와의 통합에 유용</li>
</ul>
<h5 id="useinsertioneffect">useInsertionEffect</h5>
<ul>
<li>CSS-in-JS 라이브러리를 위한 최적화된 훅</li>
<li>레이아웃 효과 이전에 스타일 삽입이 가능</li>
</ul>
<br />
<br />


<h3 id="🍡-상태-관리-라이브러리와-렌더링">🍡 상태 관리 라이브러리와 렌더링</h3>
<p>상태 관리 라이브러리(Redux, MobX, Recoil 등)는 React의 렌더링 과정과 밀접하게 연관되어 있습니다.</p>
<p>이러한 라이브러리들은 각각 고유한 방식으로 React의 렌더링 프로세스와 상호작용하며, 최적화된 상태 업데이트와 렌더링을 제공합니다.</p>
<br />

<h5 id="redux">Redux</h5>
<p>중앙 집중식 상태 관리를 제공하며, 불필요한 리렌더링을 방지하기 위해 최적화가 필요할 수 있습니다.</p>
<h5 id="mobx">MobX</h5>
<p>반응형 프로그래밍 모델을 사용하여 자동으로 상태 변화를 추적하고 필요한 부분만 업데이트합니다.</p>
<h5 id="recoil">Recoil</h5>
<p>React를 위해 특별히 설계된 상태 관리 라이브러리로, 비동기 상태 관리와 파생 상태를 쉽게 다룰 수 있게 해줍니다.</p>
<br />
<br />

<h6 id="예정된-변화와-렌더링에-미칠-영향">예정된 변화와 렌더링에 미칠 영향</h6>
<h3 id="🌈-react의-미래">🌈 React의 미래</h3>
<p>React 팀은 지속적으로 성능 개선과 개발자 경험 향상을 위해 노력하고 있는 것으로 보입니다.</p>
<pre><code>1️⃣ React Forget
- 자동 메모이제이션 기능
- 개발자가 수동으로 최적화 작업을 하지 않아도 됨

2️⃣ Server Components
- 서버에서 렌더링되고 클라이언트에서 상호작용이 가능한 컴포넌트
- 초기 로드 성능을 크게 향상 가능

3️⃣ 새로운 React 문서
- 새로운 문서를 통해 함수형 컴포넌트와 훅을 중심으로 한 현대적인 React 개발 방식을 강조</code></pre><br />

<p>이러한 변화들은 React 애플리케이션의 성능을 향상시키고, 개발자 경험을 개선하며, 더 효율적인 렌더링 프로세스를 가능하게 할 것으로 기대됩니다.</p>
<br />
<br />

<h6 id="modern-react-deepdive의-말을-빌리자면">modern react deepdive의 말을 빌리자면...</h6>
<h4 id="맺음말">맺음말</h4>
<p><a href="https://www.youtube.com/watch?v=WzRSysq7F4k">React.js: The Documentary</a>의 질의응답 영상에 따르면 현재 react가 가장 집중적으로 역량을 쏟고 있는 것은 서버에서의 리액트의 활용입니다.
어떻게 하면 서버에서 리액트를 효율적으로 사용할 수 있을지, 그리고 이러한 작동 방식을 사용자에게 어떻게 소개할지에 대해 고민하고 있는 것으로 보입니다.</p>
<p>과거 리액트는 클라이언트에 초점을 맞추고 있었고, 앞으로도 브라우저와 클라이언트에서의 작동을 개선할 예정이라고 밝힌 바 있습니다.</p>
<p>리액트 팀은 클라이언트에서는 할 수 없었던 서버에서의 작업, 그리고 서버 환경이 갖고 있는 가능성에 무게를 두고 앞으로도 서버에서 작동할 수 있는 다양한 유스케이스를 추가할 것으로 보입니다. </p>
<p>따라서 리액트를 계속 사용할 예정인 프론트엔드 개발자들은 새로운 가능성에 대비하며 서버와 클라이언트의 경계를 넘나드는 개발 역량을 갖추는 것이 중요할 것 같습니다.</p>
<br />

<blockquote>
<p>🧐 <a href="https://velog.io/@55555-jyeon/why-react">React의 과거와 미래</a> 보러 가기</p>
</blockquote>
<br />
<hr />


<p>🔗 <em>References.</em></p>
<p>[📄 Original]</p>
<ul>
<li><a href="https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-mostly-complete-guide-to-react-rendering-behavior/#final-thoughts">Blogged Answers: A (Mostly) Complete Guide to React Rendering Behavior</a></li>
</ul>
<p>[🌎 Translate]</p>
<ul>
<li><a href="https://velog.io/@arthur/%EB%B2%88%EC%97%AD-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A0%8C%EB%8D%94%EB%A7%81-%EB%8F%99%EC%9E%91%EC%9D%98-%EA%B1%B0%EC%9D%98-%EC%99%84%EB%B2%BD%ED%95%9C-%EA%B0%80%EC%9D%B4%EB%93%9C-A-Mostly-Complete-Guide-to-React-Rendering-Behavior">[번역] 리액트 렌더링 동작의 (거의) 완벽한 가이드 [A (Mostly) Complete Guide to React Rendering Behavior]</a></li>
</ul>
<br />


<p>[🐱 GitHub]</p>
<ul>
<li><a href="https://github.com/facebook/react">facebook/react github repository</a></li>
<li><a href="https://github.com/acdlite/react-fiber-architecture">React Fiber Architecture</a></li>
</ul>
<p>[🎤 Officials]</p>
<ul>
<li><a href="https://react.dev/reference/react/useTransition#usetransition">useTransition</a></li>
</ul>
<p>[📖 Books]</p>
<ul>
<li>모던 리액트 Deep Dive</li>
</ul>
<p>[👩🏻‍💻 Blogs]</p>
<ul>
<li><a href="https://legacy.reactjs.org/docs/faq-internals.html#gatsby-focus-wrapper">Virtual DOM and Internals</a></li>
<li><a href="https://daveceddia.com/javascript-references/">A Visual Guide to References in JavaScript</a></li>
<li><a href="https://m.blog.naver.com/dlaxodud2388/223195103660">[React] Fiber 아키텍처의 개념과 Fiber Reconcilation 이해하기</a></li>
<li><a href="https://namansaxena-official.medium.com/react-virtual-dom-reconciliation-and-fiber-reconciler-cd33ceb0478e">React Virtual DOM, Reconciliation and Fiber Reconciler</a></li>
<li><a href="https://adevnadia.medium.com/react-compiler-react-19-forget-about-memoization-soon-0eb325ec3ce0">React Compiler &amp; React 19 — forget about memoization soon?</a></li>
</ul>
<p>[📽️ Videos]</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=0ympFIwQFJw">What Is React Fiber? React.js Deep Dive</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>