220515 TIL

klucas·2022년 5월 15일
0
post-thumbnail

TIL DAY 183

오늘 배운 일

✔️ React Hooks

유튜브 별코딩님의 강의를 보고 작성한 나의 일지

1. useMemo

컴포넌트 성능을 최적화하는 hook

useMemo -> Memo = Memoization (메모이제이션)

동일한 값을 리턴하는 함수를 반복적으로 호출되어야 한다면, 맨 처음 값을 계산할 때 해당 값을 메모리에 저장해서 필요할 때마다 꺼내서 재사용하는 기능을 가지고 있다.

간단히 말하자면, 자주 필요한 값을 맨 처음 계산할 때 캐싱을 해둬서 그 값을 필요할 때마다 캐시에서 꺼내서 사용한다.

중요한 사실!

  • 함수형 컴포넌트는 함수이고 렌더링 될 때마다, 컴포넌트가 호출되면서 모든 내부 변수들이 초기과된다.
  • useMemo 는 처음 계산된 결과값을 메모리에 저장해서, 컴포넌트가 반복적으로 렌더링된다라고 해도 계속해서 해당 hook 이 실행할 코드를 호출하지 않고 이전에 이미 계산된 값을 꺼내서 다시 실행한다.

기본 형식

첫 번째 인자로는, 콜백함수
두 번째로는 배열을 받는다.

첫 번째 인자인 콜백함수는 우리가 Memoization 할 값을 계산해서 리턴해주는 함수

두 번째 배열은 의존성 배열이라고 불린다.
useMemo 는 안의 요소의 값이 업데이트 될 때마다 콜백함수를 호출해서 Memoization 된 값을 업데이트해서 다시 Memoization 해준다.

빈 배열일 경우, 맨 처음 컴퓨터가 마운트 되었을 때만 계산하고 이후에는 Memoization 된 값만 꺼내서 쓴다.

예 ) 계산기

App.js

import { useMemo, useState } from "react";

const hardCalculate = (number) => {
  console.log("어려운 계산!");
  for (let i = 0; i < 999999999; i++) {}
  return number + 10000;
};

const easyCalculate = (number) => {
  console.log("짱 쉬운 계산!");
  return number + 1;
};

export default function App() {
  const [hardNumber, setHardNumber] = useState(1);
  const [easyNumber, setEasyNumber] = useState(1);

  // const hardSum = hardCalculate(hardNumber);
  const hardSum = useMemo(() => {
    return hardCalculate(hardNumber);
  }, [hardNumber]);
  const easySum = easyCalculate(easyNumber);
  return (
    <div>
      <h3>어려운 계산기</h3>
      <input
        type="number"
        value={hardNumber}
        onChange={(e) => setHardNumber(parseInt(e.target.value, 10))}
      />
      <span> + 10000 = {hardSum}</span>

      <h3>쉬운 계산기</h3>
      <input
        type="number"
        value={easyNumber}
        onChange={(e) => setEasyNumber(parseInt(e.target.value, 10))}
      />
      <span> + 1 = {easySum}</span>
    </div>
  );
}

위의 코드를 보면, 저장할 함수를 useMemo 콜백함수에 저장해서 계산할 때마다 업데이트가 되도록 설계되어있다.

useState 를 사용해서 input 안에 값이 업데이트 될때마다 state 가 바뀌도록 설계했다.

숫자를 올리면...

이렇게 값이 잘 바뀐것을 확인할 수 있다.

다른 예제 )

App.js

import { useState, useEffect, useMemo } from "react";

export default function App() {
  const [number, setNumber] = useState(0);
  const [isKorea, setIsKorea] = useState(true);
  // const location = isKorea ? "한국" : "외국";

  const location = useMemo(() => {
    return {
      country: isKorea ? "한국" : "외국"
    };
  }, [isKorea]);

  useEffect(() => {
    console.log("useEffect 호출");
  }, [location]);

  return (
    <div>
      <h2>하루에 몇끼 먹어요?</h2>
      <input
        type="number"
        value={number}
        onChange={(e) => {
          setNumber(e.target.value);
        }}
      />
      <hr />
      <h2>어느 나라에 있어요?</h2>
      <p>나라 : {location.country}</p>
      <button onClick={() => setIsKorea(!isKorea)}>비행기 타자</button>
    </div>
  );
}

이번에는 useMemo 에 객체 형태에 삼항 연산자를 사용해서 state 가 true 이면, '한국'이 뜨고 false 이면 '외국'이 뜨게 설계했다.
비행기 타자 버튼을 누를때마다, 나라가 바뀐다.

재밌는 사실!

자바스크립트에서는 기본형과 참조형이 존재한다.
변수에 기본형인 숫자 1을 담고, 다른 변수에 똑같이 숫자 1을 담아 서로 비교 연산자를 진행하면...

const num = 1
const num1 = 1

num === num1

결과는...

true

하지만 참조형중 하나인 객체를 변수에 저장하고 똑같은 객체를 하나 더 만들고 비교 연산자를 하면...

const obj = {apple : "아이폰"}
const obj1 = {apple : "아이폰"}

obj === obj1

결과는...

false

그 이유는 처음에 저장되는 객체는 다른 번호로 저장되어있어, 아무리 똑같은 객체가 담긴 변수여도 비교 연산자를 하면 false 가 된다.

출처 : https://velog.io/@altjsvnf/React-useMemo

2. useCallback

useMemo 와 동일하게 컴포넌트 성능을 최적화시킨다.

이 때 Memoization 이란???

  • 자주 사용되는 값을 받아오기 위해 반복적으로 계산해야 한다면, 이전에 이미 계산한 값을 캐싱해서 해당 값이 또 필요할 때마다 반복적으로 계산하는게 아니라 메모리에서 꺼내서 재사용하는 최적화 기법!

기본 형태

useCallback( ( ) => {
	return value;
}, [item])

useMemo 랑 다르게, useCallback 은 이름에서 알 수 있듯이 인자로 전달한 콜백함수 그 자체를 Memoization 해준다. 렌더링 될 때마다, 이전에 저장해둔 함수 객체를 재사용한다.

두 번째 인자인 의존성 배열 내부에 있는 값이 변경되니 않는 이상, 다시 초기화되지 않는다.

예 )

App.js

import { useEffect, useState, useCallback } from "react";

export default function App() {
  const [number, setNumber] = useState(0);
  const [toggle, setToggle] = useState(true);

  const someFunction = useCallback(() => {
    console.log(`someFunc: number ${number}`);
    return;
  }, [number]);

  useEffect(() => {
    console.log("sumFunction이 변경되었습니다.");
  }, [someFunction]);
  return (
    <div className="App">
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(e.target.value)}
      />
      <button onClick={() => setToggle(!toggle)}>{toggle.toString()}</button>
      <br />
      <button onClick={someFunction}>Call someFunc</button>
    </div>
  );
}

다섯번 클릭했을 경우...

콘솔 로그...

숫자를 바꿀 때마다 "sumFunction이 변경되었습니다." 이 호출되면서
Call someFunc 버튼을 누르면...

"someFunc: number 5" 이 콘솔에 찍힌다.

useCallback 을 사용하지 않으면, 숫자를 바꿀때마다 렌더링되면서
"someFunc: number 숫자" 가 호출되었다.

하지만, 이 훅을 통해 오직 number 라는 state 가 바뀌고 버튼을 클릭했을 때마다, 콘솔을 호출할 수 있도록 설계되어있다.

다른 예 )

App.js

import { useCallback, useState } from "react";
import Box from "./Box";
import "./styles.css";

export default function App() {
  const [size, setSize] = useState(100);

  const [isDark, setIsDark] = useState(false);

  const createBoxStyle = useCallback(() => {
    return {
      backgroundColor: "pink",
      width: `${size}px`,
      height: `${size}px`
    };
  }, [size]);

  return (
    <div
      style={{
        background: isDark ? "black" : "white"
      }}
    >
      <input
        type="number"
        value={size}
        onChange={(e) => setSize(e.target.value)}
      />
      <button onClick={() => setIsDark(!isDark)}>Change Theme</button>
      <Box createBoxStyle={createBoxStyle} />
    </div>
  );
}

Box.js

import { useEffect, useState } from "react";

function Box({ createBoxStyle }) {
  const [style, setStyle] = useState({});

  useEffect(() => {
    console.log(`박스 키우기 🎁`);
    setStyle(createBoxStyle());
  }, [createBoxStyle]);

  return <div style={style}></div>;
}

export default Box;

App 컴포넌트 안에 Box 라는 컴포넌트를 만들어서 input 의 숫자를 증가시킬 때마다, 핑크색 박스가 점점 커지고 숫자를 줄일때마다 박스는 작아진다.

숫자 300일 때...

숫자 50일 때...

useCallback 을 사용해서 함수 객체를 저장시키고, 렌더링 될 때마다 저장된 함수를 꺼내서 재사용해서 사용된다.

그리고 Change Theme 을 클릭하면...

검정색 박스가 생기게 된다.

차이점

  • useMemo는 함수의 연산량이 많을 때 이전의 결과값을 재사용하는 목적이고, useCallback은 함수가 재생성 되는것을 방지하기 위한 목적이다.
  • 둘다 메모리의 값을 저장해두지만, 어떤 값을 저장하느냐에 차이가 있다.
  • useCallback 은 함수 자체를 기억하고, useMemo 는 함수 실행을 통해 계산된 값을 기억한다.

끝으로

이렇게 해서 나머지 hooks 를 공부하고 있어서, 다음에는 useReduer 에 대해 알아보겠다.

profile
하루를 의미있게 살자!

0개의 댓글