useCallback은 useMemo와 상당히 비슷한 함수입니다.
주로 렌더링 성능을 최적화해야 하는 상황에서 사용합니다.
이 Hook을 사용하면 만들어 놨던 함수를 재사용할 수 있습니다.
useMemo에서 생성한 Average.js 컴포넌트를 봅시다.
import { useState, useMemo } from 'react';
const getAverage = numbers => {
console.log("평균값 계산 중..");
if(numbers.length === 0) return 0;
//reduce = 누적 연산(이 경우엔 배열의 모든 요소를 하나의 값(sum)에 누적합니다)
const sum = numbers.reduce((a,b) => a+b);
return sum / numbers.length;
};
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
const onChange = e => {
setNumber(e.target.value);
};
const onInsert = e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
}
const avg = useMemo(()=>getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange}/>
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (<li key={index}>{value}</li>))}
</ul>
<p><b>평균값:</b>{avg}</p>
</div>
);
};
export default Average;
onChange와 onInsert라는 함수를 선언했지만,
이렇게 선언한다면 함수가 컴포넌트가 리렌더링될 때마다 onChange와 onInsert함수를 새로 만들어서 사용하게 됩니다.
대부분 이러한 방식에 문제가 없지만, 컴포넌트의 렌더링이 잦거나 렌더링할 컴포넌트 개수가 많아지면 이 부분을 최적화 해주는 것이 좋습니다.
useCallback을 사용하여 최적화해 봅시다.
수정된 Average.js
import { useState, useMemo, useCallback } from 'react';
const getAverage = numbers => {
console.log("평균값 계산 중..");
if(numbers.length === 0) return 0;
//reduce = 누적 연산(이 경우엔 배열의 모든 요소를 하나의 값(sum)에 누적합니다)
const sum = numbers.reduce((a,b) => a+b);
return sum / numbers.length;
};
const Average = () => {
const [list, setList] = useState([]);
const [number, setNumber] = useState('');
// 컴포넌트가 처음 렌더링될 때만 함수 생성
// => 두 번째 파라미터에 공백을 넣을 시 수정없이 계속 재활용 한다는 의미
const onChange = useCallback(e => {
setNumber(e.target.value);
}, []);
// number 혹은 list가 변경되었을 때만 함수 생성
const onInsert = useCallback(e => {
const nextList = list.concat(parseInt(number));
setList(nextList);
setNumber('');
}, [number, list]);
const avg = useMemo(()=>getAverage(list), [list]);
return (
<div>
<input value={number} onChange={onChange}/>
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (<li key={index}>{value}</li>))}
</ul>
<p><b>평균값:</b>{avg}</p>
</div>
);
};
export default Average;
useCallback의 첫 파라미터에는 생성하고 싶은 함수를 넣고
두 번째 파라미터에는 배열을 넣고,
이 배열에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야하는지 명시하면 됩니다.
onChange
처럼 비어 있는 배열을 넣게 되면 컴포넌트가 렌더링될 때 만들었던 함수를 계속해서 재사용하게 되며 onInsert
처럼 배열 안에 [**number,list]**를 넣게 되면 인풋내용이 바뀌거나 새로운 항목이 추가될 때 새로 만들어진 함수를 사용하게 됩니다.