iOS 개발자가 React 배우기: React와 성능 (3) (with useCallback)

SteadySlower·2024년 11월 16일
0

React JS

목록 보기
9/13

지난 포스팅 2개에서 useMemo와 React.memo를 활용해서 성능 최적화에 대해서 배웠다. 이번 포스팅은 내가 생각하기에는 앞선 2개의 기능 보다 그렇게 많이 사용할 것 같지는 않지만 비슷한 계열의 내용이기에 함께 포스팅한다.

하지만 useCallback이 중요하지 않다는 것은 아니다. useCallback의 작동 원리를 통해서 우리는 js의 오브젝트와 함수가 어떻게 작동하는지 원리를 알아볼 수 있다.

js에서 함수는 객체이고 react component는 re-rendering될 때 다시 실행된다.

js에서 함수는 객체 (오브젝트)이다. 그리고 리액트 컴포넌트는 리랜더링이 될 때마다 다시 실행된다. 앞으로 "함수" (큰따옴표)는 리액트 컴포넌트를 '함수'(작은 따옴표)는 리액트 컴포넌트 안에 변수에 할당된 함수를 의미한다.

즉 리액트 컴포넌트라는 "함수"안에 변수에 할당된 '함수'는 해당 "함수"가 실행되면 다시 할당된다. 즉 '함수' 오브젝트의 메모리 주소 값이 달라진다는 것이다.

useCallback은 리액트 컴포넌트 "함수"가 실행될 때, 새로운 '함수' 오브젝트를 할당하지 않고 기존의 '함수' 오브젝트를 할당되도록 하는 기능을 한다.

useCallback 예시

아래 예시 코드를 보자. 아래 예시 코드는 num1, num2, num3를 각각 1씩 더하는 버튼들과 num1, num2, num3의 값을 alert로 출력해주는 버튼 3개로 구성되어 있다.

state들이 변경되면 해당 component "함수"가 재실행되는데, 이 때 component안에 변수에 할당되어 있는 '함수' 객체가 재할당된다. 이 때 해당 alert '함수' 안에 있는 num1, num2, num3 값은 현재 state에 있는 값을 캡쳐해서 가지고 있게 된다.

하지만 alert '함수'들이 매번 새로운 값을 캡쳐하고 새롭게 할당이 될 필요는 없다. 각각 alert로 출력할 값이 바뀌었을때만 새로운 '함수'를 할당하면 된다.

export default function BlogComponent() {
    const [num1, setNum1] = useState(0);
    const [num2, setNum2] = useState(0);
    const [num3, setNum3] = useState(0);

    const alertNum1 = () => {
        alert(num1);
    };

    const alertNum2 = () => {
        alert(num2);
    };

    const alertNum3 = () => {
        alert(num3);
    };

    return (
        <div>
            <button onClick={() => setNum1((prev) => prev + 1)}>
                num1 + 1
            </button>
            <button onClick={() => setNum2((prev) => prev + 1)}>
                num2 + 1
            </button>
            <button onClick={() => setNum3((prev) => prev + 1)}>
                num3 + 1
            </button>
            <button onClick={alertNum1}>alert num1</button>
            <button onClick={alertNum2}>alert num2</button>
            <button onClick={alertNum3}>alert num3</button>
        </div>
    );
}

그런 경우 아래처럼 useCallback을 사용하면 된다. useCallback을 사용하는 법은 useEffect를 사용하는 것과 비슷하다. 첫번째 인자로 메모이제이션할 '함수'를 전달한다. 그리고 두번째 인자로 dependency (어떤 값이 바뀌었을 때 재할당할 것인지)를 전달하면 된다.

이렇게 할 경우 필요한 state가 바뀌었을 때만 값을 '함수'가 재할당되므로 성능을 개선할 수 있게 된다.

주의할 점은 dependency를 아무것도 적지 않게 되면 아무리 state 값을 바꾸더라도 '함수'는 새로운 값을 캡쳐하지 않기 때문에 alert에 바뀐 값이 출력되지 않는다.

export default function BlogComponent() {
    const [num1, setNum1] = useState(0);
    const [num2, setNum2] = useState(0);
    const [num3, setNum3] = useState(0);

    const alertNum1 = useCallback(() => {
        alert(num1)
    }, [num1])

    const alertNum2 = useCallback(() => {
        alert(num2)
    }, [num2])

    const alertNum3 = useCallback(() => {
        alert(num3)
    }, [num3])

    return (
        <div>
            <button onClick={() => setNum1((prev) => prev + 1)}>
                num1 + 1
            </button>
            <button onClick={() => setNum2((prev) => prev + 1)}>
                num2 + 1
            </button>
            <button onClick={() => setNum3((prev) => prev + 1)}>
                num3 + 1
            </button>
            <button onClick={alertNum1}>alert num1</button>
            <button onClick={alertNum2}>alert num2</button>
            <button onClick={alertNum3}>alert num3</button>
        </div>
    );
}
profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글