보통 ContextApi를 쓰면 [{},{},{}...{}] 의 형태로 많이 쓰곤 한다.

그리고 redux를 많이들 쓴다. 그런데 대용량 프로젝트가 아닌 한 괜히 redux를 쓸 필요까지는 없을 것 같아서 ContextAPI를 쓰려고 했다.
왜냐하면 관리할 상태가 {}
객체 하나에 다 들어가기 때문이다.

그냥 react에서 contextAPI를 사용했을 때 간편하고, 번거롭지 않아 편했다.
그런데 typescript로 전향하고 나니 이 방법을 쓰는데는 먹히지 않았다.
그리고 context에서 다루는 내용이 단일 객체형일 때 어떻게 다루는지 알아보자.

1. 폴더구조

일단 폴더구조를 사용할 때 자바스크립트 파일로 썼을 때는

store/	context.jsx
		reducer.jsx

이렇게 썼었는데, 이제는 하나로 사용하자.

store/	context.tsx

2. context 만들기

만약 홈페이지에 팝업이 하나만 뜬다고 가정하고, 이를 관리하는 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)

3. reducer 만들기

타입 스크립트에서는 액션 타입을 미리 정해주어야 한다.
그래서 제대로된 값이 왔는지 검증할 수 있기 때문이다. 만약 이렇게 검증하지 않는다면 타입스크립트를 쓰는 이유가 없다.

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')
        }
    }
}

4.Provider 만들기

이걸 위해서 지금까지 사용한 것이다. 타입스크립트에서 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

5. 커스텀 hook만들기

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;
}

6. Provider 적용하기

나는 _app.tsx에 적용을 할 것이다.

import PopupProvider from 'context파일 위치 상태 경로';

function App(.....){
  ....
  return(
    <...>
    	<PopupProvider>
    		<Component {...pageProps} /> //원래 있던 부분
  		</PopupProvider>
	</...>
  )
}

이런 식으로 사용하면 된다.ㅣ

7. State 읽어오기

import { usePopupState } from "../../store/context"

const Popup = () =>{
  const state = usePopupState();
  ...내용들
}

8. Dispatch 사용하기

import {usePopupDispatch} from '../../store/context'
const PopupBox = () =>{
	const dispatch = usePopupDispatch();
  	useEffect(()=>{
      dispatch({type:'PopupClose'})
    },[])
}

이런 식으로 사용하면 된다!

다음에 더 큰 프로젝트를 맡게 되면 그때는 redux를 사용해봐야겠다!

profile
코딩 재밌어요!

0개의 댓글

Powered by GraphCDN, the GraphQL CDN