Redux의 non-serialization에 대응하는 함수전달

Doodream·2022년 1월 1일
0

ChawChaw - 프로젝트

목록 보기
7/8
post-thumbnail

리덕스는 함수저장이 안돼?!

contextAPI, Recoil등 상태관리 라이브러리에서 함수를 state에 저장하고 props로 전달하는 것은 이상한 것이 아니다. 하지만

리덕스에서 store에 함수를 저장해서 컴포넌트로 전달하는 것은 이상한 과정이다. 리덕스는 공식문서에서 리덕스를 어떻게 사용하는지 이야기 해놨다.
https://ko.redux.js.org/style-guide/style-guide/#do-not-put-non-serializable-values-in-state-or-actions

reduxDevTool에서 state비교가 불가하기 때문에

이러한 에러를 끊임 없이 띄워준다. 물론 이러한 에러를 띄우지 않게 설정 할 수는 있으나 리덕스에서 권장하는 사용법에는 어긋난다. 뭐.. 그것도 devTool 사용시 비교가 안되기 때문이기도 하지만 store 라면 값을 정확하게 전달하기 위해서 serialization 가능한 값만 전달하는 것도 크다.

하지만 역시 아쉽다. contextAPI나 Recoil은 되는데 리덕스는 안된다니?!?

그래서 약간의 편법을 이용해보기로 한다.

alertActions.ts

export const confirmFunc = createAsyncThunk(
  "alert/confirmFunc",
  async (confirmFuncName: string, thunkAPI) => {
    switch (confirmFuncName) {
      case CONFIRM_VOID:
        break;
      case CONFIRM_PUSH_LOGINPAGE:
        Router.push(LOGIN_PAGE_URL);
        break;
      case CONFIRM_PUSH_POSTPAGE:
        Router.push(POST_PAGE_URL);
        break;
      case CONFIRM_PUSH_SIGNUP:
        Router.push(SIGNUP_PAGE_URL);
        break;
      case CONFIRM_PUSH_SIGNUP_WEBMAIL:
        Router.push(SIGNUP_WEBMAIL_AUTH_PAGE_URL);
        break;
      case CONFIRM_PUSH_MAIN_PAGE:
        Router.push(MAIN_PAGE);
        break;
      case CONFIRM_PUSH_MANAGE_MAINPAGE:
        Router.push(MANAGE_MAIN_PAGE_URL);
        break;
      case CONFIRM_DELETE_USER:
        try {
          await thunkAPI.dispatch(deleteUser());
        } catch (error) {
          thunkAPI.dispatch(asyncErrorHandle(error));
        }
        break;
      case CONFIRM_DISPATCH_SIGNUP:
        const user = store.getState().auth.user;
        if (
          user.email &&
          user.name &&
          user.web_email &&
          user.school &&
          user.imageUrl &&
          user.provider
        ) {
          thunkAPI.dispatch(
            signup({
              email: user.email,
              name: user.name,
              web_email: user.web_email,
              school: user.school,
              imageUrl: user.imageUrl,
              provider: user.provider,
            })
          );
        }
        break;
      case CONFIRM_INIT_LOGOUT:
        window.localStorage.removeItem("accessToken");
        window.localStorage.removeItem("expireAtAccessToken");
        window.localStorage.removeItem("user");
        window.localStorage.href = LOGIN_PAGE_URL;
        break;
      default:
        break;
    }
  }
);

AlertMessage.tsx

 const handleClickConfirm = (
    e: MouseEvent<HTMLButtonElement>,
    id: number,
    confirmFuncName: string
  ) => {
    e.preventDefault();
    // 여기서 함수를 받아서 실행
    dispatch(confirmFunc(confirmFuncName));
    dispatch(alertActions.removeAlert(id));
  };

component.tsx

    dispatch(
        alertActions.updateAlert({
          name: WARNING_ALERT,
          message: WARNING_WEBMAIL_VERIFY_MSG,
          confirmFuncName: CONFIRM_PUSH_LOGINPAGE,
        })
      );

흐름을 보면 이런식이다. confirmFuncName을 string (serialization)으로 전달해서 실제 handleClickHandler에서dispatch(confirmFunc(confirmFuncName))을 해서 함수를 실행시킨다.

단순한 로직이지만 계속 redux store에 어떻게 하면 함수를 전달 시킬 수 있을까 고민을 많이 했다.

저렇게 하지않으면 함수자체를 props로 컴포넌트에 보내야하는 불편한 로직때문에 컴포넌트마다 AlertMessage 컴포넌트를 넣어야 했기 때문이다.

개선점

  1. Errorboundary를 통한 에러집중화 전략에서 함수전달을 할 수 있다.
  2. 함수를 전달하기 위해서 AlertMessage 컴포넌트에 props로 함수를 전달하지 않아도 된다.
  3. 2번 때문에 AlertMessage 컴포넌트를 다른 컴포넌트에 넣지 않아도 된다. : 중복코드가 없어지고 로직이 간결해진다.
profile
일상을 기록하는 삶을 사는 개발자 ✒️ #front_end 💻

0개의 댓글