본문 바로가기
프로그래밍/react

[220502] redux로 전역상태 관리하는 기초세팅

by 한코코 2022. 5. 9.

state 관리를 위한 redux

액션이란 이벤트를 통해 상태를 관리하고 업데이트하기 위한 패턴 및 라이브러리인 redux.

예측 가능한 방식으로만 업데이트 될 수 있도록 하는 규칙과 함께 전체에서 사용해야 하는 상태에 대한 중앙저장소 역할을 함.

 

Context API와 비슷한데 왜 Redux를 더 많이 사용할까?

1. 전체적으로 사용하는 state가 언제 어디서 어떻게 업데이트 되는지 자세하게 추적이 가능하다.

2. Context API와 다르게 redux는 미들웨어가 있어서 비동기처리가 가능하다.

  • redux의 reducer가 state를 바로 반환하지 못하고, 미들웨어를 거쳐야 반환이 가능하다
  • 예) 로그인 시도 -> 미들웨어 (성공액션, 실패액션, 에러액션) -> 결과에 따른 state 반환

Redux 공식 사이트 : https://ko.redux.js.org/introduction/getting-started/

 

 

 

 


redux 라이브러리 설치

$ npm init -y
$ npm install redux react-redux
$ npm install redux-devtools-extension 
// dev툴과 연결해주는 라이브러리

 

 

 

redux 세팅 - 생성

reducer를 사용하기 위한 state, action을 넣고,

action안의 type에 따라 state 값이 달라지는 기능을 switch문으로 짜서 넣었다.

type은 오타가 나면 찾기 어려운 string대신 변수로 만들어 넣었다. 

//reducer.js
const initialState = {number: 0}

const UP = "COUNTER/Up"
const DOWN = "COUNTER/Down"
export const up = () => ({type:UP})
export const down = () => ({type:DOWN})

const rootReducer = (state = initialState, action) => {
  switch(action.type){
    case UP:
      return{
        ...state,
        number:state.number+1
      }
    case DOWN:
      return{
        ...state,
        number:state.number-1
      }
    default:
      return state
  }
}

 

 

 



redux 세팅 - dispatch를 호출해서 state값을 바꾸기

state 값을 바꿀 dispatch를 사용하기 위해 reducer에서 만들었던 변수를 가져왔다.

Context API에서는 임의로 dispatch를 만들어야했지만 redux는 useDispatch메서드로 만들 수 있다.

useSelector메서드는 리액트에 존재하는 모든 state값을 가져와 counter 변수에 저장해준다.

//index.js
import {up,down} from "../../reducers"
import {useSelector,useDispatch} from 'react-redux'

const Counter = () => {
  const counter = useSelector((state)=>state)
  const dispatch = useDispatch()

  const onUp = () => {dispatch(up())}
  const onDown = () => {dispatch(down())}

  return (
    <>
      <h2>Counter : {counter.number}</h2>
      <button onClick={onUp}>+1</button>
      <button onClick={onDown}>-1</button>
    </>
  )
}

 

 

 

 

 

redux 세팅 - Store 생성

redux는 전역함수가 아니라 상태라는 것을 기억하자.

redux는 객체를 반환하는 함수이며, 다음과 같은 세가지 속성이 자주 쓰인다.

-  createStore : function
-  applyMiddleware : function
-  combineReducers : function

const redux = require('redux')
const {createStore} = redux //state

 

현재는 리액트가 업데이트 되어서 createStore 대신 configureStore을 사용한다.

지금은 미들웨어를 쓰지 않을것이라서 미들웨어는 빼뒀다.

Store 컴포넌트 내부 컴포넌트들이 Store가 가진 데이터를 쓸 수 있도록 

store(고정변수)에 configureStore로 생성한 store를 넣어주었다.

Store 컴포넌트 내부 컴포넌트들을 바깥에서도 볼 수 있도록 children으로 내부 속성값을 사용.

// useStore.jsx
import {configureStore} from "@reduxjs/toolkit"

const store = configureStore({ 
  reducer : rootReducer, // 사용할 리듀서 정의
  // middleware: [...middlewares], // 사용할 미들웨어 정의
  // 기본적으로 composeWithDevTools이 적용되어있음
})

const Store = ({children}) => {
  return (
    <Provider store={store}>
      {children}
    </Provider>
  )
}

 

전역으로 데이터를 관리해야한다면 가장 최상위로 가야한다.

Store 컴포넌트로 최상위 App 컴포넌트를 감싸주었다.

//index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import Store from './store/useStore'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Store>
      <App />
    </Store>
  </React.StrictMode>
);

 

 

 

 

 


잘 생성되었는지 체크 - 만약 +1 버튼을 클릭힌다면

button의 onClick이 발동되면서 onUp메서드가 실행되고, dispatch(up())메서드가 실행된다.

type을 UP으로 입력받은 reducer 컴포넌트에선 본래 state에서 number속성에 1을 더한 값을 반환한다.

//reducer.jsx
export const up = () => ({type:UP})
case UP: return { ...state, number:state.number+1 }

useSelector는 갱신된 state값을 받아서 다시 counter에 넣어준다.

//index.jsx
const counter = useSelector((state) => state)

initialState:{number:0}으로 초깃값을 정해놓았으므로 counter.number는 0에 1을 더한 1이 된다.

만들어놓은 Store 컴포넌트는 이런 흐름이 가능하도록 데이터를 전역적으로 저장해주고있다.

<h3>Counter : {counter.number}</h3>

댓글