본문 바로가기

React

[React] Redux를 이용하여 값을 증감시키는 예제

 

[해당 포스트는 개인적으로 공부를 하고 차후에 참고용으로 하고자 작성한 것입니다.
따라서 잘못된 부분이나 부족한 부분이 있을 수 있기에 참고하시기 바랍니다.]

저번 시간에 작성했던 Redux 개념을 기반으로 간단한 예제를 만들어보자.

 

Redux를 이용한 숫자 증감 기능 만들기

-프로젝트 구성

  1. actions: Action을 처리하기 위해 만들어진 파일들의 폴더
    • index.js - 외부에 export 하기 위해 사용되는 Script
    • mainAction.js - Redux Action을 담당하는 Script
      • function actionIncrement(): 값을 증가시키는 Action
      • function actionDecrement(): 값을 감소시키는 Action
  2. components: View를 처리하기 위해 만들어진 파일들의 폴더
    • Count.js - 증감된 숫자를 표현하기 위한 Component
    • Button.js - 숫자를 증감할 수 있는 버튼을 추가하기 위한 Component
  3. containers: View Component에 기능을 추가하기 위해 만들어진 파일들의 폴더
    • App.js - Button Component와 Count Component를 가져와, 기능을 추가할 수 있도록 설정하는 Component
      • const mapStateToProps(state): Reducer에서 처리한 값을 Store에 전달하는 함수
      • const mapDispatchToProps(dispatch): Action을 Dispatch 하기 위한 함수
  4. reducers: Reduce를 처리하기 위해 만들어진 파일들의 폴더
    • index.js - 외부에 export 하기 위해 사용되는 Script
    • mainReducer.js - Redux reduce를 담당하는 Script
      • const reducerCount(state, actions): Action으로부터 받은 요청을 처리하여 state를 갱신하는 함수
      • const reducer: conbineReducers()를 호출하여 Reducer들을 병합시킴

- 프로젝트 View 구성하기

숫자 출력및 버튼을 생성한다.

+, - 버튼을 통해 출력된 숫자 값을 변화를 주도록 한다.

 

components

-Count.js

import React from 'react';

const Count = () => {
    return (
        <div>
            <h1>Redux Count</h1>
           <h1>0</h1> 
        </div>
    );
};

export default Count;

 

-Button.js

import React from 'react';

const Button = () => {
    return (
        <div>
            <button>+</button>
            <button>-</button>
        </div>
    );
};

export default Button;

 

containers

-App.js

import React from 'react';
import Count from '../components/Count';
import Button from '../components/Button';

const App = () => {
    return (
        <div style={{textAlign : 'center'}}>
            <Count/>
            <Button/>
        </div>
    );
};

export default App;

 

# Action Creator 생성

Redux의 Action을 생성하며, Action을 호출할 수 있는 Action Creator를 생성한다.

 

- mainAction.js

export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';

export const actionIncrement = () => {
    return {
        type: INCREMENT
    }
}

export const actionDecrement = () => {
    return {
        type: DECREMENT
    }
}

 

action의 구조는 type이 기본적으로 붙는다. 이후 추가적으로 key를 설정하여 추가 인자를 받을 수 있다.

actionIncrement는 INCREMENT type의 Action에 대한 Action Creator이다.

actionDecrement는 DECREMENT type의 Action에 대한 Action Creator이다.

 

-index.js

export { actionIncrement, actionDecrement, INCREMENT, DECREMENT } from './mainAction';

 

# Reducer 생성

combineReducers Function을 사용하기 위해 redux Module을 설치한다.

 

mainReducer.js

import { combineReducers } from 'redux';
import { INCREMENT, DECREMENT } from '../actions';

const initState = {
    value : 0,
    diff : 1
}

const reducerCount = (state = initState, actions) => {
    switch(actions.type){
        case INCREMENT:
            return state = {
                ...state,
                value : state.value + state.diff
            };
        case DECREMENT:
            return state = {
                ...state,
                value : state.value - state.diff
            };
        default:
            return state;
    }
}

export const reducer = combineReducers({
    reducerCount
})

 

Redux에 대한 기본 State는 Reducer에서 초기화 시킨다. 이후 reducerCount에서 지속적으로 갱신한다.

Action이 Dispatch되면 Reducer에게 처리가 넘어온다. reducerCount의 내부는 switch 문으로 구성된다.

Dispatch로 넘어온 actions의 Type에 따라 분기하여 처리를 다르게 만든다.

 

combineReducers는 여러개의 Reducer를 병합하여 Store에 전달할 수 있다. 여기선 Reducer를 한 개만 사용하기에 combineReducers를 사용 안 해도 되지만, 공부 차원에서 사용해보도록 하자.

 

- index.js

export { reducer } from './mainReducer';

 

# Store 생성

Provider를 사용하기 위해 react-redux Module을 설치하고, createStore Fuction을 사용하기 위해 redux Module을 설치하자.

 

- /src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './containers/App';
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux';
import { createStore } from 'redux';

import { reducer } from './reducers';

const store = createStore(reducer);

ReactDOM.render(<Provider store = {store}>
    <App />
</Provider>, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

createStore 함수를 이용하여 Store를 생성한다. Store는 Reducer를 인자로 받아 생성한다.

이 후 <App /> 태그를 Provider를 통해 감싼다. Provider의 type 중 하나인 store를 통해 위에서 생성한 Store를 넣어준다.

 

이로써 Action, Reducer, Store를 모두 설정했다.

다음으로 생성한 Redux 구조를 이용하여 Component에 적용시켜보자.

 

# Component에 Redux 적용하기

Component에 Redux를 연결하기 위해 connect를 호출해야 한다. connect 함수는 react-redux Module에 존재한다.

 

'mapDispatchToProps': Action에서 생성한 Action Creator를 Dispatch 하기 위한 함수. Action에서 생성한 Action Creator를 가져와서 사용한다. Action을 Dispatch 하면 Action은 Reducer에게 신호를 준다.

'mapStateToProps': Reducer에서 갱신된 state를 Store에 넘겨준다.

 

- App.js

import React from 'react';
import Count from '../components/Count';
import Button from '../components/Button';
import { connect } from 'react-redux';
import { actionIncrement, actionDecrement } from '../actions';

const App = (props) => {
    
    return (
        <div style={{textAlign : 'center'}}>
            <Count value = {props.value}/>
            <Button onClickIncrease = {props.onClickIncrease}
                    onClickDecrease = {props.onClickDecrease}/>
        </div>
    );
};

const mapDispatchToProps = (dispatch) => ({
    onClickIncrease : () => { dispatch(actionIncrement()) },
    onClickDecrease : () => { dispatch(actionDecrement()) }
});

const mapStateToProps = (state) => {
    return {
        value : state.reducerCount.value
    };
};

export default connect(mapStateToProps,
     mapDispatchToProps)(App);

 

React가 처음 실행되면 실행 순서는 다음과 같다.

 

Reducer -> mapStateToProps -> Store -> mapDispatchToProps

 

Reducer에서 먼저 state를 초기화하고 이를 mapStateToProps에 넘긴다. 이후 Store에 전달시켜 등록된 Component의 상태와 state를 저장한다. 이후 mapDispatchToProps를 호출하여 mapDispatchToProps에서 생성한 함수를 Redux에 연결된 Component에게 props로 전달하게 된다.

따라서 App Component는 Reducer의 State와 mapDispatchToProps의 함수를 자신의 props에 받아와 자식 Component에게 해당 기능을 전달할 수 있게 된다.

 

- Count.js

import React from 'react';

const Count = ({value}) => {
    return (
        <div>
            <h1>Redux Count</h1>
           <h1>{value}</h1> 
        </div>
    );
};

export default Count;

 

App.js로부터 받은 Redux의 value 값을 출력시킨다.

 

- Button.js

import React from 'react';

const Button = ({ onClickIncrease, onClickDecrease }) => {
    return (
        <div>
            <button onClick = {onClickIncrease}>+</button>
            <button onClick = {onClickDecrease}>-</button>
        </div>
    );
};

export default Button;

 

App.js에서 받은 onClickIncrease와 onClickDecrease를 받아와 버튼의 onClick에 넣는다.

 

이로써 Redux 연결이 다 되었다. + 버튼을 클릭하면 값이 올라가고, - 버튼을 클릭하면 값이 내려갈 것이다.

value는 Redux의 state에서 갱신되어 항상 최신의 값을 가져오게 된다.