리덕스로 댓글 쓰기 요청 보내기

Time Saver 2020. 11. 18. 08:40

github.com/bang-gui/blog

 

bang-gui/blog

나의 리액트 페이지. Contribute to bang-gui/blog development by creating an account on GitHub.

github.com


리액트를 다루는 기술의 연장선으로 댓글 기능을 추가하는 작업을 공부 겸 해보고 있다.

ducks스타일의 리덕스를 구현한다.

modules/comments.js를 만들자.

import { createAction, handleActions } from 'redux-actions';

const CHANGE_INPUT = 'comments/CHANGE_INPUT';

export const changeInput = createAction(CHANGE_INPUT, (body) => body);

const initialState = {
  body: '',
};

const comments = handleActions(
  {
    [CHANGE_INPUT]: (state, { payload: body }) => ({
        ...state,
        body: body,
    }),
  initialState,
);

export default comments;

 

뷰어 컨테이너 > 뷰어 > 세부 컴포넌트

이렇게 구성이 되어있다.

리덕스는 두 개의 컴포넌트를 거쳐 정보를 Props로 내려주어야 한다.

상태가 잘 관리되고 있다.

 

 

 이제 책의 포스트 쓰기 구현을 살짝 눈팅해서 리액트 saga를 만들어보자.

import { createAction, handleActions } from 'redux-actions';
import createRequestSaga, {
  createRequestActionTypes,
} from '../lib/createRequestSaga';
import * as commentAPI from '../lib/api/comments';
import { takeLatest } from 'redux-saga/effects';

const INITIALIZE = 'write/INITIALIZE'; // 모든 내용 초기화

const CHANGE_INPUT = 'comments/CHANGE_INPUT';

const [
  WRITE_COMMENT,
  WRITE_COMMENT_SUCCESS,
  WRITE_COMMENT_FAILURE,
] = createRequestActionTypes('write/WRITE_COMMENT');

export const changeInput = createAction(CHANGE_INPUT, (body) => body);
export const writeComment = createAction(WRITE_COMMENT, (id, body) => ({
  id: id,
  body: body,
}));

const writeCommentSaga = createRequestSaga(
  WRITE_COMMENT,
  commentAPI.writeComment,
);
export function* CommentSaga() {
  yield takeLatest(WRITE_COMMENT, writeCommentSaga);// takeLatest 이거 모르면 바보
}

const initialState = {
  body: '',
  comment: null,
  commentError: null,
};

const comments = handleActions(
  {
    [INITIALIZE]: (state) => initialState,
    [CHANGE_INPUT]: (state, { payload: body }) => ({
      ...state,
      body: body,
    }),
    [WRITE_COMMENT]: (state) => ({
      ...state,
      // comment와 commentError를 초기화
      comment: null,
      commentError: null,
    }),
    // 댓글 작성 성공
    [WRITE_COMMENT_SUCCESS]: (state, { payload: comment }) => ({
      ...state,
      comment,
    }),
    // 댓글 작성 실패
    [WRITE_COMMENT_FAILURE]: (state, { payload: commentError }) => ({
      ...state,
      commentError,
    }),
  },
  initialState,
);

export default comments;

 

takeEvery, takeLatest

takeEvery는 말 그대로 모든 요청을 처리한다. 이미 요청을 수행 중임에도 다음 요청을 거부하지 않고 처리하려 한다.

반면 takeLatest는 이미 처리 중인 요청이 있는데 같은 중복 요청이 들어온다면 먼저 들어온 요청들을 수행하지 않는다. 다른 요청들을 여러 요청이 중첩되었을 때 가장 마지막 요청만을 제대로 처리한다.

나는 당연히 맨 처음 들어온 요청을 먼저 처리해줄 것이라고 생각했는데 좀 반대의 개념이었다. 가장 마지막 요청만을 처리한다.

 

네트워크를 사용하는 요청에 대해

모든 통신에는 로딩, 성공, 실패가 있다.

이 모든 것을 두 개의 파일에서 끝낸다. 이해하려면 차근차근 책을 다시 보길 바란다.

modules/loading.js

lib/createRequestSaga.js

saga, thunk를 피해 갈 수는 없다. 제일 어렵다고 느껴지지만 제일 필요한 내용이다.

 

import client from './client';

export const writeComment = ({ id, body }) =>
  client.post(`/api/posts/${id}/comments`, { body });

 

commentAPI까지 연동해 놓았으니 한번 시험해보자.

나는 url에 있어야 할 포스트의 아이디를 가져오는 것에 한번 막혔다.

math.params를 조회하는데 undefined가 나와서... 무엇인가 했더니...

import React, { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { withRouter } from 'react-router-dom';
import CommentsViewer from '../../components/comments/CommentsViewer';
import { changeInput, writeComment } from '../../modules/comments';

const CommentsViewerContainer = ({ match, history }) => {
  const { postId } = match.params;

  const body = useSelector((state) => state.comments.body);
  const dispatch = useDispatch();

  const onChangeCommentInput = useCallback(
    (body) => dispatch(changeInput(body)),
    [dispatch],
  );

  const onWriteComment = () => {
    dispatch(writeComment(postId, body));
  };

  return (
    <CommentsViewer
      onChangeCommentInput={onChangeCommentInput}
      body={body}
      onWriteComment={onWriteComment}
    />
  );
};

export default withRouter(CommentsViewerContainer); //withRouter를 사용해 주어야 match와 history정보를 받아올 수 있다.

 

export defalut withRouter()를 사용해야 해당 정보를 얻어올 수 있다.

이 내용은 검색해도 잘 안나오더라... stackoverflow에 분명 있을 텐데... 책을 다시 읽어 보면서 찾았다...

 

 

db에 잘 입력된다.

 

 

github에 코드를 올려놓았다. 나는 리액트를 다루는 기술을 따라 하는 수준이라 이해도가 그리 좋지는 않다.

좋은 방법이나, 개선 사항을 알려주는 것은 환영이다.

'' 카테고리의 다른 글

삭제 기능  (0) 2020.11.24
댓글 읽기 요청 보내기  (0) 2020.11.18
생성, 조회, 삭제, 수정 API 생성하기  (0) 2020.11.16
DB를 위한 댓글 스키마 생성하기  (0) 2020.11.16