본문 바로가기
React

[React] useReducer를 사용하면, dispatch 후, 로직 순서 보장이 안 된다.

by devebucks 2023. 1. 15.
728x90

useReducer를 사용하면, dispatch 후, 로직 순서 보장이 안 된다.

 

그 이유.

 useReducer는 기본적으로 '비동기 로직'을 포함하는 '비동기 액션'을 dispatch 하지 않아요.

 

개요

context를 사용해서, 

app.tsx에 authContext를 추가했다.

auth.tsx에 context관련 코드는 넣었다.

 

auth.tsx에서 export로 useStateContext와 useDispatchContext란 이름으로 UI컴포넌트에서 import할 수 있게끔했다.

로그인을 요청 후, 서버로부터 유저 정보를 응답받고, 유저 정보를 context에 저장시키려고 했다.

context에서는 useRouter를 사용했다.

 

 

하지만, 코드가 실행되는 타임라인은 다음과 같았다.

1. '로그인' 버튼 클릭

2. 서버로 로그인 요청 및 응답 받음

3. 응답을 context dispatch한다.

 

 

 

코드로 보면,

로그인 UI 컴포넌트 pages/login.tsx

  // 로그인 요청
  const handleLogin = async (e: FormEvent) => {
    e.preventDefault();
    try {
      const res = await submitLogin({ username, password });
      console.log("전", context); 👈 실제 동작 순서 1
      await dispatch("LOGIN", res.data.user);
      console.log("후", context); 👈 실제 동작 순서 2
    } catch (err: any) {
      console.error(err);
 }

context/auth.tsx

reducer가 있고, reducer를 사용하는 useReducer훅이 있다.

const reducer = (state: State, { type, payload }: Action) => {
  switch (type) {
    case "LOGIN":
      console.log("로그인"); 👈 실제 동작 순서 3
      return {
        ...state,
        authenticated: true,
        user: payload,
      };
    // ...
    default: ...
}


export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
  const [state, defaultDispatch] = useReducer(reducer, {
    user: null,
    authenticated: false,
    isLoading: true,
  });

  console.log(state); 👈 실제 동작 순서 4

  const dispatch = (type: string, payload?: any) => {
    defaultDispatch({ type, payload });
  };

  return (
    <DispatchContext.Provider value={dispatch}>
      <StateContext.Provider value={state}>{children}</StateContext.Provider>
    </DispatchContext.Provider>
  );
};

 

브라우저 동작 콘솔

보세요. 

콘솔 '전', '후'의 사이에는 dispatch가 있는데, 콘솔이 찍힌 다음에서 dispatch가 실행되고 있죠?

 

728x90

댓글