type CountContextType = [
number,
Dispatch<SetStateAction<number>>
]
const Count1Context = createContext<CountContextType | null>(null);
export const Count1Provider = ({children} : {children : ReactNode}) => (
<Count1Context.Provider value={useState(0)}>
{children}
</Count1Context.Provider>
)
export const Count1Provider = ({children} : {children : ReactNode}) => {
const [count, setcount] = useState(0);
return (
<Count1Context.Provider value={[count, setcount]}>
{children}
</Count1Context.Provider>
)
}
export const useCount1 = () => {
const value = useContext(Count1Context);
if(value === null) throw new Error("Provider missing");
return value;
}
Count1Provider로 감싸지 않고, 다음 useCount1에 접근하려면, useContext에서 null을 반환할 것이고, 다음 if문에서 걸려 에러를 던질 것이다.
위의 로직과 완전 똑같은 훅인 useCount2
훅을 만든다.
useCount1
훅과 useCount2
훅을 사용하는 컴포넌트는 다음과 같을 것이다.
const Count1 = () => {
// 컨텍스트에서 반환하는 값
const [count1, setCount1] = useCount1();
return (
<div>
Count 1 : {count1}
<button onClick={() => setCount((c) => c + 1)}>+ 1</button>
</div>
)
}
const Count2 = () => {
// 컨텍스트에서 반환하는 값
const [count2, setCount2] = useCount2();
return (
<div>
Count 2 : {count2}
<button onClick={() => setCount((c) => c + 1)}>+ 1</button>
</div>
)
}
Count1
컴포넌트와 Count2
컴포넌트를 Parent 컴포넌트에서 사용해 보자.
import Count1 from '@/component/Count1';
import Count2 from '@/component/Count2';
const Parent = () => (
<div>
<Count1 />
<Count1 />
<Count2 />
<Count2 />
</div>
)
App 컴포넌트에서 Provider
로 감싸준다. 순서는 상관없다.
import Count1Provider from '@/provider/Count1Provider';
import Count2Provider from '@/provider/Count2Provider';
import Parent from './Parent';
const App = () => (
<Count1Provider>
<Count2Provider>
<Parent/>
</Count2Provider>
</Count1Provider>
);
<aside>
✅ Count1Provider에 존재하는 State는 Count1
에만 사용되고, Count2Provider에 존재하는 State는 Count2
에만 사용된다.
Count1 컴포넌트가 값이 바뀌어 리렌더링되어도, Count2는 리렌더링 되지 않는다.
</aside>
팩토리
패턴createStateContext 의 역할
<aside> ✅ useState를 콜백함수로 넘긴다는 것이 중요하다.
</aside>
export const createStateContext = (
// 1. useState를 콜백함수로 받음
useValue : (initialValue) => State,
) => {
// 2. 컨텍스트 생성
const StateContext = createContext(null);
// 3. Provider 생성
const StateProvider = ({initialValue, children}) => (
<StateContext.Provider value={useValue(initialValue)}>
{children}
</StateContext.Provider>
)
// 4. 공급자 커스텀 훅 생성
const useContextState = () => {
const value = useContext(StateContext);
if(value === null) throw new Error('Provider Missing');
return value;
};
// 5. 반환 값 설정
return [StateProvider, useContextState] as const;
}
createStateContext
함수에 넘기는 콜백함수를 정의한다.// 이 initialState는 사용자측 Provider에서 넘기는 initalValue가 들어간다.
export const useNumberState = (initialValue) => useState(initialValue || 0);