티스토리 뷰
useCallback
useMemo 는 함수를 값처럼 사용해서 연산 최적화를 하기위해 사용한다면, useCallback 은 특정 함수를 재정의(새로 만들지 않고) 하지 않고 재사용 하기위해 사용한다.
useCallback 이 필요한 이유 !!
그러나, 전달된 prop 이 '값' (Promitive type) 이 아니라 '객체' 나 '함수' (Reference type) 일 경우엔 얕은 비교를 하기 때문에 안에 내용이 같더라도 변경되었다고 간주하여 컴포넌트를 리랜더링 하는 경우가 있다.
import React, { useCallback, useEffect, useRef, useState } from "react";
import "./styles.css";
const ComponentA = ({ data, deleteData }) => {
useEffect(() => {
console.log("ComponentA is render");
});
return (
<div>
{data.map((it) => (
<div>
<div>{it.id}</div>
<button
onClick={() => {
deleteData(it.id);
}}
>
삭제
</button>
</div>
))}
</div>
);
};
//React.memo 전달된 prop이 변경될 때만 랜더링
const ComponentB = React.memo(({ createData }) => {
useEffect(() => {
console.log("ComponentB is render");
});
return (
<div>
<button onClick={createData}>데이터 삽입</button>
</div>
);
});
export default function App() {
const [data, setData] = useState([]);
const num = useRef(0);
const createData = () => {
num.current++;
setData([...data, { id: num.current }]);
};
const deleteData = (id) => {
setData(data.filter((it) => it.id != id));
};
return (
<div className="App">
<ComponentA data={data} deleteData={deleteData} />
<ComponentB createData={createData} />
</div>
);
}
위에서, App 컴포넌트의 data state 는 ComponentB의 button(데이터 삽입) 을 누르게 되면 변경이되어 App 컴포넌트를 리랜더링 한다.
그 과정에서, createData 함수를 재선언하게 되는데, 이 때, createData 함수가 reference type 이므로 ComponentB 에서 createData 함수가 변경되었다고 판단하여 ComponentB를 리랜더링하게 된다.그러므로, App 컴포넌트가 랜더링 될 때, createData 함수가 재선언되지 않도록 만들어야 하는데, 이 때 사용하는 것이 useCallback hook 이다 !!
useCallback 사용
함수가 재선언되지 않게, 최적화를 하기 위해서 함수를 useCallback을 사용하여 감싸준다.
import React, { useCallback, useEffect, useRef, useState } from "react";
import "./styles.css";
const ComponentA = ({ data, deleteData }) => {
useEffect(() => {
console.log("ComponentA is render");
});
return (
<div>
{data.map((it) => (
<div>
<div>{it.id}</div>
<button
onClick={() => {
deleteData(it.id);
}}
>
삭제
</button>
</div>
))}
</div>
);
};
//React.memo 전달된 prop이 변경될 때만 랜더링
const ComponentB = React.memo(({ createData }) => {
useEffect(() => {
console.log("ComponentB is render");
});
return (
<div>
<button onClick={createData}>데이터 삽입</button>
</div>
);
});
export default function App() {
const [data, setData] = useState([]);
const num = useRef(0);
const createData = useCallback(() => {
num.current++;
setData((data) => [...data, { id: num.current }]);
}, []);
// const createData = () => {
// num.current++;
// setData([...data, { id: num.current }]);
// };
const deleteData = (id) => {
setData(data.filter((it) => it.id != id));
};
return (
<div className="App">
<ComponentA data={data} deleteData={deleteData} />
<ComponentB createData={createData} />
</div>
);
}
useCallback 을 사용할 때 , 2번째 인자에 defendency array 를 넘기고, setData 로 state를 초기화 해줄 때, 함수형 업데이트로 초기화를 해주어야 한다.
함수형 업데이트로 초기화를 해주어야, defenden array를 비워도 항상 최신의 state를 함수형 업데이트의 인자를 통해서 참조할 수 있게 된다.
참고
[React] 최적화 / 컴포넌트 재사용 / React.memo
비효율적인 컴포넌트 rendering setCount(10); setText("Hello"); App 컴포넌트 의 count state를 setCount로 변경하게 되면, App 컴포넌트가 랜더링 되고 자식 컴포넌트 들인 CountView 컴포넌트와 TextView 컴..
espania.tistory.com
https://espania.tistory.com/367
[React] 최적화 / 함수 재사용 / memoization / useMemo
Memoization 이미 계산 해 본 연산 결과를 기억 해 두었다가 동일한 계산을 시키면, 다시 연산하지 않고, 기억 해두 었던 데이터 를 반환 시키게 하는 방법 useMemo export default function App() { const data..
espania.tistory.com
https://codesandbox.io/s/romantic-violet-vx9erh?file=/src/App.js:0-1311
romantic-violet-vx9erh - CodeSandbox
romantic-violet-vx9erh by jins4731 using react, react-dom, react-scripts
codesandbox.io
'React' 카테고리의 다른 글
| [React] ROUTING / PAGE ROUTING (0) | 2022.05.22 |
|---|---|
| [React] 최적화 / 상태 변화 처리 / useReducer (0) | 2022.05.21 |
| [React] 최적화 / 함수 재사용 / memoization / useMemo (0) | 2022.05.08 |
| [React] 최적화 / 컴포넌트 재사용 / React.memo (0) | 2022.05.02 |
| [React] 실습 / API 호출 / useEffect / Mount (0) | 2022.05.02 |