redux와 비동기 함수 호출을 사용하기 위해 actionType 선언과 함수 호출 부분을 묶어줬다.
export const createRequestActionTypes = (type: string) => {
const SUCCESS = `${type}_SUCCESS`;
const FAILURE = `${type}_FAILURE`;
return [type, SUCCESS, FAILURE];
};
export default function createRequestThunk(type: string, request: any) {
const SUCCESS = `${type}_SUCCESS`;
const FAILURE = `${type}_FAILURE`;
return (params: any) => async (dispatch: any) => {
dispatch({ type });
try {
const response = await request(params);
dispatch({
type: SUCCESS,
payload: response.data.data,
});
} catch (e) {
dispatch({
type: FAILURE,
payload: e,
error: true,
});
throw e;
}
};
}
params랑 request랑 dispatch는 일단 any로 놔둠
언젠가 고치겠지
// modules/media.ts
...
const [LOAD, LOAD_SUCCESS, LOAD_FAILURE] =
createRequestActionTypes("media/LOAD");
const [UPLOAD, UPLOAD_SUCCESS, UPLOAD_FAILURE] =
createRequestActionTypes("media/UPLOAD");
export const load = createRequestThunk(LOAD, mediaAPI.load);
export const upload = createRequestThunk(UPLOAD, mediaAPI.upload);
interface MediaType {
id: number;
src: string;
videoName: string;
videoUrl: string;
videoType: string;
videoLanguage: string;
}
interface MediaReducer {
media: MediaType | null;
uploadedMedia: MediaType | null;
error: string | null;
}
const initialState: MediaReducer = {
media: null,
uploadedMedia: null,
error: null,
};
export default createReducer<MediaReducer>(initialState, {
[LOAD_SUCCESS]: (state, { payload: media }) => ({
...state,
media,
error: null,
}),
[LOAD_FAILURE]: (state, { payload: error }) => ({
...state,
media: null,
error,
}),
[UPLOAD_SUCCESS]: (state, { payload: uploadedMedia }) => ({
...state,
uploadedMedia,
error: null,
}),
[UPLOAD_FAILURE]: (state, { payload: error }) => ({
...state,
uploadedMedia: null,
error,
}),
});
원래는 redux-actions의 handleActions로 처리했는데 그렇게 하니까 TypeScript 변환이 복잡해 보이길래(?) typesafe-actions를 사용하기로 함
createReducer를 적용하고 interface도 선언해서 적용함
다행히
오류
안
뜸
ㅎㅎㅎ
media 에서 오류 안 떠서 기뻤는데 user 파일에 똑같이 처리하니까 오류뜸
어이가 없어서
// modules/user.ts
...
export const login = createRequestThunk(LOGIN, userAPI.login);
export const logout = createRequestThunk(LOGOUT, userAPI.logout);
export const signup = createRequestThunk(SIGNUP, userAPI.signup);
interface UserReducer {
login: boolean;
isSend: boolean;
isVerify: boolean;
tokenExp: string;
error: string | null;
}
const initialState: UserReducer = {
login: false,
isSend: false,
isVerify: false,
tokenExp: "",
error: null,
};
export default createReducer<UserReducer>(initialState, {
[LOGIN_SUCCESS]: (state, { payload: data }) => ({
...state,
login: data.login,
tokenExp: data.tokenExp,
error: null,
}),
[LOGIN_FAILURE]: (state, { payload: error }) => ({
...state,
login: false,
error,
}),
[SIGNUP_SUCCESS]: (state) => ({
...state,
error: null,
}),
[SIGNUP_FAILURE]: (state, { payload: error }) => ({
...state,
login: null,
error,
}),
[LOGOUT_SUCCESS]: (state, { payload: login }) => ({
...state,
login,
error: null,
}),
[LOGOUT_FAILURE]: (state, { payload: error }) => ({
...state,
error,
}),
...
});
근데 내가 잘못한거였다.
boolean type 선언해놓고 null 집어넣고 있었다.
많이 잘못했음.
❗ createReducer에서 null로 넣어준 부분 false로 변경
Header를 수정하려고 하는데 여기서 Redux 값을 가져와서 사용하는 부분이 있었다.
const login = useSelector(({ user }) => ({
login: user.login
}))
해당 구문에 오류가 발생했다.
// modules/index.ts
export type RootState = ReturnType<typeof persistedReducer>;
// components/Header.tsx
const login = useSelector((state: RootState) => state.user.login);
modules의 index 파일에 RootState 선언해주고 Header 코드 고쳐주니까 해결!!!
// components/Header.tsx
dispatch(logout());
// lib/createRequestThunk.ts
export default function createRequestThunk(type: string, request: any) {
const SUCCESS = `${type}_SUCCESS`;
const FAILURE = `${type}_FAILURE`;
return (params?: any) => async (dispatch: any) => {
dispatch({ type });
try {
const response = await request(params);
dispatch({
type: SUCCESS,
payload: response.data.data,
});
} catch (e) {
dispatch({
type: FAILURE,
payload: e,
error: true,
});
throw e;
}
};
}
그리고 좀 사소한 오류인데 로그아웃 코드에서 자꾸 오류가 났다.
내 잘못 아닌줄 알고 vscode 껐다켰다 했다.
근데 내 잘못이었다.
params를 그냥 any로 해놨음
그래서 인자 안 받는 logout에서는 오류가 나더라.
물음표 추가함
해결쓰
import Cookies from "universal-cookie";
import axios, { HeadersDefaults } from "axios";
const cookies = new Cookies();
const client = axios.create({
baseURL: URL,
timeout: 10000,
headers: { "Content-Type": "application/json" },
});
client.interceptors.request.use((config) => {
config.headers.common["Authorization"] = `Bearer ${cookies.get(
"refresh_token",
)}`;
return config;
});
export default client;
axios header 부분에서 오류 발생
client.interceptors.request.use((config) => {
const token = cookies.get("refresh_token");
if (config.headers) {
config.headers.Authorization = token ? `Bearer ${token}` : "";
}
return config;
});
config.headers.common["Authorization"]을 config.headers.Authorization으로 바꿔주니까 해결됐다.
이유는 모르겠다.
const _handleFunc = () => {
dispatch(func()).then();
}
// 오류 발생
const _handleFunc = async () => {
await dispatch(func());
// code...
}
아래 코드로 바꾸니까 로그인은 원하는대로 로직 반영됨
근데 회원가입 시 메일전송, 체크 로직에서 바로바로 state 확인을 못하고 이전 state를 확인한다.
ㅎ...
// modules/user.ts
import { createAction } from 'typesafe-actions';
export const renewalExpires = createAction(RENEWAL_EXPIRES)();
// App.tsx
dispatch(renewalExpires(data));
인자값이 0개가 들어와야 하는데 하나만 들어온다고 오류가 났다.
분명 redux-actions 사용했을때는 괜찮았는데 이상해서 다시 redux-actions로 바꿔봤다.
된다.
createReducer 적용하면서 같이 바꿨던건데 괜히 바꿨다.
index.js를 index.tsx로 바꿔주니까 코드에서 오류는 발생하지 않았지만 실행하니까 오류가 나오더라.
근데
다시 실행하니까
됨.
ㅎ...
일단 오늘은 끝