본문 바로가기

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' 카테고리의 다른 글

React Img Slider 구현(useRef)  (0) 2022.03.13
TIL 22 React ref  (0) 2021.11.21
TIL 21 리액트 Router Nav바 숨기기  (0) 2021.11.19
TIL 20 리액트 함수형 컴포넌트(useState)  (0) 2021.11.18
TIL 19 Props로 받은값 State로 넘기기  (0) 2021.11.10