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 컴포넌트를 넣어야 했기 때문이다.