[Web] React(19) /React Actions, Combine Reducers

최예린·2022년 9월 13일
0

React

목록 보기
12/19

reducer들을 어떻게 분리해서 상태의 부분들을 관리할지. 그리고 전체 상태를 관리하기위해서 reducer들을 어떻게 합치는지 공부해보겠습니다.

  1. 상태의 한 부분을 책임지는 리듀서들을 실행하는 방법
  2. 전체 상태를 관리하기위해서 리듀서들을 합치는 방법

Redux Actions이란?

Action

action은 하나의 타입 필드를 갖는 플레인 자바스크립트 객체이다. 액션은 애플리케이션에서 발생하는 무언가를 설명하는 사건이라고 생각할 수 있다.

Reducer

reducer 는 현재 상태와 액션 객체를 파라미터로 받아와서 새로운 상태를 반환해주는 함수이다.

function reducer(state, action) {
  // 새로운 상태를 만드는 로직
  // const nextState = ...
  return nextState;
}

(state, action) => newState
간단하게 리듀서는 받아온 액션(이벤트)의 타입에 근거하여 이벤트를 핸들링하는 event listener라고 생각할 수 있다.

Reducers 쪼개기

애플리케이션이 복잡할때, 특히 애플리케이션이 많은 부분 상태들로 구성될 때 리듀서를 여러개의 함수로 쪼개는 것이 더 쉽습니다. 상태의 형태에 따라 리듀서를 다수의 함수로 쪼갤 수 있으며 각각의 함수들은 상태의 한 부분을 관리할 것입니다.

redux 디렉토리에 dishes.js, comments.jsm promotions.js, leaders.js 파일을 생성해서 리듀서들을 분리해줍니다.

redux/dishes.js 생성하기

import { DISHES } from '../shared/dishes';

export const Dishes = (state = DISHES, action) => {
    switch (action.type) {
        default:
          return state;
      }
};

상태가 정의되어있지않거나 default상태이면 DISHES로 초기화합니다.
여기서 초기화를 해주기때문에 configureStore에서는 initialState가 더이상 필요없어지기때문에 이따가 아래에서 수정해주겠습니다.

redux/comments.js 생성하기

import { COMMENTS } from '../shared/comments';

export const Comments = (state = COMMENTS, action) => {
    switch (action.type) {

        default:
          return state;
      }
};

나머지 세개도 dishes와 마찬가지로 새롭게 파일을 생성해서 리듀서들을 분리해줍니다.

redux/promotions.js 생성하기

import { PROMOTIONS } from '../shared/promotions';

export const Promotions = (state = PROMOTIONS, action) => {
    switch (action.type) {
        default:
          return state;
      }
};

redux/leaders.js 생성하기

import { LEADERS } from '../shared/leaders';

export const Leaders = (state = LEADERS, action) => {
    switch (action.type) {
        default:
          return state;
      }
};

이제 reducer.js 파일을 삭제해도 됩니다.

Reducers 합치기

상태 관리를 부분 상태를 관리하는 서로 다른 리듀서들로 분리했습니다.
이제 그것들을 합쳐볼겁니다.
configureStore.js 파일을 열어서 코드를 다음과 같이 업데이트 합니다.

configureStore.js

import {createStore, combineReducers} from 'redux';
import { Dishes } from './dishes';
import { Comments } from './comments';
import { Promotions } from './promotions';
import { Leaders } from './leaders';

export const ConfigureStore = () => {
    const store = createStore(
        combineReducers({
            dishes: Dishes,
            comments: Comments,
            promotions: Promotions,
            leaders: Leaders
        })
    );

    return store;
}

리듀서들을 합칠 때는 redux에서 제공하는 combineReducers를 사용합니다.

Actions 생성하기

redux/ActionTypes.js 생성하기

export const ADD_COMMENT = 'ADD_COMMENT';

ActionCreators.js 생성하기

import * as ActionTypes from './ActionTypes';

export const addComment = (dishId, rating, author, comment) => ({
    type: ActionTypes.ADD_COMMENT,
    payload: {
        dishId: dishId,
        rating: rating,
        author: author,
        comment: comment
    }
});

comments.js

import { COMMENTS } from '../shared/comments';
import * as ActionTypes from './ActionTypes';

export const Comments = (state = COMMENTS, action) => {
    switch (action.type) {
        case ActionTypes.ADD_COMMENT:
            var comment = action.payload;
            comment.id = state.length;
            comment.date = new Date().toISOString();
            console.log("Comment: ", comment);
            return state.concat(comment);

        default:
          return state;
      }
};

액션이 ActionCreator.js에 의해 디스패치됐을때
액션을 초기화하도록 코드를 업데이트해줍니다.

  • A.concat(B)
    두개의 문자열(배열)을 하나의 문자열(배열)로 만들어주는 함수입니다. 기존의 것들을 변경하지않으며 새로 배열을 생성해서 반환합니다.

MainComponent.js

. . .

import { addComment } from '../redux/ActionCreators';

. . .

  const mapDispatchToProps = dispatch => ({
  
    addComment: (dishId, rating, author, comment) => dispatch(addComment(dishId, rating, author, comment))
  
  });

. . .

      <DishDetail dish={this.props.dishes.filter((dish) => dish.id === parseInt(match.params.dishId,10))[0]}
        comments={this.props.comments.filter((comment) => comment.dishId === parseInt(match.params.dishId,10))}
        addComment={this.props.addComment}
      />

. . .

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Main));

DishdetailComponent.js 내에서 사용할 수 있도록 MainComponent.js 코드를 업데이트 해줍니다.

DishdetailComponent.js

. . .

  function RenderComments({comments, addComment, dishId}) {



. . .

      <CommentForm dishId={dishId} addComment={addComment} />


. . .

        this.props.addComment(this.props.dishId, values.rating, values.yourname, values.comment);



. . .

      <RenderComments comments={props.comments}
        addComment={props.addComment}
        dishId={props.dish.id}
      />

. . .

마지막으로 사용자가 제출한 댓글폼에 따라서 액션을 초기화하도록 DishdetailComponent.js를 업데이트해줍니다.

이제 comment를 작성하고 submit하면 특정 dishId의 comment list에 새롭게 추가되는걸 확인할 수 있습니다.

액션을 사용하여 리덕스 스토어를 변경하고 즉시 리액트 애플리케이션 뷰에 반영하는 방법을 알아보았습니다.

profile
경북대학교 글로벌소프트웨어융합전공/미디어아트연계전공

1개의 댓글

comment-user-thumbnail
2025년 6월 14일

The development and improvement of language programs really brings great creativity. With each sharing are good lessons to develop skills. Join quality resources to accumulate and develop advanced block blast skills.

답글 달기