const cachedFn = useCallback(Fn, dep);
Fn :
dep:
Object.is 비교 알고리즘을 사용NOTE
console.log(+0 === -0); // true console.log(Object.is(+0, -0)); // false ❗ console.log(NaN === NaN); // false console.log(Object.is(NaN, NaN)); // true ✅
import React, { useCallback, useState } from "react";
const Child = React.memo(
({ onClick, childNum }: { onClick: () => void; childNum: number }) => {
console.log(`🔁 Child 리렌더링됨 ${childNum}`);
return <button onClick={onClick}>Click me</button>;
}
);
export default function Parent() {
const [count, setCount] = useState(0);
const handleClick = () => {
console.log("clicked");
};
const cachedhandleClick = useCallback(handleClick, []);
return (
<div>
<h1>Count: {count}</h1>
<Child onClick={cachedhandleClick} childNum={1} />
<Child onClick={handleClick} childNum={2} />
<button onClick={() => setCount((c) => c + 1)}>Increase Count</button>
</div>
);
}
리액트의 렌더링 조건
1. 상태가 변화하면 리렌더
2. prop가 변화하면 리렌더
3. 부모컴포넌트가 변하면 자식 컴포넌트도 리렌더!
이 조건을 항상 기억하고 쓰면 useCallback을 통한 최적화 가능
// counterStore.ts
import { create } from "zustand";
interface Counter {
count: number;
increase: () => void;
}
export const useCounterStore = create<Counter>((set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
}));
import React from "react";
import { useCounterStore } from "../store/useCounterStore";
const Child = React.memo(({ childNum }: { childNum: number }) => {
console.log(`🔁 Child 리렌더링됨 ${childNum}`);
const increase = useCounterStore((state) => state.increase);
return (
<div>
<button onClick={increase}>Increase Count Btn (Child)</button>
</div>
);
});
function ExampleZustand() {
console.log(`🔁 Parent 리렌더링됨`);
// const [count, setCount] = useState(0);
const { count } = useCounterStore();
return (
<div>
<h1>Count: {count}</h1>
<Child childNum={2} />
</div>
);
}
export default ExampleZustand;