본문 바로가기

React

TIL 28 React Redux기본

1. Redux란?

 Redux는 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너이다. 쉽게 생각하면 각 컴포넌트마다 관리했던 state값들을

전역에서 관리해주는것이라고 이해하면된다. 프로젝트를 진행하다보면 부모 컴포넌트에서 하위 컴포넌트에다가 state값들을

props로 타고 타고 넘겨주는걸 경험해봤을텐데 이를 하나의 store에다가 관리를 해 어디에서든 접근이 쉽게 만들어준다.

2.  리덕스 프로젝트 구조

└── redux
    ├── index.js   // root reducer
    ├── counter.js // 기능 1
    ├── fetch.js   // 기능 2

 

src파일에다가 redux폴더를 만들어주고 redux의 구성 요소인 Action Type, Action, Reducer 셋을 모두 하나의 파일 안에서 관리하는 패턴으로 구성해준다. 이를 Ducks pattern이라고 한다.

// src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from "redux";
import { Provider } from "react-redux";
import rootReducer from "./redux";
import FunctionCounter from './FunctionCounter';
import ClassCounter from './ClassCounter';

const store = createStore(rootReducer);

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

 

기본적으로 src/index.js에서 가장 상위에다가 <Provider>태그로 감싸줘야한다. 그리고 store속성에다 위에서 변수 store을 달아준다.

 

// src/redux/index.js

import { combineReducers } from "redux";
import fetch from './fetch'
import counter from './counter';

const rootReducer = combineReducers({
  fetch,
  counter
});

export default rootReducer;

 

redux폴더안에 있는 index.js에서 rootReducer을 선언을 해주는데 이때 리덕스에서 제공해주는 combineReducers을 통해서

2개 이상의 Reducer들을 관리가 가능하다.

 

// src/redux/counter.js

const initialState = { count: 10};

const INCREASE = 'counter/INCREASE'
const DECREASE = 'counter/DECREASE'

export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });

export default function counter(state = initialState, action) {
  switch (action.type) {
    case INCREASE:
      return { count: state.count + 1 };
    case DECREASE:
      return { count: state.count - 1 };
    default:
      return state;
  }
}

 

initialState라는 변수에다가 state를 관리하고(초기 상태 선언) , INCREASE, DECREASE는 액션 타입을 만드는 과정이다.

그 다음에 increase, decrease는 액션 생성함수를 선언한거다. 마지막으로 counter라는 리듀서를 생성한거다.

리듀서에서 액션 타입에 따라 어떤걸 실행할지 switch, case문으로 결정한다.

3. 함수형 컴포넌트에서 적용해보기

import React from 'react'
import { useDispatch, useSelector } from "react-redux";
import { increase, decrease } from './redux/counter';

const FunctionCounter = () => {
  const counter = useSelector((store) => store.counter)
  const dispatch = useDispatch();

  return (
    <div>
      <h1>Hello Redux</h1>
      <h2>{counter.count}</h2>
      <button onClick={()=>{dispatch(increase())}}>+</button>
      <button onClick={() => {dispatch(decrease())}}>-</button>
    </div>
  )
}

export default FunctionCounter

 

함수형 컴포넌트에서는 useSelector라는 hook을 사용해서 쉽게 리덕스의 state값에 조회할 수 있다. useDispatch hook을 통해서

액션을 실행 할 수 있게한다. 그래서 +버튼을 누르게되면 increase() 액션이 실행되고 type이 INCREASE이므로 count가 +1

되는걸 확인할 수 있다.

4. 클래스형 컴포넌트에서 적용하기

import React, { Component } from 'react'
import { connect } from 'react-redux';
import * as counterAction from './redux/counter'

class ClassComponent extends Component {
  
  render() {
    const {count, increase, decrease} = this.props
    return (
      <div className="ClassCounter">
        <h1>Hello Redux</h1>
        <h2>{count}</h2>
        <button onClick={increase}>+</button>
        <button onClick={decrease}>-</button>

      </div>
    )
  }
}

const mapStateToProps = (state) => ({
  count: state.counter.count
});

const mapDispatchToProps = (dispatch) => ({
  increase: () => dispatch(counterAction.increase()),
  decrease: () => dispatch(counterAction.decrease())
});

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

 

Class형에서는 hook을 지원하지 않기때문에 connect함수로 적용해야된다. mapStateToProps와 mapDispatchToProps로

각각 store에 저장되있는 state값과 dispatch()로 액션 실행 함수를 가져와야한다. 이값들은 해당 컴포넌트의 props로 전달해준다.

그래서 render함수 밑에 구조분해할당으로 값들을 받아온것을 볼 수 있다.

'React' 카테고리의 다른 글