useCallback은 리액트의 렌더링 성능을 위해 제공되는 훅이다.
컴포넌트가 렌더링될 때마다 새로운 함수를 생성해서 자식 컴포넌트의 속성값으로 입력하는 경우가 많다. 이것은 부모 컴포넌트가 렌더링될 때마다 자식 컴포넌트의 속성값으로 새로운 함수가 입력되기 때문에 불필요한 렌더링이 발생한다는 문제점이 있다.
리액트에서는 이 문제를 해결하기 위해 useCallback 훅을 제공한다.
>사용법
import React, { useState, useCallback } from "react";
export default function App() {
const [name, setName] = useState("");
const [age, setAge] = useState(0);
const [v1, setV1] = useState(0);
const onSave = useCallback(() => saveToServer(name, age), [name, age]);
// 자식 컴포넌트에게 속성으로 내려줄 함수를 useCallback 훅의 첫 번째 매개변수로 입력하고 두 번째 매개변수로 의존성 배열을 넣어준다.
// 의존성 배열이 변경되지 않으면 이전에 생성한 함수가 재사용된다. 따라서 name과 age값이 변경되지 않으면 UserEdit 컴포넌트의 onSave 속성값으로 항상 같은 함수가 전달된다.
return (
<div>
<p>{`name is ${name}`}</p>
<p>{`age is ${age}`}</p>
<UserEdit onSave={onSave} setName={setName} setAge={setAge} />
<UserEdit2
onSave={() => saveToServer(name, age)}
setName={setName}
setAge={setAge}
/>
// 기존에 이런식 함수를 속성값으로 내려줬을 것이다. 이렇게 되면 부모컴포넌트가 렌더링될 때마다 새로운 함수가 입력되기 때문에 속성값은 항상 변경되고 불필요한 렌더링이 발생한다.
<p>{`v1: ${v1}`}</p>
<button onClick={() => setV1(Math.random())}>v1 수정</button>
</div>
);
}
const UserEdit = React.memo(function ({ onSave, setName, setAge }) {
console.log("UserEdit render");
return null;
});
const UserEdit2 = React.memo(function ({ onSave, setName, setAge }) {
console.log("UserEdit2 render");
return null;
});
function saveToServer(name, age) {}
useMemo 훅은 계산량이 많은 함수의 반환값을 재활용하는 용도로 사용된다.
>사용법
import React, { useMemo, useState } from "react";
export default function App() {
const [v1, setV1] = useState(0);
const [v2, setV2] = useState(0);
const [v3, setV3] = useState(0);
const value = useMemo(() => runExpensiveJob(v1, v2), [v1, v2]);
return (
<>
<p>{`value is ${value}`}</p>
<button
onClick={() => {
setV1(Math.random());
setV2(Math.random());
}}
>
v1/v2 수정
</button>
<p>{`v3 is ${v3}`}</p>
<button onClick={() => setV3(Math.random())}>v3 수정</button>
</>
);
}
function runExpensiveJob(v1, v2) {
console.log("runExpensiveJob is called");
// run something too expensive
// 계산이 많고 복잡한 로직이 있다고 가정한다.
return v1 + v2;
}