Redux - React에서의 Saga 패턴

BigbrotherShin·2020년 3월 13일
0

Frontend

목록 보기
8/31
post-thumbnail

패턴

React-Saga에서 95%의 비동기 요청은 다음과 같은 패턴으로 작성해도 무방하다.

  1. Saga에 동작(예제에서는 watchLogin)을 등록하고
  2. takeLatest 또는 takeEvery 둘 중 무엇을 쓸 지 결정하고, 실제 동작 할 login은 따로 작성
  3. 실제 동작할 코드는 따로 작성

예제

import { all, fork, call, put, takeLatest } from 'redux-saga/effects';
import { LOG_IN_REQUEST, LOG_IN_SUCCESS, LOG_IN_FAILURE } from '../reducers/user';

function* login() { // 3. 실제 동작할 코드는 따로 작성
  try {
    yield fork(logger);
    yield call(loginAPI);
    yield put({
      type: LOG_IN_SUCCESS,
    });
  } catch (e) {
    console.error(e);
    yield put({
      type: LOG_IN_FAILURE,
    });
  }
}

function* watchLogin() {
  yield takeLatest(LOG_IN_REQUEST, login); 
  // 2. takeLatest 또는 takeEvery 둘 중 무엇을 쓸 지 결정하고,
  // 실제 동작 할 login은 따로 작성
}

export default function* userSaga() {
  yield all([fork(watchLogin)]); // 1. Saga에 watchLogin을 등록하고
}

saga에 데이터 넣어주기

컴포넌트에서 dispatch할 때 action뿐 만 아니라 데이터도 saga에 넣어줄 수 있습니다.

예제

components/PostCard.js

import React, { useCallback } from 'react';
import { useSelector } from 'react-redux';

const PostCard = ({ post }) => {
  const { me } = useSelector(state => state.user);
  const dispatch = useDispatch();

  const onSubmitComment = useCallback(() => {
    if (!me) {
      return alert('로그인이 필요합니다.');
    }
    dispatch({
      type: ADD_COMMENT_REQUEST,
      data: { // dispatch할 때 saga에 데이터를 전달할 수 있습니다.
        postId: post.id,
      },
    });
  }, []);
  
  return (
    <div>
      {commentFormOpened && (
        <>
          <Form onFinish={onSubmitComment}>
            <Form.Item>
              <Input.TextArea
                rows={4}
                value={commentText}
                onChange={onChangeCommentText}
              />
            </Form.Item>
            <Button type='primary' htmlType='submit'>
              삐약
            </Button>
          </Form>
        </>
      )}
    </div>
  );
};

sagas/post.js

function addCommentAPI(addCommentData) {
  // yield call(addCommentAPI, action.data)
  // 의 두 번째 인자 action.data가 addCommentData 인자로 들어갑니다.
  
	// 서버에 요청 보내는 부분
}

function* addComment(action) { // action 인자를 통해
  // ADD_COMMENT_REQUEST dispatch에 있는 data를 조회할 수 있습니다.
  try {
    yield call(addCommentAPI, action.data); // 두 번째 인자에 들어가는 action.data 데이터는
    yield put({
      type: ADD_COMMENT_SUCCESS,
      data: {
        postId: action.data.postId, // ADD_COMMENT_REQUEST dispatch에 포함된 data 조회. -> ADD_COMMENT_SUCCESS 액션에 동봉하여 dispatch 합니다.
      },
    });
  } catch (e) {
    console.error(e);
    put({
      type: ADD_COMMENT_FAILURE,
      error: e,
    });
  }
}

function* watchAddComment() { // ADD_COMMENT_REQUEST 액션이 dispatch 되면
  yield takeLatest(ADD_COMMENT_REQUEST, addComment); // addComment 함수 실행
}

export default function* postSaga() {
  yield all([fork(watchAddPost), fork(watchAddComment)]);
}
profile
JavaScript, Node.js 그리고 React를 배우는

0개의 댓글