[React] Redux

eslim·2020년 12월 23일
0

React

목록 보기
5/5
post-thumbnail

Redux

React와 Redux

  • React는 컴포넌트 개별적으로 상태관리를 하는데 redux는 상태관리를 하는 전용 장소(store)에서 상태 관리를 한다.

Store

  • 생태 관리로, 규모가 클 경우 카테골리별로 분류하는 경우가 일반적이다.
{
    // 세션과 관련된 것
    session: {
        loggedIn: true,
        user: {
            id: "114514",
            screenName: "@mpyw",
        },
    },
 
    // 표시중인 타임라인에 관련된 것
    timeline: {
        type: "home",
        statuses: [
            {id: 1, screenName: "@mpyw", text: "hello"},
            {id: 2, screenName: "@mpyw", text: "bye"},
        ],
    },
 
    // 알림과 관련된 것
    notification: [],
}

Action 및 Action Creator

  • Store에 존재하는 State에 직접 접근하기 위해서는 action을 거쳐, reducer가 action의 발생을 감지하면, state를 경신된다.
{
    type: "액션의 종류를 한번에 식별할 수 있는 문자열 혹은 심볼",
    payload: "액션의 실행에 필요한 임의의 데이터",
}

export const ADD_VALUE = '@@myapp/ADD_VALUE';
export const addValue = amount => ({type: ADD_VALUE, payload: amount});

Reducer

  • 이전 상태와 Action 을 합쳐, 새로운 state 를 만드는 조작
import { ADD_VALUE } from './actions';
 
export default (state = {value: 0}, action) => {
    switch (action.type) {
        case ADD_VALUE:
            return { ...state, value: state.value + action.payload };
        default:
            return state;
    }
}

초기 상태는 reducer의 디폴트 인수에서 정의된다.
상태가 변할 때 전해진 state는 그 자체의 값으로 대체되는 것이 아니라 새로운 것이 합셩되는 것처럼 쓰여진다.

대규모 개발로 reducer를 분할하는 경우 redux에서 제공하는 combineReducers 함수를 이용한다.

import { combineReducers } from 'redux';
 
const sessionReducer = (state = {loggedIn: false, user: null}, payload) => {
    /* 省略 */
};
const timelineReducer = (state = {type: "home", statuses: []}, payload) => {
    /* 省略 */
};
const notificationReducer = (state = [], payload) => {
    /* 省略 */
};
 
export default combineReducers({
    session: sessionReducer,
    timeline: timelineReducer,
    notification: notificationReducer,
})

reducer분할에 쓰인 key가 그대로 state 분할에도 쓰인다.

순수한 component와 연결된 component

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addValue } from './actions';
 
const Counter = ({ value, dispatchAddValue }) => (
    <div>
        Value: {value}
        <a href="#" onClick={e => dispatchAddValue(1)}>+1</a>
        <a href="#" onClick={e => dispatchAddValue(2)}>+2</a>
    </div>
);
 
export default connect(
    state => ({ value: state.value }),
    dispatch => ({ dispatchAddValue: amount => dispatch(addValue(amount)) })
)(Counter)

component가 store 로부터 정보를 받는 경우, props를 통해 받으며, 이는 상태가 변경될때마다 새로운 component가 다시 만들어진다는 의미이다.

  • Store가 가진 state를 어떻게 props에 엮을 지 정한다(이 동작을 정의하는 함수는mapStateToProps라고 불립니다)
  • Reducer에 action을 알리는 함수 dispatch를 어떻게 props에 엮을 지 정한다(이 동작을 정의하는 함수는mapDispatchToProps라고 불립니다)
  • 위에 두가지가 적용된 props를 받을 Component를 정한다
  • Store와 Reducer를 연결시킬 수 있도록 만들어진 Component가 반환값이 된다

mapStateToProps

카운터의 예를 다시 보면,

{
    value: 2,
}

<Counter value={2} />

로 들어가길 바라며
state => ({ value: state.value})## 라고 썼다. 기본적으로 필요한 것만 선별하여props로 엮는다

mapDispacthToProps

  • Reducer를 향해 통지를 할 수 있게 만들기 위해서는 만든 action을 dispatch라는 함수에 넘겨줘야만 한다.
    이렇게 하면 모든 Reducer가 실행 된다. Reducer에 switch문으로 분기를 나눈 것은 바로 이 때문이다. Reducer는 관계없는 action을 무시하고, 자기에게 주어진 action만을 처리하도록 되어있어야만 한다.
    Component 쪽에 하나하나 수동으로dispatch하는 처리를 하지 않아도 되도록, 여기서 action의 생성부터dispatch의 실행까지 한번에 이뤄질 수 있도록 함수를 정의하여props에 넘겨주도록 한다

bindActionCreators

  • mapDispatchToProps에서 생략이 가능한 함수

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addValue } from './actions';
 
 
const Counter = ({ value, addValue }) => (
    <div>
        Value: {value}
        <a href="#" onClick={e => addValue(1)}>+1</a>
        <a href="#" onClick={e => addValue(2)}>+2</a>
    </div>
);
 
export default connect(
    state => ({ value: state.value }),
    { addValue }
)(Counter)

0개의 댓글