useCallback
useCallback
์ ๋ฆฌ๋ ๋๋ง ๊ฐ์ ํจ์ ์ ์๋ฅผ ์บ์ฑํด ์ฃผ๋ React Hook์
๋๋ค.
const cachedFn = useCallback(fn, dependencies)
๋ ํผ๋ฐ์ค
useCallback(fn, dependencies)
๋ฆฌ๋ ๋๋ง ๊ฐ์ ํจ์ ์ ์๋ฅผ ์บ์ฑํ๋ ค๋ฉด ์ปดํฌ๋ํธ์ ์ต์๋จ์์ useCallback
์ ํธ์ถํ์ธ์.
import { useCallback } from 'react';
export default function ProductPage({ productId, referrer, theme }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]);
์๋์์ ๋ ๋ง์ ์์๋ฅผ ํ์ธํด๋ณด์ธ์.
๋งค๊ฐ๋ณ์
-
fn
: ์บ์ฑํ ํจ์ซ๊ฐ์ ๋๋ค. ์ด ํจ์๋ ์ด๋ค ์ธ์๋ ๋ฐํ๊ฐ๋ ๊ฐ์ง ์ ์์ต๋๋ค. React๋ ์ฒซ ๋ ๋๋ง์์ ์ด ํจ์๋ฅผ ๋ฐํํฉ๋๋ค. (ํธ์ถํ๋ ๊ฒ์ด ์๋๋๋ค!) ๋ค์ ๋ ๋๋ง์์dependencies
๊ฐ์ด ์ด์ ๊ณผ ๊ฐ๋ค๋ฉด React๋ ๊ฐ์ ํจ์๋ฅผ ๋ค์ ๋ฐํํฉ๋๋ค. ๋ฐ๋๋กdependencies
๊ฐ์ด ๋ณ๊ฒฝ๋์๋ค๋ฉด ์ด๋ฒ ๋ ๋๋ง์์ ์ ๋ฌํ ํจ์๋ฅผ ๋ฐํํ๊ณ ๋์ค์ ์ฌ์ฌ์ฉํ ์ ์๋๋ก ์ด๋ฅผ ์ ์ฅํฉ๋๋ค. React๋ ํจ์๋ฅผ ํธ์ถํ์ง ์์ต๋๋ค. ์ด ํจ์๋ ํธ์ถ ์ฌ๋ถ์ ํธ์ถ ์์ ์ ๊ฐ๋ฐ์๊ฐ ๊ฒฐ์ ํ ์ ์๋๋ก ๋ฐํ๋ฉ๋๋ค. -
dependencies
:fn
๋ด์์ ์ฐธ์กฐ๋๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ์ ๋ชฉ๋ก์ ๋๋ค. ๋ฐ์ํ ๊ฐ์ props์ state, ๊ทธ๋ฆฌ๊ณ ์ปดํฌ๋ํธ ์์์ ์ง์ ์ ์ธ๋ ๋ชจ๋ ๋ณ์์ ํจ์๋ฅผ ํฌํจํฉ๋๋ค. ๋ฆฐํฐ๊ฐ React๋ฅผ ์ํ ์ค์ ์ผ๋ก ๊ตฌ์ฑ๋์ด ์๋ค๋ฉด ๋ชจ๋ ๋ฐ์ํ ๊ฐ์ด ์์กด์ฑ์ผ๋ก ์ฌ๋ฐ๋ฅด๊ฒ ๋ช ์๋์ด ์๋์ง ๊ฒ์ฆํฉ๋๋ค. ์์กด์ฑ ๋ชฉ๋ก์ ํญ๋ชฉ ์๊ฐ ์ผ์ ํด์ผ ํ๋ฉฐ[dep1, dep2, dep3]
์ฒ๋ผ ์ธ๋ผ์ธ์ผ๋ก ์์ฑํด์ผ ํฉ๋๋ค. React๋Object.is
๋น๊ต ์๊ณ ๋ฆฌ์ฆ์ ์ด์ฉํด ๊ฐ ์์กด์ฑ์ ์ด์ ๊ฐ๊ณผ ๋น๊ตํฉ๋๋ค.
๋ฐํ๊ฐ
์ต์ด ๋ ๋๋ง์์๋ useCallback
์ ์ ๋ฌํ fn
ํจ์๋ฅผ ๊ทธ๋๋ก ๋ฐํํฉ๋๋ค.
ํ์ ๋ ๋๋ง์์๋ ์ด์ ๋ ๋๋ง์์ ์ด๋ฏธ ์ ์ฅํด ๋์๋ fn
ํจ์๋ฅผ ๋ฐํํ๊ฑฐ๋ (์์กด์ฑ์ด ๋ณํ์ง ์์์ ๋), ํ์ฌ ๋ ๋๋ง ์ค์ ์ ๋ฌํ fn
ํจ์๋ฅผ ๊ทธ๋๋ก ๋ฐํํฉ๋๋ค.
์ฃผ์์ฌํญ
useCallback
์ Hook์ด๋ฏ๋ก, ์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ ๋๋ ์ปค์คํ Hook์์๋ง ํธ์ถํ ์ ์์ต๋๋ค. ๋ฐ๋ณต๋ฌธ์ด๋ ์กฐ๊ฑด๋ฌธ ๋ด์์ ํธ์ถํ ์ ์์ต๋๋ค. ์ด ์์ ์ด ํ์ํ๋ค๋ฉด ์๋ก์ด ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌํด์ state๋ฅผ ์ ์ปดํฌ๋๋ก ์ฎ๊ธฐ์ธ์.- React๋ ํน๋ณํ ์ด์ ๊ฐ ์๋ ํ ์บ์ ๋ ํจ์๋ฅผ ์ญ์ ํ์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๊ฐ๋ฐ ํ๊ฒฝ์์๋ ์ปดํฌ๋ํธ ํ์ผ์ ํธ์งํ ๋ React๊ฐ ์บ์๋ฅผ ์ญ์ ํฉ๋๋ค. ๊ฐ๋ฐ ํ๊ฒฝ๊ณผ ํ๋ก๋์
ํ๊ฒฝ ๋ชจ๋์์, ์ด๊ธฐ ๋ง์ดํธ ์ค์ ์ปดํฌ๋ํธ๊ฐ ์ผ์ ์ค๋จ๋๋ฉด React๋ ์บ์๋ฅผ ์ญ์ ํฉ๋๋ค. ์์ผ๋ก React๋ ์บ์ ์ญ์ ๋ฅผ ํ์ฉํ๋ ๋ ๋ง์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, React์ ๊ฐ์ํ๋ ๋ชฉ๋ก์ ๋ํ ๋นํธ์ธ ์ง์์ด ์ถ๊ฐํ๋ค๋ฉด, ๊ฐ์ํ๋ ํ
์ด๋ธ ๋ทฐํฌํธ์์ ์คํฌ๋กค ๋ฐ์ ํญ๋ชฉ์ ๋ํด ์บ์๋ฅผ ์ญ์ ํ๋๊ฒ์ด ์ ์ ํ ๊ฒ ์
๋๋ค. ์ด๋
useCallback
์ ์ฑ๋ฅ ์ต์ ํ ๋ฐฉ๋ฒ์ผ๋ก ์์กดํ๋ ๊ฒฝ์ฐ์ ๊ฐ๋ฐ์์ ์์๊ณผ ์ผ์นํด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์๋ค๋ฉด state ๋ณ์ ๋ ref๊ฐ ๋ ์ ์ ํ ์ ์์ต๋๋ค.
์ฉ๋ฒ
์ปดํฌ๋ํธ์ ๋ฆฌ๋ ๋๋ง ๊ฑด๋๋ฐ๊ธฐ
๋ ๋๋ง ์ฑ๋ฅ์ ์ต์ ํํ ๋ ์์ ์ปดํฌ๋ํธ์ ๋๊ธฐ๋ ํจ์๋ฅผ ์บ์ฑํ ํ์๊ฐ ์์ต๋๋ค. ๋จผ์ ์ด ์์ ์ ์ํํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๊ตฌ๋ฌธ์ ์ดํด๋ณธ ๋ค์ ์ด๋ค ๊ฒฝ์ฐ์ ์ ์ฉํ์ง ์์๋ณด๊ฒ ์ต๋๋ค.
์ปดํฌ๋ํธ์ ๋ฆฌ๋ ๋๋ง ๊ฐ์ ํจ์๋ฅผ ์บ์ฑํ๋ ค๋ฉด ํจ์ ์ ์๋ฅผ useCallback
Hook์ผ๋ก ๊ฐ์ธ์ธ์.
import { useCallback } from 'react';
function ProductPage({ productId, referrer, theme }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]);
// ...
useCallback
์๊ฒ ๋ ๊ฐ์ง๋ฅผ ์ ๋ฌํด์ผ ํฉ๋๋ค
- ๋ฆฌ๋ ๋๋ง ๊ฐ์ ์บ์ฑํ ํจ์ ์ ์
- ํจ์์์ ์ฌ์ฉ๋๋ ์ปดํฌ๋ํธ ๋ด๋ถ์ ๋ชจ๋ ๊ฐ์ ํฌํจํ๊ณ ์๋ ์์กด์ฑ ๋ชฉ๋ก
์ต์ด ๋ ๋๋ง์์ useCallback
์ผ๋ก๋ถํฐ ๋ฐํ๋๋ ํจ์๋ ํธ์ถ์์ ์ ๋ฌํ ํจ์์
๋๋ค.
์ด์ด์ง๋ ๋ ๋๋ง์์ React๋ ์์กด์ฑ์ ์ด์ ๋ ๋๋ง์์ ์ ๋ฌํ ์์กด์ฑ๊ณผ ๋น๊ตํฉ๋๋ค. ์์กด์ฑ ์ค ํ๋๋ผ๋ ๋ณํ ๊ฐ์ด ์๋ค๋ฉด(Object.is
๋ก ๋น๊ต), useCallback
์ ์ ๊ณผ ๋๊ฐ์ ํจ์๋ฅผ ๋ฐํํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด useCallback
์ ์ด๋ฒ ๋ ๋๋ง์์ ์ ๋ฌํ ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.
๋ค์ ๋งํ๋ฉด, useCallback
์ ์์กด์ฑ์ด ๋ณํ๊ธฐ ์ ๊น์ง ๋ฆฌ๋ ๋๋ง ๊ฐ์ ํจ์๋ฅผ ์บ์ฑํฉ๋๋ค.
์ด ๊ธฐ๋ฅ์ด ์ธ์ ์ ์ฉํ์ง ์์๋ฅผ ํตํด ์ดํด๋ณด๊ฒ ์ต๋๋ค.
handleSubmit
ํจ์๋ฅผ ProductPage
์์ ShippingForm
์ปดํฌ๋ํธ๋ก ์ ๋ฌํ๋ค๊ณ ๊ฐ์ ํด ๋ด
์๋ค.
function ProductPage({ productId, referrer, theme }) {
// ...
return (
<div className={theme}>
<ShippingForm onSubmit={handleSubmit} />
</div>
);
theme
prop์ ํ ๊ธ ํ๋ฉด ์ฑ์ด ์ ์ ๋ฉ์ถ๋ค๋ ๊ฒ์ ์๊ฒ ๋์๋๋ฐ, JSX์์ <ShippingForm />
์ ์ ๊ฑฐํ๋ฉด ์ฑ์ด ๋นจ๋ผ์ง ๊ฒ์ฒ๋ผ ๋๊ปด์ง๋๋ค. ์ด๊ฒ์ <ShippingForm />
์ปดํฌ๋ํธ์ ์ต์ ํ๋ฅผ ์๋ํด ๋ณผ ๊ฐ์น๊ฐ ์๋ค๋ ๊ฒ์ ๋ํ๋
๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก, ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋งํ ๋ React๋ ์ด๊ฒ์ ๋ชจ๋ ์์์ ์ฌ๊ท์ ์ผ๋ก ์ฌ๋๋๋งํฉ๋๋ค. ์ด๊ฒ์ด ProductPage
๊ฐ ๋ค๋ฅธ theme
๊ฐ์ผ๋ก ๋ฆฌ๋ ๋๋ง ํ ๋, ShippingForm
์ปดํฌ๋ํธ ๋ํ ๋ฆฌ๋ ๋๋ง ํ๋ ์ด์ ์
๋๋ค. ์ด ๊ฒ์ ๋ฆฌ๋ ๋๋ง์ ๋ง์ ๊ณ์ฐ์ ์๊ตฌํ์ง ์๋ ์ปดํฌ๋ํธ์์๋ ๊ด์ฐฎ์ต๋๋ค. ํ์ง๋ง ๋ฆฌ๋ ๋๋ง์ด ๋๋ฆฐ ๊ฒ์ ํ์ธํ ๊ฒฝ์ฐ, ShippingForm
์ memo
๋ก ๊ฐ์ธ๋ฉด ๋ง์ง๋ง ๋ ๋๋ง๊ณผ ๋์ผํ props์ผ ๋ ๋ฆฌ๋ ๋๋ง์ ๊ฑด๋๋ฐ๋๋ก ํ ์ ์์ต๋๋ค.
import { memo } from 'react';
const ShippingForm = memo(function ShippingForm({ onSubmit }) {
// ...
});
์ด๋ ๊ฒ ๋ณ๊ฒฝํ ShippingForm
์ ๋ชจ๋ props๊ฐ ๋ง์ง๋ง ๋ ๋๋ง๊ณผ ๊ฐ๋ค๋ฉด ๋ฆฌ๋ ๋๋ง์ ๊ฑด๋๋๋๋ค. ์ฌ๊ธฐ๊ฐ ํจ์ ์บ์ฑ์ด ์ค์ํด์ง๋ ์๊ฐ์
๋๋ค! useCallback
์์ด handleSubmit
์ ์ ์ํ๋ค๊ณ ๊ฐ์ ํด ๋ด
์๋ค.
function ProductPage({ productId, referrer, theme }) {
// theme์ด ๋ฐ๋๋๋ง๋ค ๋ค๋ฅธ ํจ์๊ฐ ๋ ๊ฒ์
๋๋ค...
function handleSubmit(orderDetails) {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}
return (
<div className={theme}>
{/* ... ๊ทธ๋์ ShippingForm์ props๋ ๊ฐ์ ๊ฐ์ด ์๋๋ฏ๋ก ๋งค๋ฒ ๋ฆฌ๋ ๋๋ง ํ ๊ฒ์
๋๋ค.*/}
<ShippingForm onSubmit={handleSubmit} />
</div>
);
}
์๋ฐ์คํฌ๋ฆฝํธ์์ function () {}
๋ () => {}
์ ํญ์ ๋ค๋ฅธ ํจ์๋ฅผ ์์ฑํฉ๋๋ค. ์ด๊ฒ์ {}
๊ฐ์ฒด ๋ฆฌํฐ๋ด์ด ํญ์ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๋ฐฉ์๊ณผ ์ ์ฌํฉ๋๋ค. ๋ณดํต์ ๊ฒฝ์ฐ์๋ ๋ฌธ์ ๊ฐ ๋์ง ์์ง๋ง, ์ฌ๊ธฐ์๋ ShippingForm
props๋ ์ ๋ ๊ฐ์์ง ์ ์๊ณ memo
์ต์ ํ๋ ๋์ํ์ง ์์ ๊ฒ์ด๋ผ๋ ๊ฑธ ์๋ฏธํฉ๋๋ค. ์ฌ๊ธฐ์ useCallback
์ด ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค.
function ProductPage({ productId, referrer, theme }) {
// React์๊ฒ ๋ฆฌ๋ ๋๋ง ๊ฐ์ ํจ์๋ฅผ ์บ์ฑํ๋๋ก ์์ฒญํฉ๋๋ค...
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]); // ...์ด ์์กด์ฑ์ด ๋ณ๊ฒฝ๋์ง ์๋ ํ...
return (
<div className={theme}>
{/* ...ShippingForm์ ๊ฐ์ props๋ฅผ ๋ฐ๊ฒ ๋๊ณ ๋ฆฌ๋ ๋๋ง์ ๊ฑด๋๋ธ ์ ์์ต๋๋ค.*/}
<ShippingForm onSubmit={handleSubmit} />
</div>
);
}
handleSubmit
์ useCallback
์ผ๋ก ๊ฐ์์ผ๋ก์จ ๋ฆฌ๋ ๋๋ง ๊ฐ์ ์ด๊ฒ์ด (์์กด์ฑ์ด ๋ณ๊ฒฝ๋๊ธฐ ์ ๊น์ง๋) ๊ฐ์ ํจ์๋ผ๋ ๊ฒ์ ๋ณด์ฅํฉ๋๋ค. ํน๋ณํ ์ด์ ๊ฐ ์๋ค๋ฉด ํจ์๋ฅผ ๊ผญ useCallback
์ผ๋ก ๊ฐ์ ํ์๋ ์์ต๋๋ค. ์ด ์์์์์ ์ด์ ๋ โmemoโ๋ก ๊ฐ์ผ ์ปดํฌ๋ํธ์ ์ ๋ฌํ๊ธฐ ๋๋ฌธ์ ํด๋น ํจ์๊ฐ ๋ฆฌ๋ ๋๋ง์ ๊ฑด๋๋ธ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. useCallback
์ด ํ์ํ ๋ค๋ฅธ ์ด์ ๋ ์ด ํ์ด์ง์ ๋ท๋ถ๋ถ์์ ์ค๋ช
ํ๊ฒ ์ต๋๋ค.
Deep Dive
useMemo
๊ฐ useCallback
๊ณผ ํจ๊ป ์ฐ์ด๋ ๊ฒ์ ์์ฃผ ๋ดค์ ๊ฒ์
๋๋ค. ๋ hook์ ๋ชจ๋ ์์ ์ปดํฌ๋ํธ๋ฅผ ์ต์ ํํ ๋ ์ ์ฉํฉ๋๋ค. ๋ฌด์ธ๊ฐ๋ฅผ ์ ๋ฌํ ๋ memoization(๋ค๋ฅธ ๋ง๋ก๋ ์บ์ฑ)์ ํ ์ ์๋๋ก ํด์ค๋๋ค.
import { useMemo, useCallback } from 'react';
function ProductPage({ productId, referrer }) {
const product = useData('/product/' + productId);
const requirements = useMemo(() => { // ํจ์๋ฅผ ํธ์ถํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํฉ๋๋ค.
return computeRequirements(product);
}, [product]);
const handleSubmit = useCallback((orderDetails) => { // ํจ์ ์์ฒด๋ฅผ ์บ์ฑํฉ๋๋ค.
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]);
return (
<div className={theme}>
<ShippingForm requirements={requirements} onSubmit={handleSubmit} />
</div>
);
}
์ฐจ์ด์ ์ ๋ฌด์์ ์บ์ฑํ๋์ง ์ ๋๋ค.
useMemo
๋ ํธ์ถํ ํจ์์ ๊ฒฐ๊ณผ๊ฐ์ ์บ์ฑํฉ๋๋ค. ์ด ์์์์๋computeRequirements(product)
ํจ์ ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํด์product
๊ฐ ๋ณ๊ฒฝ๋์ง ์๋ ํ ์ด ๊ฒฐ๊ณผ๊ฐ์ด ๋ณ๊ฒฝ๋์ง ์๋๋ก ํฉ๋๋ค. ์ด๊ฒ์ ๋ถํ์ํ๊ฒShippingForm
์ ๋ฆฌ๋ ๋๋งํ์ง ์๊ณrequirements
๊ฐ์ฒด๋ฅผ ๋๊ฒจ์ค ์ ์๋๋ก ํด์ค๋๋ค. ํ์ํ ๋ React๋ ๋ ๋๋ง ์ค์ ๋๊ฒจ์ฃผ์๋ ํจ์๋ฅผ ํธ์ถํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ๊ณ์ฐํฉ๋๋ค.useCallback
์ ํจ์ ์์ฒด๋ฅผ ์บ์ฑํฉ๋๋ค.useMemo
์ ๋ฌ๋ฆฌ, ์ ๋ฌํ ํจ์๋ฅผ ํธ์ถํ์ง ์์ต๋๋ค. ๊ทธ ๋์ , ์ ๋ฌํ ํจ์๋ฅผ ์บ์ฑํด์productId
๋referrer
์ด ๋ณํ์ง ์์ผ๋ฉดhandleSubmit
์์ฒด๊ฐ ๋ณํ์ง ์๋๋ก ํฉ๋๋ค. ์ด๊ฒ์ ๋ถํ์ํ๊ฒShippingForm
์ ๋ฆฌ๋ ๋๋งํ์ง ์๊ณhandleSubmit
ํจ์๋ฅผ ์ ๋ฌํ ์ ์๋๋ก ํด์ค๋๋ค. ํจ์์ ์ฝ๋๋ ์ฌ์ฉ์๊ฐ ํผ์ ์ ์ถํ๊ธฐ ์ ๊น์ง ์คํ๋์ง ์์ ๊ฒ์ ๋๋ค.
์ด๋ฏธ useMemo
์ ์ต์ํ๋ค๋ฉด useCallback
์ ๋ค์๊ณผ ๊ฐ์ด ์๊ฐํ๋ ๊ฒ์ด ๋์์ด ๋ ์ ์์ต๋๋ค.
// (React ๋ด๋ถ์) ๊ฐ๋จํ ๊ตฌํ
function useCallback(fn, dependencies) {
return useMemo(() => fn, dependencies);
}
useMemo
์ useCallback
์ ์ฐจ์ด์ ์ ๋ํด ๋ ์์๋ณด์ธ์.
Deep Dive
์ด ์ฌ์ดํธ์ฒ๋ผ ๋๋ถ๋ถ์ ์ํธ์์ฉ์ด (ํ์ด์ง ์ ์ฒด๋ ์ ์ฒด ๋ถ๋ฌธ์ ๊ต์ฒดํ๋ ๊ฒ์ฒ๋ผ) ๊ตต์งํ ๊ฒฝ์ฐ, ๋ณดํต memoization์ด ํ์ํ์ง ์์ต๋๋ค. ๋ฐ๋ฉด์ ์ฑ์ด (๋ํ์ ์ด๋ํ๋ ๊ฒ๊ณผ ๊ฐ์ด) ๋ฏธ์ธํ ์ํธ์์ฉ์ ํ๋ ๊ทธ๋ฆผ ํธ์ง๊ธฐ ๊ฐ์ ๊ฒฝ์ฐ, memoization์ด ๋งค์ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
useCallback
์ผ๋ก ํจ์๋ฅผ ์บ์ฑํ๋ ๊ฒ์ ๋ช ๊ฐ์ง ๊ฒฝ์ฐ์๋ง ๊ฐ์น ์์ต๋๋ค.
memo
๋ก ๊ฐ์ธ์ง ์ปดํฌ๋ํธ์ prop์ผ๋ก ๋๊น๋๋ค. ์ด ๊ฐ์ด ๋ณํ์ง ์์ผ๋ฉด ๋ฆฌ๋ ๋๋ง์ ๊ฑด๋๋ฐ๊ณ ์ถ์ต๋๋ค. memoization์ ์์กด์ฑ์ด ๋ณํ์ ๋๋ง ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋งํ๋๋ก ํฉ๋๋ค.- ๋๊ธด ํจ์๊ฐ ๋์ค์ ์ด๋ค Hook์ ์์กด์ฑ์ผ๋ก ์ฌ์ฉ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด,
useCallback
์ผ๋ก ๊ฐ์ธ์ง ๋ค๋ฅธ ํจ์๊ฐ ์ด ํจ์์ ์์กดํ๊ฑฐ๋,useEffect
์์ ์ด ํจ์์ ์์กดํฉ๋๋ค.
๋ค๋ฅธ ๊ฒฝ์ฐ์์ useCallback
์ผ๋ก ํจ์๋ฅผ ๊ฐ์ธ๋ ๊ฒ์ ์๋ฌด๋ฐ ์ด์ต์ด ์์ต๋๋ค. ๋ํ ์ด๋ ๊ฒ ํ๋ ๊ฒ์ด ํฐ ๋ถ์ด์ต์ ๊ฐ์ ธ์ค์ง๋ ์์ผ๋ฏ๋ก ์ผ๋ถ ํ์ ๊ฐ๋ณ์ ์ธ ๊ฒฝ์ฐ๋ฅผ ๋ฐ๋ก ์๊ฐํ์ง ์๊ณ , ๊ฐ๋ฅํ ํ ๋ง์ด memoizationํ๋ ๋ฐฉ์์ ํํฉ๋๋ค. ๋จ์ ์ ์ฝ๋์ ๊ฐ๋
์ฑ์ด ๋จ์ด์ง๋ ๊ฒ์
๋๋ค. ๋ํ, ๋ชจ๋ memoization์ด ํจ๊ณผ์ ์ธ ๊ฒ์ ์๋๋๋ค. โํญ์ ์๋ก์ดโ ํ๋์ ๊ฐ์ด ์๋ค๋ฉด ์ ์ฒด ์ปดํฌ๋ํธ์ memoization์ ๊นจ๊ธฐ์ ์ถฉ๋ถํฉ๋๋ค.
useCallback
์ด ํจ์์ ์์ฑ์ ๋ง์ง ์๋๋ค๋ ์ ์ ์ฃผ์ํ์ธ์. ํญ์ ํจ์๋ฅผ ์์ฑํ์ง๋ง (์ด๊ฑด ๊ด์ฐฎ์ต๋๋ค!), ๊ทธ๋ฌ๋ React๋ ๋ณ๊ฒฝ์ด ์๋ ๊ฒฝ์ฐ์๋ ๋ฌด์ํ๊ณ ์บ์๋ ํจ์๋ฅผ ๋ฐํํฉ๋๋ค
์ค์ ๋ก ๋ช ๊ฐ์ง ์์น์ ๋ฐ๋ฅด๋ฉด ๋ง์ memoization์ ๋ถํ์ํ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
- ์ปดํฌ๋ํธ๊ฐ ๋ค๋ฅธ ์ปดํฌ๋ํธ๋ฅผ ์๊ฐ์ ์ผ๋ก ๊ฐ์ธ๊ณ ์๋ค๋ฉด JSX๋ฅผ ์์์ผ๋ก ๋ฐ๊ฒ ํ์ธ์. ๊ฐ์ธ๋ ์ปดํฌ๋ํธ๊ฐ ์์ ์ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ๋ฉด, React๋ ์์๋ค์ ๋ฆฌ๋ ๋๋งํ ํ์๊ฐ ์๋ค๋ ๊ฒ์ ์๊ฒ ๋ฉ๋๋ค.
- ๊ฐ๋ฅํ ํ ๋ก์ปฌ ์ํ๋ฅผ ์ ํธํ๊ณ , ์ปดํฌ๋ํธ ๊ฐ ์ํ ๊ณต์ ๋ฅผ ํ์ ์ด์์ผ๋ก ํ์ง ๋ง์ธ์. ํผ์ด๋ ํญ๋ชฉ์ด ํธ๋ฒ๋์๋์ง์ ๊ฐ์ ์ผ์์ ์ธ ์ํ๋ฅผ ํธ๋ฆฌ์ ์๋จ์ด๋ ์ ์ญ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ์งํ์ง ๋ง์ธ์.
- ๋ ๋๋ง ๋ก์ง์ ์์ํ๊ฒ ์ ์งํ์ธ์. ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋๋งํ๋ ๊ฒ์ด ๋ฌธ์ ๋ฅผ ์ผ์ผํค๊ฑฐ๋ ๋์ ๋๋ ์๊ฐ์ ์ธ ํ์ฒด๋ฅผ ์์ฑํ๋ค๋ฉด, ๊ทธ๊ฒ์ ์ปดํฌ๋ํธ์ ๋ฒ๊ทธ์ ๋๋ค! memoization์ ์ถ๊ฐํ๋ ๋์ ๋ฒ๊ทธ๋ฅผ ํด๊ฒฐํ์ธ์.
- ์ํ๋ฅผ ์ ๋ฐ์ดํธํ๋ ๋ถํ์ํ Effects๋ฅผ ํผํ์ธ์. React ์ฑ์์ ๋๋ถ๋ถ์ ์ฑ๋ฅ ๋ฌธ์ ๋ Effects๋ก๋ถํฐ ๋ฐ์ํ ์ฐ์๋ ์ ๋ฐ์ดํธ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ๊ณ์ํด์ ๋ ๋๋งํ๋ ๊ฒ์ด ์์ธ์ ๋๋ค.
- Effects์์ ๋ถํ์ํ ์์กด์ฑ์ ์ ๊ฑฐํ์ธ์. ์๋ฅผ ๋ค์ด, memoization ๋์ ๊ฐ์ฒด๋ ํจ์๋ฅผ Effect ์์ด๋ ์ปดํฌ๋ํธ ์ธ๋ถ๋ก ์ด๋์ํค๋ ๊ฒ์ด ๋ ๊ฐ๋จํ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
๋ง์ฝ ํน์ ์ํธ์์ฉ์ด ์ฌ์ ํ ๋๋ฆฌ๊ฒ ๋๊ปด์ง๋ค๋ฉด, React Developer Tools profiler๋ฅผ ์ฌ์ฉํ์ฌ, ์ด๋ค ์ปดํฌ๋ํธ๊ฐ memoization์ ๊ฐ์ฅ ํ์๋ก ํ๋์ง ์ดํด๋ณด๊ณ , ํ์ํ ๊ณณ์ memoization์ ์ถ๊ฐํ์ธ์. ์ด๋ฐ ์์น๋ค์ ์ปดํฌ๋ํธ๋ฅผ ๋ ์ฝ๊ฒ ๋๋ฒ๊น ํ๊ณ ์ดํดํ ์ ์๋๋ก ํด์ฃผ๊ธฐ ๋๋ฌธ์ ์ด๋ค ๊ฒฝ์ฐ๋ผ๋ ๋ฐ๋ฅด๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ฅ๊ธฐ์ ์ผ๋ก ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฐ๋ฆฌ๋ memoization์ ์๋ํํ๋ ๊ธฐ์ ์ ์ฐ๊ตฌํ๊ณ ์์ต๋๋ค.
Example 1 of 2: useCallback
๊ณผ memo
๋ก ๋ฆฌ๋ ๋๋ง ๊ฑด๋๋ฐ๊ธฐ
์ด ์์์์ ShippingForm
์ปดํฌ๋ํธ๋ ์ธ์์ ์ผ๋ก ๋๋ฆฌ๊ฒ ๋ง๋ค์๊ธฐ ๋๋ฌธ์ ๋ ๋๋งํ๋ React ์ปดํฌ๋ํธ๊ฐ ์ค์ ๋ก ๋๋ฆด ๋ ์ด๋ค ์ผ์ด ์ผ์ด๋๋ ์ง ๋ณผ ์ ์์ต๋๋ค. ์นด์ดํฐ๋ฅผ ์ฆ๊ฐ์ํค๊ณ ํ
๋ง๋ฅผ ํ ๊ธ ํด๋ณด์ธ์.
์นด์ดํฐ๋ฅผ ์ฆ๊ฐ์ํค๋ฉด ๋๋ ค์ง ShippingForm
์ด ๋ฆฌ๋ ๋๋งํ๊ธฐ ๋๋ฌธ์ ๋๋ฆฌ๋ค๊ณ ๋๊ปด์ง๋๋ค. ์ด๋ ์์๋ ๋์์
๋๋ค. ์นด์ดํฐ๊ฐ ๋ณ๊ฒฝ๋์์ผ๋ฏ๋ก ์ฌ์ฉ์์ ์๋ก์ด ์ ํ์ ํ๋ฉด์ ๋ฐ์ํด์ผ ํ๊ธฐ ๋๋ฌธ์
๋๋ค.
๋ค์์ผ๋ก ํ
๋ง๋ฅผ ํ ๊ธ ํด๋ณด์ธ์. useCallback
์ memo
์ ํจ๊ป ์ฌ์ฉํ ๋๋ถ์, ์ธ์์ ์ธ ์ง์ฐ์๋ ๋ถ๊ตฌํ๊ณ ๋น ๋ฆ
๋๋ค! ShippingForm
์ handleSubmit
ํจ์๊ฐ ๋ณํ์ง ์์๊ธฐ ๋๋ฌธ์ ๋ฆฌ๋ ๋๋ง์ ๊ฑด๋๋ฐ์์ต๋๋ค. productId
์ referrer
(useCallback
์ ์์กด์ฑ) ๋ชจ๋ ๋ง์ง๋ง ๋ ๋๋ง์ผ๋ก๋ถํฐ ๋ณํ์ง ์์๊ธฐ ๋๋ฌธ์ handleSubmit
ํจ์๋ ๋ณํ์ง ์์์ต๋๋ค.
import { useCallback } from 'react'; import ShippingForm from './ShippingForm.js'; export default function ProductPage({ productId, referrer, theme }) { const handleSubmit = useCallback((orderDetails) => { post('/product/' + productId + '/buy', { referrer, orderDetails, }); }, [productId, referrer]); return ( <div className={theme}> <ShippingForm onSubmit={handleSubmit} /> </div> ); } function post(url, data) { // ์์ฒญ์ ๋ณด๋ธ๋ค๊ณ ์๊ฐํ์ธ์... console.log('POST /' + url); console.log(data); }
Memoized ์ฝ๋ฐฑ์์ ์ํ ์ ๋ฐ์ดํธํ๊ธฐ
๋๋๋ก memoized ์ฝ๋ฐฑ์์ ์ด์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ํ๋ฅผ ์ ๋ฐ์ดํธํด์ผ ํ ๋๊ฐ ์์ต๋๋ค.
handleAddTodo
ํจ์๋ todos
๋ก๋ถํฐ ๋ค์ ํ ์ผ์ ๊ณ์ฐํ๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ์์กด์ฑ์ผ๋ก ๋ช
์ํ์ต๋๋ค.
function TodoList() {
const [todos, setTodos] = useState([]);
const handleAddTodo = useCallback((text) => {
const newTodo = { id: nextId++, text };
setTodos([...todos, newTodo]);
}, [todos]);
// ...
๋ณดํต์ memoized ํจ์๊ฐ ๊ฐ๋ฅํ ํ ์ ์ ์์กด์ฑ์ ๊ฐ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ค์ ์ํ๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด ์ด๋ค ์ํ๋ฅผ ์ฝ๋ ๊ฒฝ์ฐ, ์ ๋ฐ์ดํธ ํจ์๋ฅผ ๋์ ๋๊ฒจ์ค์ผ๋ก์จ ์์กด์ฑ์ ์ ๊ฑฐํ ์ ์์ต๋๋ค.
function TodoList() {
const [todos, setTodos] = useState([]);
const handleAddTodo = useCallback((text) => {
const newTodo = { id: nextId++, text };
setTodos(todos => [...todos, newTodo]);
}, []); // โ
todos ์์กด์ฑ์ ํ์ํ์ง ์์ต๋๋ค.
// ...
์ฌ๊ธฐ์ todos
๋ฅผ ์์กด์ฑ์ผ๋ก ๋ง๋ค๊ณ ์์์ ๊ฐ์ ์ฝ๋ ๋์ , React์ ์ด๋ป๊ฒ ์ํ๋ฅผ ์
๋ฐ์ดํธํ ์ง์ ๋ํ ์ง์นจ์ ๋๊ฒจ์ค๋๋ค. ์
๋ฐ์ดํธ ํจ์์ ๋ํด ๋ ์์๋ณด์ธ์.
Effect๊ฐ ๋๋ฌด ์์ฃผ ์คํ๋๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ
๊ฐ๋ Effect ์์์ ํจ์๋ฅผ ํธ์ถํด์ผ ํ ์๋ ์์ต๋๋ค.
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');
function createOptions() {
return {
serverUrl: 'https://localhost:1234',
roomId: roomId
};
}
useEffect(() => {
const options = createOptions();
const connection = createConnection();
connection.connect();
// ...
์ด๊ฒ์ ๋ฌธ์ ๋ฅผ ๋ฐ์์ํต๋๋ค. ๋ชจ๋ ๋ฐ์ํ ๊ฐ์ Effect์ ์์กด์ฑ์ผ๋ก ์ ์ธ๋์ด์ผ ํฉ๋๋ค. ํ์ง๋ง createOptions
๋ฅผ ์์กด์ฑ์ผ๋ก ์ ์ธํ๋ฉด Effect๊ฐ ์ฑํ
๋ฐฉ๊ณผ ๊ณ์ ์ฌ์ฐ๊ฒฐ๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
useEffect(() => {
const options = createOptions();
const connection = createConnection();
connection.connect();
return () => connection.disconnect();
}, [createOptions]); // ๐ด ๋ฌธ์ ์ : ์ด ์์กด์ฑ์ ๋งค ๋ ๋๋ง๋ง๋ค ๋ณ๊ฒฝ๋ฉ๋๋ค.
// ...
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด, Effect์์ ํธ์ถํ๋ ค๋ ํจ์๋ฅผ useCallback
์ผ๋ก ๊ฐ์ ์ ์์ต๋๋ค.
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');
const createOptions = useCallback(() => {
return {
serverUrl: 'https://localhost:1234',
roomId: roomId
};
}, [roomId]); // โ
roomId๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง ๋ณ๊ฒฝ๋ฉ๋๋ค.
useEffect(() => {
const options = createOptions();
const connection = createConnection();
connection.connect();
return () => connection.disconnect();
}, [createOptions]); // โ
createOptions๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง ๋ณ๊ฒฝ๋ฉ๋๋ค.
// ...
์ด๊ฒ์ ๋ฆฌ๋ ๋๋ง ๊ฐ์ roomId
๊ฐ ๊ฐ๋ค๋ฉด createOptions
ํจ์๋ ๊ฐ๋ค๋ ๊ฒ์ ๋ณด์ฅํฉ๋๋ค. ํ์ง๋ง, ํจ์ ์์กด์ฑ์ ์ ๊ฑฐํ๋ ๊ฒ์ด ๋ ์ข์ต๋๋ค. ํจ์๋ฅผ Effect ์์ผ๋ก ์ด๋์ํค์ธ์.
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');
useEffect(() => {
function createOptions() { // โ
useCallback์ด๋ ํจ์ ์์กด์ฑ์ด ํ์ํ์ง ์์ต๋๋ค.
return {
serverUrl: 'https://localhost:1234',
roomId: roomId
};
}
const options = createOptions();
const connection = createConnection();
connection.connect();
return () => connection.disconnect();
}, [roomId]); // โ
roomId๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง ๋ณ๊ฒฝ๋ฉ๋๋ค.
// ...
์ด์ ์ฝ๋๋ ๋ ๊ฐ๋จํด์ก๊ณ useCallback
์ ํ์ํ์ง ์์ต๋๋ค. Effect์ ์์กด์ฑ ์ ๊ฑฐ์ ๋ํด ๋ ์์๋ณด์ธ์.
์ปค์คํ Hook ์ต์ ํํ๊ธฐ
์ปค์คํ
Hook์ ์์ฑํ๋ ๊ฒฝ์ฐ, ๋ฐํํ๋ ๋ชจ๋ ํจ์๋ฅผ useCallback
์ผ๋ก ๊ฐ์ธ๋ ๊ฒ์ด ์ข์ต๋๋ค.
function useRouter() {
const { dispatch } = useContext(RouterStateContext);
const navigate = useCallback((url) => {
dispatch({ type: 'navigate', url });
}, [dispatch]);
const goBack = useCallback(() => {
dispatch({ type: 'back' });
}, [dispatch]);
return {
navigate,
goBack,
};
}
์ด๋ ๊ฒ ํ๋ฉด Hook์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๊ฐ ํ์ํ ๋ ๊ฐ์ง๊ณ ์๋ ์ฝ๋๋ฅผ ์ต์ ํํ ์ ์์ต๋๋ค.
๋ฌธ์ ํด๊ฒฐ
์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ ๋๋ง๋ค useCallback
์ด ๋ค๋ฅธ ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.
๋ ๋ฒ์งธ ์ธ์๋ก ์์กด์ฑ ๋ฐฐ์ด์ ์ง์ ํ๋์ง ํ์ธํ์ธ์!
์์กด์ฑ ๋ฐฐ์ด์ ๊น๋จน์ผ๋ฉด useCallback
์ ๋งค๋ฒ ์๋ก์ด ํจ์๋ฅผ ๋ฐํํฉ๋๋ค.
function ProductPage({ productId, referrer }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}); // ๐ด ๋งค๋ฒ ์๋ก์ด ํจ์๋ฅผ ๋ฐํํฉ๋๋ค: ์์กด์ฑ ๋ฐฐ์ด ์์
// ...
๋ค์์ ๋ ๋ฒ์งธ ์ธ์๋ก ์์กด์ฑ ๋ฐฐ์ด์ ๋๊ฒจ์ฃผ๋๋ก ์์ ํ ์ฝ๋์ ๋๋ค.
function ProductPage({ productId, referrer }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]); // โ
๋ถํ์ํ๊ฒ ์๋ก์ด ํจ์๋ฅผ ๋ฐํํ์ง ์์ต๋๋ค.
// ...
์ด๊ฒ์ด ๋์์ด ๋์ง ์๋๋ค๋ฉด ์์กด์ฑ ์ค ์ ์ด๋ ํ๋๊ฐ ์ด์ ๋ ๋๋ง๊ณผ ๋ค๋ฅธ ๊ฒ์ด ๋ฌธ์ ์ ๋๋ค. ์์กด์ฑ์ ์ฝ์์ ์ง์ ๊ธฐ๋กํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ๋๋ฒ๊น ํ ์ ์์ต๋๋ค.
const handleSubmit = useCallback((orderDetails) => {
// ..
}, [productId, referrer]);
console.log([productId, referrer]);
๊ทธ๋ฐ ๋ค์ ์ฝ์์์ ์๋ก ๋ค๋ฅธ ๋ ๋๋ง์ ๋ฐฐ์ด์ ๋ง์ฐ์ค ์ค๋ฅธ์ชฝ ํด๋ฆญ ํ โ์ ์ญ ๋ณ์๋ก ์ ์ฅโ์ ์ ํํ ์ ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๊ฒ์ด temp1
, ๋ ๋ฒ์งธ ๊ฒ์ด temp2
๋ก ์ ์ฅ๋๋ค๋ฉด, ๋ธ๋ผ์ฐ์ ์ฝ์์ ํตํด ๊ฐ ์์กด์ฑ์ด ๋ ๋ฐฐ์ด์์ ๊ฐ์์ง ํ์ธํ ์ ์์ต๋๋ค.
Object.is(temp1[0], temp2[0]); // ์ฒซ ๋ฒ์งธ ์์กด์ฑ์ด ๋ฐฐ์ด ๊ฐ์ ๋์ผํ๊ฐ์?
Object.is(temp1[1], temp2[1]); // ๋ ๋ฒ์งธ ์์กด์ฑ์ด ๋ฐฐ์ด ๊ฐ์ ๋์ผํ๊ฐ์?
Object.is(temp1[2], temp2[2]); // ... ๋๋จธ์ง ๋ชจ๋ ์์กด์ฑ๋ ํ์ธํฉ๋๋ค ...
์ด๋ค ์์กด์ฑ์ด memoization์ ๊นจ๊ณ ์๋์ง ์ฐพ์๋ค๋ฉด ์ด๋ฅผ ์ ๊ฑฐํ๊ฑฐ๋ memoizationํ๋ ๋ฐฉ๋ฒ์ ์ฐพ์ผ์ธ์.
๋ฐ๋ณต๋ฌธ์์ ๊ฐ ํญ๋ชฉ๋ง๋ค useCallback
์ ํธ์ถํ๊ณ ์ถ์ง๋ง, ์ด๊ฒ์ ํ์ฉ๋์ง ์์ต๋๋ค.
Chart
์ปดํฌ๋ํธ๊ฐ memo
๋ก ๊ฐ์ธ์ ธ ์๋ค๊ณ ์๊ฐํด ๋ด
์๋ค. ReportList
์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง ๋ ๋๋ง๋ค, ๋ชจ๋ Chart
ํญ๋ชฉ์ด ๋ฆฌ๋ ๋๋ง ํ๋ ๊ฒ์ ๋ง๊ณ ์ถ์ต๋๋ค. ํ์ง๋ง ๋ฐ๋ณต๋ฌธ์์ useCallback
์ ํธ์ถํ ์ ์์ต๋๋ค.
function ReportList({ items }) {
return (
<article>
{items.map(item => {
// ๐ด ์ด๋ ๊ฒ ๋ฐ๋ณต๋ฌธ ์์์ useCallback์ ํธ์ถํ ์ ์์ต๋๋ค.
const handleClick = useCallback(() => {
sendReport(item)
}, [item]);
return (
<figure key={item.id}>
<Chart onClick={handleClick} />
</figure>
);
})}
</article>
);
}
๋์ ๊ฐ๋ณ ํญ๋ชฉ์ ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌํ๊ณ , ๊ฑฐ๊ธฐ์ useCallback
์ ๋ฃ์ผ์ธ์.
function ReportList({ items }) {
return (
<article>
{items.map(item =>
<Report key={item.id} item={item} />
)}
</article>
);
}
function Report({ item }) {
// โ
useCallback์ ์ต์์ ๋ ๋ฒจ์์ ํธ์ถํ์ธ์
const handleClick = useCallback(() => {
sendReport(item)
}, [item]);
return (
<figure>
<Chart onClick={handleClick} />
</figure>
);
}
๋์์ผ๋ก ๋ง์ง๋ง ์ค๋ํซ์์ useCallback
์ ์ ๊ฑฐํ๊ณ ๋์ Report
์์ฒด๋ฅผ memo
๋ก ๊ฐ์ธ๋ ๋ฉ๋๋ค. item
prop์ด ๋ณ๊ฒฝ๋์ง ์์ผ๋ฉด Report
๋ ๋ฆฌ๋ ๋๋งํ์ง ์๊ธฐ ๋๋ฌธ์ Chart
๋ ๋ฆฌ๋ ๋๋ง์ ๊ฑด๋๋๋๋ค.
function ReportList({ items }) {
// ...
}
const Report = memo(function Report({ item }) {
function handleClick() {
sendReport(item);
}
return (
<figure>
<Chart onClick={handleClick} />
</figure>
);
});