[React Hooks 총정리] useCallback

혜빈·2024년 7월 8일

REACT 보충개념

목록 보기
33/48

useCallback

  • Memoization 기법으로 컴포넌트를 최적화 시켜주는 기법

Memoization

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

useMemo VS useCallback

  • useMemo는 인자로 넣어준 콜백함수가 return하는 값을 Memoization 해줌

  • useCallback은 인자로 넣어준 콜백함수 그 자체를 Memoization 해줌

  • 만약 calculate라는 함수를 Memoization 해준다면 useCallback으로 그 함수를 감싸주면 됨
const calculate = useCallback((num) => {
	return num + 1;
}, [item])

  • 함수가 필요할때마다 메모리에서 가져와서 재사용함
    (새로 생성 X)

함수형 컴포넌트

function Component() {
	const calculate = (num) => {
    	return num + 1
    };
	return <div> {value} </div>    
};
  • 렌더링 -> Component 함수 호출 -> 모든 내부 변수 초기화

useCallback으로 감싼 함수형 컴포넌트

function Component() {
	const calculate = useCallback((num) => {
    	return num + 1
    }, [item]);
	return <div> {value} </div>
};
  • 컴포넌트가 다시 렌더링 되더라도 calculate가 초기화 되는 것을 막을 수 있음

  • 컴포넌트가 맨 처음 렌더링 될 때만 함수 객체를 만들어서 calculate를 초기화 해주고, 이후에 렌더링이 될 때는 calculate 변수가 새로운 함수 객체를 다시 할당받는게 아닌 이전에 이미 할당받은 함수 객체를 계속해서 가지고 있으면서 재사용 함

  • 렌더링 -> Component 함수 호출 -> Memoization된 함수를 재사용


useCallback의 구조

  • 두개의 인자를 받음
  • 첫 번째 인자 : Memoization 해줄 callback 함수
  • 두 번째 인자 : 의존성 배열
const calculate = useCallback((num) => {
	return num + 1;
}, [item])
  • Memoization된 함수는 의존성 배열 내부의 값이 변경되지 않는 이상 다시 초기화 되지 않음

실제 코드 구현

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

function UseCallbackHook() {
  const [number, setNumber] = useState(0);

  const someFunction = () => {
    // 현재 number State 안에 어떤 숫자가 있는지 보여줌
    console.log(`someFunc: number: ${number}`);
    return;
  };

  // 첫 렌더링시, someFunction이 변경시 실행
  useEffect(() => {
    console.log("someFunction이 변경되었습니다.");
  }, [someFunction]);

  return (
    <div>
      <input
        type="number"
        value={number}
        // input 안의 숫자가 바뀔때마다 setNumber 호출해서 number State update해줌
        onChange={(e) => setNumber(e.target.value)}
      ></input>
      <br />
      <button onClick={someFunction}>Call someFunc</button>
    </div>
  );
}

export default UseCallbackHook;
  • someFunction은 함수 객체가 들어있는 메모리의 주소를 받고 있고,
    컴포넌트가 렌더링이 되어 컴포넌트가 초기화 된다면 함수 객체가 새로 만들어져서
    또 다른 메모리 공간에 저장이 되기 때문에 새로운 주소가 someFunction 변수 안에 들어가게 됨
  • useEffect의 입장에서는 someFunction의 주소값이 바뀌었으니 콜백함수를 호출함
  • 그래서 numberState를 바꿔주면 계속해서 'someFunction이 변경되었습니다'가 console에 출력됨

useCallback을 사용해보자

  • useCallback을 사용해서 useCallbackHook 컴포넌트가 렌더링 되더라도 someFunction이 바뀌지 않도록 해보기
  1. useCallback import
  2. someFunction를 useCallback으로 감싸주기

  • 아무리 useCallbackHook 컴포넌트가 다시 렌더링 되더라도 someFunction은 바뀌지 않음 !

  • 처음 렌더링 시 useEffect가 한 번 불리고, Call someFunc 버튼 클릭시 number State안에 0이 잘 들어가 있는 것을 볼 수 있음

  • number State를 증가시켜도 useState는 불리지 않음

  • 그 다음 Call someFunc 버튼을 클릭해보면 아직도 number가 0인데,
    함수를 memoization 했을 당시 number가 0이었기 때문임
    -> 두 번째 인자인 의존성 배열을 변경해주면 number가 바뀔때마다 함수가 바뀜

  • number가 바뀔때마다 useEffect가 호출됨 -> number가 바뀌면 someFunction함수가 다시 memoization 됨 -> someFunction 안에는 새로운 함수의 주소가 들어옴 -> useEffect의 의존성 배열안의 somFunction이 바뀌었으니 console이 출력이 됨

실제 코드 구현 2

UseCallbackHook2

Box

  • 박스 사이즈를 변경하면 '박스 사이즈 키우기'가 console에 출력됨

  • 그런데 Theme 변경은 박스 사이즈와 전혀 연관이 없는데도
    Change Theme 버튼 클릭시에도 '박스 사이즈 키우기'가 console에 출력됨

  • State 변화 -> 다시 렌더링 -> CreateBoxStyle 초기화 되기 때문에 일어나는 현상

  • 비효율적이기 때문에 CreateBoxStyle이 size가 바뀌었을때만 초기화가 되도록 코드 수정하자!

  • useCallback으로 CreateBoxStyle 감싸주기

  • Theme 변경해도 '박스 사이즈 키우기' 출력 안됨
  • 의존성 배열 안에 있는 size가 변경되지 않는 이상 memoization한 createBoxStyle 함수를 재사용하기 때문 -> Box 컴포넌트 안에 있는 useEffect도 불리지 않음
profile
최강 개발자를 꿈꾸는 병아리

0개의 댓글