Redux - 상태 관리 라이브러리

@Joy Lee · February 20, 2022 · 6 min read

💡 Redux란?

Redux란 '상태 관리 라이브러리'로써 기존에 흩어져 있는 state들을 한 곳에 모아 관리하여 예측 불가능한 버그를 최소화하고 효율적으로 state를 사용할 수 있도록 합니다. 또한 Redux는 React 외에도 Angular, Vue, jQuery 등 다양한 환경에서 사용할 수 있습니다.

why-using-redux

  • React에서의 상태관리

    React에서의 상태는 props를 통해 각 컴포넌트로 전달됩니다. 특정 컴포넌트에서 state가 변화하면 props로 연결된 모든 컴포넌트가 함께 업데이트 됩니다.

  • Redux에서의 상태관리

    Redux에서의 상태는 컴포넌트끼리 공유하지 않고 store라는 파일을 거쳐 필요한 컴포넌트로 즉시 전달됩니다. (store : 앱에서 사용되는 모든 state를 저장하고 관리하는 장소)

📝 Redux의 3원칙

  1. Single source of truth

    필요한 상태 데이터는 모두 store라는 데이터 공간에 저장하고 관리됩니다.

  2. State is read-only

    리액트에서 useState로 상태 변경을 하듯이 리덕스에서는 action이라는 객체를 통해서만 상태를 변경할 수 있습니다. (예측 가능)

  3. Changes are made with pure functions

    상태 변경은 순수함수(reducer)로만 가능합니다.

redux

🎉 Redux 시작하기

0. Redux 설치 및 폴더 구조

npm install redux react-redux
redux/
├── actions/
│   ├── index.js # 액션 엔트리
│   ├── actionTypes.js # 액션 타입 상수 파일
│   ├── auth.js # action 1
│   └── counter.js  # action 2
├── reducers/
│   ├── index.js # 리듀서 엔트리 (rootReducer)
│   ├── auth.js # reducer 1
│   └── counter.js # reducer 2
└── store.js # 스토어 엔트리 (스토어 생성)

1. action 생성

action : 객체 형식으로 컴포넌트에서 상태 변경을 요청할 때 사용

  • type : 액션명 (필수)
  • payload : 변경할 상태 값 (옵션)

action 생성 시 필요한 값으로는 typepayload 가 있는데 이때, type은 파일을 별도로 만들어 상수(constant)로 관리하는 것이 유지 보수 하기 좋습니다.

// actions/actionTypes.js
export const LOG_IN = "LOG_IN"
export const LOG_OUT = "LOG_OUT"
export const INCREASE_COUNT = "INCREASE_COUNT"
export const DECREASE_COUNT = "DECREASE_COUNT"
//actions/auth.js
import { LOG_IN, LOG_OUT } from "./actionTypes"
// 로그인 요청 action
export const login = user => ({
  type: LOG_IN,
  payload: user, // 전달받은 상태값을 payload에 저장
})
// 로그아웃 요청 action
export const logout = () => ({
  type: LOG_OUT,
})

2. reducer 생성

reducer : action 에 맞게 state를 업데이트 하는 함수

reducer는 상태(state)와 액션(action)을 전달 받아 '현재 상태'를 '새로운 상태'로 교체 한 후 반환하는 함수이며 주로 switch ~ case 문으로 작성합니다.

const initialState = {
  user: '',
  loading: false
};
const reducer = (state = initialState, action) {
  switch(action.type) {
    case LOG_IN:
      return {
        ...state, // 현재 상태를 가져와
        user: action.payload // 전달받은 payload값으로 교체
      }
    case LOG_OUT:
      return {
        ...state,
        user: ''
      }
    default:
      return state
  }
}

reducer 파일이 여러개라면 index.js 파일을 만들고 combineReducers를 사용해 reducer를 하나로 합쳐주는 rootReducer를 생성합니다.

// reducers/index.js
import { combineReducers } from "redux"
import { authReducer, counterReducer } from "reducers"
export const rootReducer = combineReducers({
  auth: authReducer,
  counter: counterReducer,
})

3. store 생성

store : 모든 상태가 저장되는 공간

만들어둔 reducer(or rootReducer) 함수를 createStore에 전달하여 store를 생성합니다.

import { createStore } from "redux"
const store = createStore(rootReducer)
export default store

🔎 Redux 사용하기

- Provider

Provider : store에 저장된 상태값을 컴포넌트로 전달

모든 컴포넌트에서 store에 접근할 수 있도록 최상단 컴포넌트(App)를 Provider로 감싸주고 store를 전달합니다.

import React from "react"
import ReactDOM from "react-dom"
import { App } from "./App"
import { Provider } from "react-redux"
import store from "redux/store"

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

- useSelector

useSelector : store에 저장된 상태값 가져와서 사용

import { useSelector } from "react-redux"

export const mainPage = () => {
  const user = useSelector(state => state.auth.user)

  return <div>{user}님 환영합니다</div>
}

- useDispatch

useDispatch : action을 실행시켜 store의 상태값 업데이트

import { useDispatch } from "react-redux"
import {login} from "actions/auth.js"

export const loginPage = () => {
  const [value, setValue] = useState('');
  const dispatch = useDispatch()

  // login 액션을 실행시켜 input value값을 store로 전달!
  const handleLogIn = () => {
    dispatch(login(value))
  }

  return (
    <input value={value} type="text"/>
    <button onClick={handleLogIn}>Log In</button>
  )
}


REFERENCE
Youtube 생활코딩 https://youtu.be/yjuwpf7VH74
야무의 React 러닝 가이드 https://yamoo9.github.io/react-master/lecture/rd-redux.html

Joy Lee
FRONTEND DEVELOPER