๐ ์ฐธ๊ณ
1. https://solo5star.dev/posts/42/
๐ Provider ๋ด๋ถ์ ์ปดํฌ๋ํธ๊ฐ ์๋ ๊ฒฝ์ฐ (<Text />)
const CounterValueContext = createContext(0);
const CounterActionContext = createContext({
increase: () => {},
decrease: () => {},
});
export function CounterProvider({ children }: { children: React.ReactNode }) {
const [counter, setCounter] = useState(0);
const increase = () => setCounter((prev) => prev + 1);
const decrease = () => setCounter((prev) => prev - 1);
console.log('Counter Provider');
return (
<CounterValueContext.Provider value={counter}>
<CounterActionContext.Provider value={{ increase, decrease }}>
<Text />
{children}
</CounterActionContext.Provider>
</CounterValueContext.Provider>
);
}
export function useCounter() {
const value = useContext(CounterValueContext);
return value;
}
export function useSetCounter() {
const value = useContext(CounterActionContext);
return value;
}
export default function ContextPage() {
console.log('Context Page');
return (
<CounterProvider>
<Plus />
<Number />
<Minus />
<Hello />
</CounterProvider>
);
}
// Text.tsx
export default function Text() {
console.log('Text');
return <h3>Counter Text</h3>;
}
// Plus.tsx
export default function Plus() {
const { increase } = useSetCounter();
console.log('Plus');
return <button onClick={increase}>+</button>;
}
// Minus.tsx
export default function Minus() {
const { decrease } = useSetCounter();
console.log('Minus');
return <button onClick={decrease}>-</button>;
}
// Number.tsx
export default function Number() {
const count = useCounter();
console.log('Number');
return <div>{count}</div>;
}
// Hello.tsx
export default function Hello() {
console.log('Hello');
return <div>Hello!</div>;
}
<Hello /> ์ปดํฌ๋ํธ๋ฅผ ์ ์ธํ <Text />, <Plus />, <Minus />, <Number /> ์ปดํฌ๋ํธ ๋ชจ๋ counter ์ํ๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ๋ฆฌ๋ ๋๋ง์ด ๋ฐ์ํ๋ค.
<Text />๋ CounterProvider์ ๋ด๋ถ ์ํ๊ฐ ๋ณ๊ฒฝ๋์๊ธฐ ๋๋ฌธ์ ๋ฆฌ๋ ๋๋ง๋์๊ณ , ๋ฆฌ๋ ๋๋ง ๋๋ฉด์ increase, decrease ํจ์๋ ์๋ก ๋ง๋ค์ด์ง๊ธฐ ๋๋ฌธ์ context์ ๊ฐ์ ๋ฐ๋ผ๋ณด๊ณ ์๋(useCounter, useSetCounter) ๋ชจ๋ ์์ ์ปดํฌ๋ํธ๋ค์ด ๋ฆฌ๋ ๋๋ง ๋์๋ค.
- ๋ฆฌ๋ ๋๋ง์ ๋ง๋ ๋ฐฉ๋ฒ
context์ ๊ฐ์ ์ฌ์ฉํ๊ณ ์์ง ์์ <Text />์ ๋ฆฌ๋ ๋๋ง์ ๋ง๋ ๋ฐฉ๋ฒ์ <Text /> ์ปดํฌ๋ํธ์ React memo ๋ฅผ ์ ์ฉํ๊ฑฐ๋ <Hello /> ์ปดํฌ๋ํธ์ฒ๋ผ children์ผ๋ก ๋ ๋๋ง ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
increase, decrease ํจ์๋ฅผ ์ฌ์ฉํ๊ณ ์๋ ์ปดํฌ๋ํธ์ ๋ฆฌ๋ ๋๋ง์ ๋ง๋ ๋ฐฉ๋ฒ์ useMemo๋ฅผ ์ ์ฉํ actions ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ์ ๋ฌํ๋ ๊ฒ์ด๋ค. ์ด๋ฌ๋ฉด <CounterProvider />, <Number /> ์ปดํฌ๋ํธ๋ง ๋ฆฌ๋ ๋๋ง ๋๋ค.
export function CounterProvider({ children }: { children: React.ReactNode }) {
const [counter, setCounter] = useState(0);
const actions = useMemo(
() => ({
increase() {
setCounter((prev) => prev + 1);
},
decrease() {
setCounter((prev) => prev - 1);
},
}),
[],
);
console.log('Counter Provider');
return (
<CounterValueContext.Provider value={counter}>
<CounterActionContext.Provider value={actions}>
{children}
</CounterActionContext.Provider>
</CounterValueContext.Provider>
);
}
increase, decrease ๊ฐ ํจ์์ useCallback์ ์ ์ฉํด value = {{ increase, decrease }} ๋ก ์ ๋ฌํ ๊ฒฝ์ฐ, ๋ ๋๋ง ์ต์ ํ๊ฐ ์ ์ฉ๋์ง ์๋๋ค. ์๋ํ๋ฉด <CounterProvider />๊ฐ ๋ฆฌ๋ ๋๋ง ๋๋ฉด์ increase, decrease ํจ์๋ ๋ฉ๋ชจ์ด์ ์ด์ ๋์ง๋ง, value๋ก ์ ๋ฌํ๋ ๊ฐ์ฒด๋ ์๋ก ๋ง๋ค์ด์ง๊ธฐ๋๋ฌธ์ ์ต์ ํ๊ฐ ๋์ง ์๋๋ค.
๋ง์ฝ increase ํจ์ ํ๋๋ง ์ ๋ฌํ๋ค๋ฉด useCallback๋ง์ผ๋ก ์ต์ ํํ ์ ์๋ค.
๐ children์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง ํ ๊ฒฝ์ฐ
export function CounterProvider({ children }: { children: React.ReactNode }) {
const [counter, setCounter] = useState(0);
const actions = useMemo(
() => ({
increase() {
setCounter((prev) => prev + 1);
},
decrease() {
setCounter((prev) => prev - 1);
},
}),
[],
);
console.log('Counter Provider');
return (
<CounterValueContext.Provider value={counter}>
<CounterActionContext.Provider value={actions}>
{children}
</CounterActionContext.Provider>
</CounterValueContext.Provider>
);
}
export default function ContextPage() {
console.log('Context Page');
return (
<CounterProvider>
<Text>
<HeadingNumber />
</Text>
<Plus />
<Number />
<Minus />
<Hello />
</CounterProvider>
);
}
// Text.tsx
export default function Text({ children }: { children: React.ReactNode }) {
console.log('Text');
return (
<h3>
Counter Text
{children}
</h3>
);
}
// HeadingNumber.tsx
export default function HeadingNumber() {
const count = useCounter();
console.log('Heading Number');
return <span> โ
{count} โ
</span>;
}
// Hello.tsx
export default function Hello() {
console.log('Hello');
const count = useCounter();
return <div>Hello!</div>;
}
- <Text />๋ children์ผ๋ก <HeadingNumber /> ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๋ค.
- <Hello />๋ count ์ํ๋ฅผ ๊ฐ์ง์ง๋ง ์ฌ์ฉํ์ง ์๋๋ค.
![]() |
![]() |
count ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ฉด <Counter Provider />์ useCounter()๋ฅผ ์ฌ์ฉํ <Heading Number />, <Number />, <Hello /> ์ปดํฌ๋ํธ๋ง ๋ฆฌ๋ ๋๋ง ๋๋ค. (actions๋ useMemo๋ฅผ ์ ์ฉํ๊ธฐ ๋๋ฌธ์, <Plus /> <Minus /> ์ปดํฌ๋ํธ๋ ๋ฆฌ๋ ๋๋ง ๋ฐ์ํ์ง ์์)
<Text />๋ <HeadingNumber />๊ฐ ๋ฆฌ๋ ๋๋ง ๋์์ด๋ context ๊ฐ์ ์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ ๋ฆฌ๋ ๋๋ง ๋์ง ์๋๋ค.
์ ๊ฒฝ์ฐ๋ค์ ํตํด Context API์ ๋ชจ๋ ์์ ์ปดํฌ๋ํธ๋ค์ด ๋ฆฌ๋ ๋๋ง ๋๋ ๊ฒ์ ์๋๋ผ๋ ์ฌ์ค์ด๋ค!
๐ ํ๋์ context provider๋ก ๊ฐ๊ณผ ํจ์๋ฅผ ์ฌ์ฉํ๋ค๋ฉด?
const CounterContext = createContext({
counter: 0,
actions: { increase: () => {}, decrease: () => {} },
});
export function CounterProvider({ children }: { children: React.ReactNode }) {
const [counter, setCounter] = useState(0);
const actions = useMemo(
() => ({
increase() {
setCounter((prev) => prev + 1);
},
decrease() {
setCounter((prev) => prev - 1);
},
}),
[],
);
const value = useMemo(() => ({ counter, actions }), [counter, actions]);
console.log('Counter Provider');
return (
<CounterContext.Provider value={value}>{children}</CounterContext.Provider>
);
}
export function useCounter() {
const value = useContext(CounterContext);
return value;
}
// Plus.tsx
export default function Plus() {
const {
actions: { increase },
} = useCounter();
console.log('Plus');
return <button onClick={increase}>+</button>;
}
// Minus.tsx
export default function Minus() {
const {
actions: { decrease },
} = useCounter();
console.log('Minus');
return <button onClick={decrease}>-</button>;
}
ํ๋์ provider๋ฅผ ํตํด ๊ฐ์ ์ ๋ฌํ๊ณ ์๋ ๊ฒฝ์ฐ context์ ๊ฐ์ ์ฌ์ฉํ๊ณ ์๋ ๋ชจ๋ ์ปดํฌ๋ํธ์์ ๋ฆฌ๋ ๋๋ง์ด ๋ฐ์ํ๋ค. actions๋ useMemo๋ฅผ ์ ์ฉํ์ด๋, counter๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค value์ useMemo dependencies๊ฐ ๋ฐ๋๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋์ ์ํ๊ฐ ์์ฃผ ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ์๋ ๊ฐ๊ณผ ์ํ ๋ณ๊ฒฝ ํจ์ provider๋ฅผ ๋ถ๋ฆฌํ์ฌ ๊ด๋ฆฌํ๋๊ฒ ์ข๋ค.