Assignment 9: 페이워크 기술 과제 정리 글입니다.
json-server
로 만든 임시 서버와 Redux-Saga를 이용해 비동기 네트워크 통신을 진행했습니다. Redux-Saga를 이용해 Todo Item을 생성하는 과정을 정리해봤습니다.
Todo Item을 생성하는 action
, reducer
, saga
생성 과정입니다.
Todo Item을 생성 요청
, 성공
, 실패
를 처리하기 위해 각각 액션 타입과 액션 생성 함수를 생성했습니다.
요청 함수에는 Item 생성에 필요한 데이터
와 성공 함수에는 전역 상태에 추가할 데이터
를 받았습니다.
// store/actions
export const CREATE_TODO_REQUEST = "CREATE_TODO_REQUEST" as const;
export const CREATE_TODO_SUCCESS = "CREATE_TODO_SUCCESS" as const;
export const CREATE_TODO_FAILURE = "CREATE_TODO_FAILURE" as const;
export const createTodoRequest = ({ content, isCheck, createAt }: ITodo) => ({
type: CREATE_TODO_REQUEST,
content,
isCheck,
createAt,
});
export const createTodoSuccess = (payload: ITodo) => ({
type: CREATE_TODO_SUCCESS,
payload,
});
export const createTodoFailure = (payload: Error) => ({
type: CREATE_TODO_SUCCESS,
payload,
});
export type TodoAction =
| ReturnType<typeof createTodoRequest>
| ReturnType<typeof createTodoSuccess>
| ReturnType<typeof createTodoFailure>;
Action Type 별로 전역 변수를 관리합니다. 로딩과 에러 처리를 위해 createLoading
, createError
변수를 이용했습니다.
CREATE_TODO_SUCCESS Action 시에 전달받은 새로운 Todo Item을 spread 연산자를 이용해 불변성을 유지한 채 기존의 todos에 추가했습니다.
// store/reducers/todo
export const initialState = {
todos: [],
createLoading: false,
createError: false,
};
type TodoState = {
todos: ITodo[];
createLoading: boolean;
createError: boolean;
};
const todo = (
state: TodoState = initialState,
action: TodoAction
): TodoState => {
switch (action.type) {
case CREATE_TODO_REQUEST:
return {
...state,
createLoading: true,
createError: false,
};
case CREATE_TODO_SUCCESS:
return {
...state,
todos: [...state.todos, { ...action.payload }],
createLoading: false,
createError: false,
};
case CREATE_TODO_FAILURE:
return {
...state,
createLoading: false,
createError: true,
};
}
};
비동기 통신을 담당하는 saga 부분입니다.
takeLatest effects
를 이용해 dispatch로 Action이 호출될 때 마지막 요청의 응답만을 얻을 수 있습니다. 첫 번째 인자로 Action, 두 번째 인자로 Action이 dispatch 됐을 때 실행할 함수를 적습니다.
먼저 액션 생성 함수에서 전달받은 변수들을 action을 통해 받을 수 있습니다. 비구조화 할당 문법을 통해 미리 선언했습니다.
saga 함수에선 call
과 put effects
를 사용했습니다.
call effect
를 이용해 네트워크 통신 함수를 실행시킵니다. 일반 함수는 함수 뒤에 괄호를 이용해 인자를 전달하지만, call effect
는 두 번째 인자에 전달한 인수들을 적습니다.
call effect
는 함수를 동기적으로 실행합니다. 마치 함수 앞에 await를 준 효과를 줄 수 있어 네트워크 응답을 받은 후 다음 로직을 실행할 수 있습니다. 비동기적으로 실행하려면 call 대신fork effect
를 사용합니다.
put
은 dispatch
와 같은 effect입니다. 앞의 call effect로 응답을 제대로 받았다면 성공 Action을 dispatch, 응답받는 과정에서 오류가 생겼다면 실패 Action을 호출합니다. payload
변수를 통해 성공 시 응답을, 실패 시 에러를 전달했습니다.
// store/sagas/todo
function* createTodoSaga(action: ReturnType<typeof createTodoRequest>) {
try {
const { content, isCheck, createAt } = action;
//export const createTodoData = ({ content, isCheck, createAt }: ITodo) =>
//axios.post(`${BASE_URL}/${END_POINT}`, { content, isCheck, createAt });
const response: AxiosResponse = yield call(authApi.createTodoData, {
content,
isCheck,
createAt,
});
yield put({
type: CREATE_TODO_SUCCESS,
payload: response.data,
});
} catch (e) {
yield put({
type: CREATE_TODO_FAILURE,
payload: e,
});
}
}
export function* todoSaga() {
yield takeLatest(CREATE_TODO_REQUEST, createTodoSaga);
}
- 컴포넌트에서 dispatch를 통해 요청 Action 호출
- reducer에서 요청 Action 호출 -> 전역 상태 관리
- Redux-saga에서 Action 호출 후 saga 함수 실행
- saga 함수에서 동기적으로 네트워크 요청 처리 후 다음 Action 실행 ( 성공 혹은 실패 Action )
- reducer에서 다음 Action 호출 -> 전역 상태 관리