보통 ContextApi를 쓰면 [{},{},{}...{}] 의 형태로 많이 쓰곤 한다.
그리고 redux를 많이들 쓴다. 그런데 대용량 프로젝트가 아닌 한 괜히 redux를 쓸 필요까지는 없을 것 같아서 ContextAPI를 쓰려고 했다.
왜냐하면 관리할 상태가 {}
객체 하나에 다 들어가기 때문이다.
그냥 react에서 contextAPI를 사용했을 때 간편하고, 번거롭지 않아 편했다.
그런데 typescript로 전향하고 나니 이 방법을 쓰는데는 먹히지 않았다.
그리고 context에서 다루는 내용이 단일 객체형일 때 어떻게 다루는지 알아보자.
일단 폴더구조를 사용할 때 자바스크립트 파일로 썼을 때는
store/ context.jsx
reducer.jsx
이렇게 썼었는데, 이제는 하나로 사용하자.
store/ context.tsx
만약 홈페이지에 팝업이 하나만 뜬다고 가정하고, 이를 관리하는 contextAPI를 만든다고 가정해보자.
그러면 우리한테 필요한 것은 popup 상태를 알리는 것과 메세지가 필요할 것이다.
그에 대한 타입을 정의해보자.
import React, { useReducer,useContext,createContext,Dispatch} from 'react'
type State = {
popup?:string;
popupMessage?:string;
}
그리고 그 내용의 기본값들을 정해보자.
const initialState :State = {
popup:false,
popupMessage:'';
}
그리고 이를 편히 쓸 수 있게 해주는 Context를 만들어보자.
const PopupContext = createContext<State | null>(null)
타입 스크립트에서는 액션 타입을 미리 정해주어야 한다.
그래서 제대로된 값이 왔는지 검증할 수 있기 때문이다. 만약 이렇게 검증하지 않는다면 타입스크립트를 쓰는 이유가 없다.
type Action =
|{
type:'Error';
message:string
}|{
type:'Success';
message:string
}|{
type:'PopupClose';
};
그런 다음 dispatch를 만들기위한 type을 만들어준다.
type PopupDispatch = Dispatch<Action>
그리고 context를 만들어준다.
const PopupDispatchContext = createContext<PopupDispatch | null>(null);
그 다음에 reducer을 만들어준다.
function reducer(state:State, action:Action):State {
switch(action.type){
case 'PopupClose':{
console.log('walletConnect들어옴')
console.log(state)
return{
...state,
popup:false
}
(...생략)
default:{
throw new Error('Unhandled action')
}
}
}
이걸 위해서 지금까지 사용한 것이다. 타입스크립트에서 contextAPI를 사용하려면 두개로 나누어주는 것이 편하다. 그리고 이 것을 쉽게 사용하기 위해서 하나의 파일에서 작업하는 것이다.
그리고 두 단계로 나누어서 Provider가 생김에 주목하자. typescript에서는 원래 자바스크립트에서 가능했던 value={state,dispatch}
를 사용하려면 오류가 자꾸 나서 사용할 수가 없었다.
export function PopupProvider ({children}:{children:React.ReactNode}){
const [state,dispatch]=useReducer(reducer,initialState);
return(
<PopupContext.Provider value = {state}>
<PopupDispatchContext.Provider value = {dispatch}>
{children}
</PopupDispatchContext.Provider>
</PopupContext.Provider>
)
}
export default PopupProvider
2개의 함수를 만들 것이다. 하나는 상태를 읽어오는 함수이고, 하나는 dispatch를 사용할 수 있게끔하는 함수이다. 생각보다 간단하다.
export function usePopupState(){
const state= useContext(PopupContext);
if(!state) throw new Error('Cannot find PopupContext')
return state;
}
export function usePopupDispatch(){
const dispatch = useContext(PopupDispatchContext);
if(!dispatch) throw new Error('Cannot find PopupContext')
return dispatch;
}
나는 _app.tsx에 적용을 할 것이다.
import PopupProvider from 'context파일 위치 상태 경로';
function App(.....){
....
return(
<...>
<PopupProvider>
<Component {...pageProps} /> //원래 있던 부분
</PopupProvider>
</...>
)
}
이런 식으로 사용하면 된다.ㅣ
import { usePopupState } from "../../store/context"
const Popup = () =>{
const state = usePopupState();
...내용들
}
import {usePopupDispatch} from '../../store/context'
const PopupBox = () =>{
const dispatch = usePopupDispatch();
useEffect(()=>{
dispatch({type:'PopupClose'})
},[])
}
이런 식으로 사용하면 된다!
다음에 더 큰 프로젝트를 맡게 되면 그때는 redux를 사용해봐야겠다!