React Hook

소히·2022년 10월 30일
0
post-thumbnail

useMemo와 useCallback를 살펴보기 전에, memoization에 대해 먼저 알아보자

Memoization

기존에 수행한 연산의 결과값을 어딘가에 저장해두고 동일한 입력이 들어오면 재활용하는 프로그래밍 기법.
📍 적절히 사용하면 중복 연산을 피할 수 있어서 애플리케이션의 성능을 최적화 할 수 있다!

function Sarah(props) {
  // ....... 로직
  
  return;
}

위와 같은 컴포넌트 함수는 React에서 랜더링이 일어날 때마다 호출이 된다.

만약, 함수가 내부적으로 복잡한 연산을 수행한다면 랜더링 될 때마다 지연이 발생할 수 있다. 이러한 문제를 해결하기 위해 memoization을 적용 시켜 줄 수 있다.

useMemo

특정 값(value)를 재사용하고자 할 때 사용한다.

아래 예시를 보면, props로 넘어온 value값을 Calculator라는 함수에 인자로 넘겨서 result 값을 구한 후, <div>엘리먼트로 출력을 하고 있다.

만약 여기서 Calculator가 내부적으로 복잡한 연산을 하는 함수라고 가정해보자.
해당 컴포넌트는 렌더링을 할 때마다 이 함수를 계속 호출할 것이고, 그 때마다 시간이 몇 초 이상 소요가 될 것이다. 결국 이 지연은 렌더링에도 영향을 미치게 될 것이며, 사용자는 앱의 로딩 속도가 느리다는 생각을 하게 될 것이다.

function Calculator({value}){

	const result = calculate(value);

	return <>
      <div>
		{result}
      </div>
  </>;
}

하지만 아래와 같이 useMemo를 사용함으로써, value의 값을 저장 해뒀다가 필요할 때 사용함으로써 Calculator 함수호출을 줄일 수 있다. 특히 value 값이 렌더링 할 때마다 계속 바뀌지 않는 경우라면 더욱 좋다.

import { useMemo } from "react";

function Calculator({value}){

	const result = useMemo(() => calculate(value), [value]);

	return <>
      <div>
		{result}
      </div>
  </>;
}

이런식으로 useMemo를 호출하여 Calculator를 감싸주면, 이전에 구축된 렌더링과 새로 구축되는 렌더링을 비교해 value값이 동일할 경우에는 이전 렌더링의 value값을 그대로 재활용 할 수 있게 된다.


useCallback

특정 결과값을 재사용하는 useMemo와 달리 useCallback은 함수의 재사용을 위해 사용한다.

아래 코드를 보면, Calculator 컴포넌트 내에 add 라는 함수가 선언되어 있다. 이 add 함수는 props로 넘어온 xy의 값을 더해 <div> 태그에 값을 출력하고 있다.

function Calculator({x, y}){

	const add = () => x + y;

	return <>
      <div>
		{add()}
      </div>
  </>;
}

useMemo와 마찬가지로 해당 컴포넌트가 리렌더링 되더라도 그 함수가 의존하고 있는 값인 xy가 바뀌지 않을 때, useCallback Hook을 사용할 수 있다. 즉. xy값이 동일하다면 다음 렌더링 때 이 함수를 다시 사용하는 것이다.

import React, { useCallback } from "react";

function Calculator({x, y}){

	const add = useCallback(() => x + y, [x, y]);

	return <>
      <div>
		{add()}
      </div>
  </>;
}

✏️ useCallback과 참조 동등성

useCallback은 참조 동등성에 의존한다. React는 JavaScript 언어로 만들어진 오픈소스 라이브러리이기 때문에 기본적으로 JavaScript의 문법을 따라간다. JavaScript에서 함수는 객체이다. 객체는 메모리에 저장할 때 값을 저장하는 게 아니라 값의 주소를 저장하기 때문에, 반환하는 값이 같을 지라도 일치연산자로 비교했을 때 false가 출력된다.

function doubleFactory(){
    return (a) => 2 * a;
}

const double1 = doubleFactory();
const double2 = doubleFactory();

double1(8); // 16
double2(8); // 16

double1 === double2;  // false
double1 === double1;  // true

double1double2는 같은 함수를 할당 했음에도 메모리 주소 값이 다르기 때문에 같다고 보지 않는다. 두개의 함수는 동일한 코드를 공유하더라도 메모리 주소가 다르기 때문에, 메모리 주소에 의한 참조 비교 시 다른 함수로 본다.

이는 React 또한 같다. React는 리렌더링 시 함수를 새로 만들어서 호출을 한다. 새로 만들어 호출된 함수는 기존의 함수와 같은 함수가 아니다. 그러나 useCallback을 이용해 함수 자체를 저장해서 다시 사용하면 함수의 메모리 주소 값을 저장했다가 다시 사용한다는 것과 같다고 볼 수 있다. 따라서 React 컴포넌트 함수 내에서 다른 함수의 인자로 넘기거나 자식 컴포넌트의 prop으로 넘길 때 예상치 못한 성능 문제를 막을 수 있다.

0개의 댓글