본문 바로가기

웹 개발/React

React) Hooks : useCallback 으로 렌더링 성능 최적화하기

Hooks : useCallback


useCallback은 주로 렌더링이 자주 되는 상황에서 성능 최적화를 위해 사용됩니다. 

컴포넌트는 랜더링될때마다 컴포넌트 내부의 함수들을 모두 새로 생성하는데 useCallback을 사용하면 useMemo에서 이전에 계산된 값을 재사용하여 불필요한 연산을 피했던 것 처럼, 생성해 둔 함수를 재사용해 불필요한 함수 생성을 줄일 수 있습니다. 

컴포넌트 렌더링이 자주 발생하거나 렌더링 해야 할 컴포넌트가 많은 경우 이를 이용해 성능 최적화를 해주는 것이 좋습니다. 

const example = useCallback(() => {생성할 함수...},[배열]);

두번째 파라미터로 주어지는 배열에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야 하는지 알려주는 것입니다. 


  • example source code

import React, { useState, useMemo, useCallback } from 'react';

const getAverage = list => {
    console.log('평균값 계산 중...');
    if (list.length===0) return 0;
    const sum = list.reduce((a,b) => a+b);
    return sum/list.length;
}

const Average = () => {
    const [list,setList] = useState([]);
    const [number, setNumber] = useState('');

    // 처음 렌더링될 때만 함수 생성 
    const handleChange = useCallback( e => {setNumber(e.target.value)}, []);
    const handleKeyPress = e => {
        if (e.key === 'Enter') {
            handleClick();
        }
    }
    // number or list가 바뀌었을 때만 함수 생성 
    const handleClick = useCallback(e => {
        const newList = list.concat(parseInt(number));
        setList(newList);
        setNumber('');
    },[number,list]);

    const avg = useMemo(() => getAverage(list), [list]);
    
    
    return(
        <div>
            <h1>Hooks practice</h1>
            <input 
                value={number} 
                onChange={handleChange}
                onKeyPress={handleKeyPress}
            />
            <button onClick={handleClick}>register</button>
            <ul>
                {list.map((item,i) => <li key={i}>{item}</li>)}
            </ul>
            <div>average: {avg}</div>
        </div>
    );
}

export default Average;

다음 코드에서 useCallback을 사용하지 않았다면 컴포넌트가 랜더링 될 때마다 handleClick와 handleChange 함수가 새로 생성됩니다.

 

그러나 useCallback을 사용하여 handleChange는 다른 변화에 영향 받지 않고 항상 그대로 사용되기 때문에 두번째 파라미터에 아무것도 전달하지 않습니다. 따라서 처음 렌더링 될 때에만 함수를 생성하게 됩니다. 

const handleChange = useCallback( e => {setNumber(e.target.value)}, []);

handleClick은 사용자가 입력한 number와 그 값이 추가된 list가 변화할 때마다 달라지는 함수이기 때문에 number와 list를 두번쩨 파라미터의 요소로 전달합니다. 따라서 handleClick 함수는 number과 list가 바뀔 때만 함수가 새롭게 생성되고, 이렇게 새로 생성된 함수를 사용할 수 있습니다. 

const handleClick = useCallback(e => {
        const newList = list.concat(parseInt(number));
        setList(newList);
        setNumber('');
    },[number,list]);

References

  • 리액트를 다루는 기술 (김민준)