<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yu_yu.log</title>
        <link>https://velog.io/</link>
        <description>재밌게! 개발 탐구 생활</description>
        <lastBuildDate>Mon, 09 Nov 2020 16:58:29 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yu_yu.log</title>
            <url>https://images.velog.io/images/yu_yu/profile/8e8eae40-e9af-4d6b-b8e8-b57c7a168b93/IMG_9930 2.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yu_yu.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yu_yu" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[useMemo, useCallback, React.memo]]></title>
            <link>https://velog.io/@yu_yu/useMemo-useCallback-React.memo-gu4rsta9</link>
            <guid>https://velog.io/@yu_yu/useMemo-useCallback-React.memo-gu4rsta9</guid>
            <pubDate>Mon, 09 Nov 2020 16:58:29 GMT</pubDate>
            <description><![CDATA[<p>useMemo와 useCallback은 이전 값을 기억해서 성능을 최적화하는 용도로 사용된다.</p>
<h2 id="usememo">useMemo</h2>
<p>useMemo 훅은 계산량이 많은 함수의 반환값을 재활용하는 용도로 사용된다.</p>
<pre><code class="language-js">import React, {useMemo} from &#39;react&#39;;
import { runExpensiveJob } from &#39;./util&#39;;

function MyComponent({v1, v2}) {
  const value = useMemo(() =&gt; runExpensiveJob(v1,v2), [v1, v2]);
  return &lt;p&gt;{`value is ${value}`}&lt;/p&gt;;
}</code></pre>
<p>useMemo 훅의 첫 번째 매개변수로 함수를 입력한다. useMemo 훅은 이 함수가 반환한 값을 기억한다. useMemo 훅의 두 번째 매개변수는 의존성 배열이다. 의존성 배열의 값이 변경되지 않으면 이전에 반환된 값을 재사용한다. 만약 배열의 값이 변경됐으면 첫 번째 매개변수로 입력된 함수를 실행하고 그 반환값을 기억한다.</p>
<h2 id="usecallback">useCallback</h2>
<p>useCallback은 리액트의 랜더링 성능을 위해 제공되는 훅이다. 컴포넌트가 렌더링될 때마다 새로운 함수를 생성해서 자식 컴포넌트의 속성값으로 입력하는 경우가 많다. </p>
<p>다음은 useCallback 훅이 필요한 예이다.</p>
<pre><code class="language-js">import React, {useSatate} from &#39;react&#39;;
import {saveToServer} from &#39;./api&#39;;
import UserEdit from &#39;./UserEdit&#39;;

function Profile(){
  const [name, setName] = useState(&#39;&#39;);
  const [age, setAge] = useState(0);

  return (
    &lt;div&gt;
      &lt;p&gt;{`name is ${name}`}&lt;/p&gt;
      &lt;p&gt;{`age is ${age}`}&lt;/p&gt;
      &lt;UserEdit 
        onSave={() =&gt; saveToServer(name, age)}
        setName={setName}
        setAge={setAge}
      /&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>Profile 컴포넌트가 렌더링될 때마다 UserEdit 컴포넌트의 onSave 속성값으로 새로운 함수가 입력된다. 따라서 UserEdit 컴포넌트에서 React.memo를 사용해도 onSave 속성값이 항상 변경되고 그 때문에 불필요한 렌더링이 발생한다. onSave 속성값은 name이나 age값이 변경되지 않으면 항상 같아야 한다.
 useCallback 훅을 사용하면 불필요한 렌더링을 막을 수 있다. 다음은 useCallback 훅을 사용한 코드다.</p>
<pre><code class="language-js">function Profile(){
  const [name, setName] = useState(&#39;&#39;);
  const [age, setAge] = useState(0);
  const onSave = useCallback(() =&gt; saveToServer(name, age), [name, age]);
  return (
    &lt;div&gt;
        &lt;p&gt;{`name is ${name}`}&lt;/p&gt;
        &lt;p&gt;{`age is ${age}`}&lt;/p&gt;
    &lt;UserEdit onSave={onSave} setName={setName} setAge={setAge} /&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>이전에 onSave 속성값으로 전달했던 것과 같은 함수를 useCallback 훅의 첫번째 매개변수로 입력한다. useCallback 훅의 두 번째 매개변수는 의존성 배열이다. 의존성 배열이 변경되지 않으면 이전에 생성한 함수가 재사용된다. 따라서 name과 age값이 변경되지 않으면, UserEdit 컴포넌트의 onSave 속성값으로 항상 같은 함수가 전달된다.</p>
<h2 id="reactmemo">React.memo</h2>
<p>React는 먼저 컴포넌트를 렌더링(rendering) 한 뒤, 이전 렌더된 결과와 비교하여 DOM 업데이트를 결정한다. 만약 렌더 결과가 이전과 다르다면, React는 DOM을 업데이트한다. 다음 렌더링 결과와 이전 결과의 비교는 빠르다. 하지만 어떤 상황에서는 이 과정의 속도를 좀 더 높일 수 있다.컴퍼넌트가 React.memo()로 래핑 될 때, React는 컴퍼넌트를 렌더링하고 결과를 메모이징(Memoizing)한다. 그리고 다음 렌더링이 일어날 때 props가 같다면, React는 메모이징(Memoizing)된 내용을 재사용한다.</p>
<pre><code class="language-js">export function Movie({ title, releaseDate }) {
  return (
    &lt;div&gt;
      &lt;div&gt;Movie title: {title}&lt;/div&gt;
      &lt;div&gt;Release date: {releaseDate}&lt;/div&gt;
    &lt;/div&gt;
  );
}

export const MemoizedMovie = React.memo(Movie);</code></pre>
<p>MemoizedMovie의 렌더링 결과는 메모이징 되어있다. 만약 title이나 releaseData 같은 props가 변경 되지 않는다면 다음 렌더링 때 메모이징 된 내용을 그대로 사용하게 된다.</p>
<p>메모이징 한 결과를 재사용 함으로써, React에서 리렌더링을 할 때 가상 DOM에서 달라진 부분을 확인하지 않아 성능상의 이점을 누릴 수 있다.</p>
<h3 id="비교-함수-커스터마이징">비교 함수 커스터마이징</h3>
<p>React.memo의 두 번째 매개변수로 속성값 비교 함수를 입력한다. 속성값 비교 함수에서 참을 반환하면 이후 단계를 생략하고 이전 렌더링 결과를 재사용한다. 만약 속성값 비교 함수를 입력하지 않으면 얕은 비교를 수행하는 기본 함수가 사용된다.</p>
<p>비교 방식을 수정하고 싶다면 React.memo() 두 번째 매개변수로 비교함수를 만들어 넘겨주면 된다.</p>
<pre><code class="language-js">function moviePropsAreEqual(prevMovie, nextMovie) {
  return (
    prevMovie.title === nextMovie.title &amp;&amp;
    prevMovie.releaseDate === nextMovie.releaseDate
  );
}

const MemoizedMovie2 = React.memo(Movie, moviePropsAreEqual);</code></pre>
<h3 id="언제-reactmemo를-써야할까">언제 React.memo()를 써야할까</h3>
<p>컴퍼넌트가 같은 props로 자주 렌더링되거나, 무겁고 비용이 큰 연산이 있는 경우, React.memo()로 컴퍼넌트를 래핑할 필요가 있다.</p>
<h3 id="언제-reactmemo를-사용하지-말아야-할까">언제 React.memo()를 사용하지 말아야 할까</h3>
<p>위에서 언급한 상황에 일치하지 않는다면 React.memo()를 사용할 필요가 없을 가능성이 높다.</p>
<p>렌더링될 때 props가 다른 경우가 대부분인 컴포넌트를 생각해보면, 메모이제이션 기법의 이점을 얻기 힘들다.
또한, 기술적으로는 가능하지만 클래스 기반의 컴퍼넌트를 React.memo()로 래핑하는것은 적절하지 않다. 클래스 기반의 컴퍼넌트에서 메모이제이션이 필요하다면 PureComponent를 확장하여 사용하거나, shouldComponentUpdate() 메서드를 구현하는 것이 적절하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[변수 var, let, const]]></title>
            <link>https://velog.io/@yu_yu/%EB%B3%80%EC%88%98-var-let-const</link>
            <guid>https://velog.io/@yu_yu/%EB%B3%80%EC%88%98-var-let-const</guid>
            <pubDate>Sun, 25 Oct 2020 12:07:51 GMT</pubDate>
            <description><![CDATA[<h1 id="var-let-const-키워드의-역할과-차이점은-무엇인가">var, let, const 키워드의 역할과 차이점은 무엇인가?</h1>
<p>변수란 데이터(data)를 저장할 수 있는 메모리 공간을 말하고,
var, let, const 모두 자바스크립트에서 변수를 선언할 때 쓰이는 키워드들이다. </p>
<p>ES5까지 var를 이용해서 변수를 정의했고 ES6부터 const와 let을 이용하는 새로운 변수 정의 방법이 생겼다.</p>
<p>var와 let은 변하는 어떤 값을 정의할 때 쓰고, const는 변하지 않는 값, 상수를 정의할 때 쓰인다.</p>
<h2 id="그럼-기존-var-키워드가-있는데-let-const-키워드가-새로-나온-이유는-뭘까">그럼 기존 var 키워드가 있는데 let, const 키워드가 새로 나온 이유는 뭘까?</h2>
<h3 id="var가-가진-문제-1-함수-스코프">var가 가진 문제 1: 함수 스코프</h3>
<p>var로 선언된 변수는 함수 스코프를 가진다. 스코프란 변수의 유효 범위를 의미한다. 그래서 함수 안에 선언된 변수를 함수 바깥에서 사용하면 참조 에러가 난다. </p>
<p>그리고 var 변수를 최상위에서 선언하면 전역변수가 되는데, var 키워드 없이 선언되어도 전역변수가 된다는 점이 특이하다.</p>
<p>for문, while문, switch 문, if 문 등 그 안에서 정의 된 변수가 반복문, 조건문이 끝난 이후에도 계속 남는 문제점이 있다.</p>
<h3 id="var가-가진-문제-2-재선언을-허용">var가 가진 문제 2: 재선언을 허용</h3>
<p>var 키워드를 사용하면 여러 번 변수를 다시 선언 할 수 있다. 
let 키워드로 동일한 범위에서 let을 두 번 사용하여 동일한 변수를 선언하면 오류다. 
var는 여러번 동일한 변수를 선언해도 이미 선언된 변수는 무시된다. </p>
<h3 id="var가-가진-문제-3-호이스팅">var가 가진 문제 3: 호이스팅</h3>
<p>var로 정의된 변수는 그 변수가 속한 스코프의 최상단으로 끌어올려진다. 
변수가 정의된 시점보다 먼저 변수를 사용하게 될 경우 호이스팅으로 인해 변수의 정의만 끌어올려지고 값은 원래 정의했던 위치에서 할당된다. </p>
<p>에러가 발생하지 않고 사용될 수 있는 이러한 특징은 직관적이지 않고, 단점이라고 할 수 있다.</p>
<h2 id="var의-문제를-해결하는-const-let">var의 문제를 해결하는 const, let</h2>
<h3 id="const-let은-블록-스코프다">const, let은 블록 스코프다</h3>
<p>블록스코프에서는 블록을 벗어나면 변수를 사용할 수 없다.
조건문이나 반복문에서 생성된 변수를 블록 바깥에서 사용하려고 하면 에러가 발생하는데, 오히려 이런 상황에서 에러가 발생하는 것이 직관적이며 이해하기도 쉽다.</p>
<h3 id="const-let에서의-호이스팅">const, let에서의 호이스팅</h3>
<p>const 또는 let으로 정의된 변수도 호이스팅된다. 하지만 var와 다르게 변수가 정의된 시점보다 먼저 변수를 사용할 수 없다. 변수가 정의된 위치와 호이스팅된 위치 사이에서 변수를 사용하려고 하면 에러가 발생하기 때문이다. </p>
<pre><code>Uncaught ReferenceError: Cannot access &#39;foo&#39; before initialization</code></pre><p>이 구간을 임시적 사각지대(temporal dead zone)라고 한다.
즉, TDZ 구간에 있는 변수 객체는 <code>선언은 되어있지만 아직 초기화가 되지않아 변수에 담길 값을 위한 공간이 메모리에 할당되지 않은 상태</code> 이다.</p>
<p>임시적 사각지대에서 변수를 사용하지 못한다면 호이스팅의 역할은 무엇일까?
호이스팅으로 어떤 지역 스코프에서 의도치 않게게 더 상위 스코프의 같은 변수를 참조하는 오류를 발생하지 않게 하기 위함?</p>
<h3 id="const는-변수를-재할당-불가능하게-만든다">const는 변수를 재할당 불가능하게 만든다.</h3>
<p>const로 정의된 변수는 재할당이 불가능하다. 반대로 let, var로 정의된 변수는 재할당할 수 있다. 재할당 불가능한 변수는 프로그램의 복잡도를 상당히 낮춰주기 때문에 되도록이면 재할당 불가능한 변수를 사용하는게 좋다.
다만 const로 정의된 객체의 내부 속성값은 수정 가능하다는 점을 주의해야 한다.</p>
]]></description>
        </item>
    </channel>
</rss>