최고 리덕스야 고맙다! Redux & Redux Toolkit 알아보기

DANO PARK·2022년 5월 25일
39

무작정 따라하기

목록 보기
7/9
post-thumbnail

What is Redux?

리덕스는 상태 관리 라이브러리 중 하나로, 현재까지 가장 많이 쓰이고 있다.

상태 관리란 UI와 UX에 맞게 데이터를 관리하거나, 서버와 주고 받는 데이터를 관리하는 것을 말한다.

간단한 프로젝트라면 괜찮겠지만, 복잡하고 크기가 큰 대형 프로젝트라면 상태 관리의 난도는 크게 올라간다. 리액트의 state 끌어올리기를 생각해보자. 한 컴포넌트의 함수를 props 형태로 다른 컴포넌트로 전달하고 또 그것을 props 형태로 또 다른 컴포넌트로 전달하고... 이런 복잡한 구조는 불필요한 props 전달로 유지보수 또는 props 추적을 힘들게하는 Props drilling을 야기한다.

상태 관리 라이브러리는 이러한 문제들을 해결하기 위해 고안되었다.

위의 그림은 기존 상태 관리 방식을 시각화한 것이다. 위 그림처럼 상태 변경이 한 번 일어났을 뿐인데 해당 데이터를 변경하기 위해 또 다른 상태 변경이 여러 번 일어나고 있다. 이러한 구조는 오류를 야기할 수 있으며, 발생한 오류를 잡아내기도 쉽지 않다.

그러나 리덕스는 Reducer와 Store를 통해 상태 변경 과정을 간소화하여 기존의 문제를 해결했다. 이것은 복잡한 상태 관리를 매우 효율적이고 간편하게 변경하여 오류 발생률을 낮추게 한다.

Redux 기본 용어

리덕스의 기본 용어에 대해서 알아보자.

Store

스토어는 컴포넌트의 상태를 관리하는 저장소다. 하나의 프로젝트는 하나의 스토어만 가질 수 있다.

Action

스토어의 상태를 변경하기 위해서는, 액션을 생성해야한다. 액션은 객체이며, 반드시 type을 가져야 한다. 액션 객체는 액션생성함수에 의해서 만들어진다.

Reducer

리듀서는 현재 상태와 액션 객체를 받아 새로운 상태를 리턴하는 함수다.

Dispatch

디스패치는 스토어의 내장 함수 중 하나이며, 액션 객체를 넘겨줘 상태를 업데이트 시켜주는 역할을 한다.

Subscribe

스토어의 내장 함수 중 하나로, 리듀서가 호출될 때 서브스크라이브된 함수 및 객체를 호출한다.

아래의 그림으로 위의 용어들을 이해해보자.

  1. UI가 처음 렌더링될 때, UI 컴포넌트는 리덕스 스토어의 상태에 접근하여 해당 상태를 렌더링한다.

  2. 이후 UI에서 상태가 변경되면, 앱은 디스패치를 실행해 액션을 일으킨다.

  3. 새로운 액션을 받은 스토어는 리듀서를 실행하고 리듀서를 통해 나온 값을 새로운 상태로 저장한다.

  4. 서브스크라이브된 UI은 상태 업데이트로 변경된 데이터를 새롭게 렌더링한다.

Redux 사용하기

리덕스를 사용하기 위해서는 먼저 리덕스를 설치해야 한다.

$ npm install redux

리액트 환경이라면 추가로 react-redux를 설치해야한다.

$ npm install redux react-redux

Store 만들기

리덕스 설치가 완료되었다면, 스토어를 만들어 주자. 스토어는 createStore()를 통해 만들 수 있다.

import { createStore } from 'redux';

그러나 리덕스 4버전 이상일 경우 아래와 같은 경고 메세지가 나타난다.

경고 메세지는 스토어를 만들때 리덕스의 createStore()를 사용하기보단, 리덕스 툴킷의 configureStore()를 사용할 것을 요구한다.

리덕스 툴킷을 이용해 기존 리덕스 문법보다 훨씬 쉬운 방법으로 상태 관리를 할 수 있는데, 리덕스 개발사 쪽에서 리덕스 툴킷을 쓰라고 하는 것 같다.

Redux Toolkit 사용하기

리액트 환경에서 아래의 카운트업 코드를 리덕스 툴킷을 통해 만들어 보자.

// App.jsx

import React, { useState } from 'react'

export default function App() {
  const [counter, setCounter] = useState(0);

  const minus = () => {
    setCounter(prev => prev - 1);
  }
  const plus = () => {
    setCounter(prev => prev + 1);
  }

  return (
    <div>
      <button onClick={minus}>-</button>
      Value: { counter } 
      <button onClick={plus}>+</button>
    </div>
  );
}

리덕스 툴킷 역시 설치가 필요하다.

npm install @reduxjs/toolkit

리액트 환경이라면 react-redux 설치가 필요하다.

Store 연동하기

Providerreact-redux에서 리액트 앱에 스토어를 연동할 수 있게 해주는 컴포넌트다. 아래와 같이 Provider 컴포넌트를 불러와 연동할 컴포넌트를 감싸준 뒤, Provider의 props로 사용할 스토어를 지정해주면 된다.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

import { Provider } from "react-redux";
import store from "./store/store.js";

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

Store 만들기

먼저 store.js에 configureStore()로 스토어를 만들어주자.

// store.js

import { configureStore } from '@reduxjs/toolkit';

export const store = configureStore({
	reducer: counterSlice,
    middleware: [...middlewares]
})

기존 리덕스에서는 스토어 생성 후 미들웨어가 한 개 이상이라면, 여러 메서드를 통해 긴 코드를 작성해야 했다.

configureStore()는 별도의 메서드 없이 바로 미들웨어를 추가할 수 있다는 장점이 있다.

createSlice 생성

기존 리덕스에서는 액션을 디스패치하기 위한 별도의 함수가 필요했고, 액션의 객체를 리듀서를 통해 리턴하는 구조였다.

createSlice()는 액션에 대한 함수 설정과 리듀서를 따로 생성하지 않아도 된다.

아래는 createSlice()를 사용한 카운트업 코드와 그에 대한 설명이다.

// countSlice.jsx

import { createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    plus: state => {
      state.value += 1
    },
    minus: state => {
      state.value -= 1
    },
  },
})

export const { plus, minus } = counterSlice.actions; 
export default counterSlice.reducer;
  • initialState를 통해 state의 처음 상태를 정의한다.
  • reducers에서 액션을 설정한다.
  • plusmius를 export해서 App.jsx에 import한다.
  • slice는 slice.reducer로 내보낸다. store.js는 위 파일을 전부 리듀서로 받는다.

useSelector, useDispatch로 상태 접근하기

useSelector()는 기존 리덕스의 connect()를 이용하지 않고 리덕스의 상태를 조회할 수 있다.

useDispatch()는 생성한 액션을 발생시키며, 액션생성 함수를 가져온다. 위 설명의 디스패치와 같다고 보면 된다.

아래는 useSelector()useDispatch()에 대한 설명이다.

// App.jsx

import React from 'react'
import { useDispatch, useSelector } from 'react-redux';
import { plus, minus } from './counter/countSlice01';

export default function App() {
  const count = useSelector(state => state.counter.value);
  const dispatch = useDispatch();

  return (
    <div>
      <button onClick={() => dispatch(minus())}>-</button>
      Value: { count } 
      <button onClick={() => dispatch(plus())}>+</button>
    </div>
  );
}
  • useSelector()로 스토어에서 현재 상태 값을 가져온다.
  • useDispatch()를 통해 변경되는 값을 스토어로 전달한다.

끝.

profile
단오해서 단호박!

2개의 댓글

comment-user-thumbnail
2022년 11월 8일

리덕스민수야 고맙다🙏

답글 달기
comment-user-thumbnail
2023년 2월 24일

썸네일 ㅋㅋㅋㅋㅋㅋㅋ 최고민수 ㅋㅋㅋㅋㅋㅋ 🤣

답글 달기