useCallback은 useMemo와 상당히 비슷한 함수이다.
주로 렌더링 성능을 최적화해야 하는 상황에서사용한다.
이 Hook을 사용하면 이벤트 핸들러 함수를 필요할 때만 생성할 수 있다.
Average.js파일로 비교해 보자.
import React, { useState } from "react";
const getAverage = (numbers) => {
console.log("평균값 계산 중");
if (numbers.length === 0) return 0;
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("");
};
return (
<div>
<input value={number} onChange={onChange} />
<button onClick={onInsert}>등록</button>
<ul>
{list.map((value, index) => (
<li key={index}>{value}</li>
))}
</ul>
<div>
<b>평균값:</b> {getAverage(list)}
</div>
</div>
);
};
export default Average;
onChange와 onInsert라는 함수를 따로 선언하면서 컴포넌트가 리렌더링 될 때마다 함수가 새로 생성된다.
이런 경우 렌더링해야 할 컴포넌트의 개수가 많아지면 최적화를 진행하는 것이 좋다.
이럴 때 useCallback을 사용한다.
import React, { useState, useMemo, useCallback } from "react";
const getAverage = (numbers) => {
console.log("평균값 계산 중");
if (numbers.length === 0) return 0;
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);
}, []); // 컴포넌트가 처음 렌더링 될 때만 함수 생성
const onInsert = useCallback(() => {
const nextList = list.concat(parseInt(number));
setlist(nextList);
setNumber("");
}, [number, list]); // 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>
<div>
<b>평균값:</b> {avg}
</div>
</div>
);
};
export default Average;
useCallback의 첫 번째 파라미터에는 생성하고 싶은 함수를 넣고, 두 번째 파라미터에는 배열을 넣으면 된다.
이 배열에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야 하는지 명시해야 한다.
해당 배열이 비어있으면 컴포넌트가 렌더링 될 때 단 한 번만 함수가 생서오디며
배열 안에 내용을 넣게 되면 인풋 내용이 바뀌거나 새로운 항목이 추가될 때마다 함수가 생성된다.
함수 내부에서 상태 값에 의존해야 할 때는 그 값을 두 번째 파라미터 안에 포함시켜 주어야 한다.
onChange의 경우에는 기존 값을 조회하지 않고 바로 설정만 하기 때문에 배열이 비어 있어도 상관 없지만 onInsert의 경우 기존의 값을 조회해서 리스트를 생성하기 때문에 배열 안에 값을 꼭 넣어 주어야 하낟.