Redux Toolkit 정리

moreas·2023년 2월 17일
0

팀 프로젝트

목록 보기
2/14
post-thumbnail

리덕스 툴킷을 배우려면 우선 리액트 리덕스의 동작 원리에 대해 간단히 알아야 한다.

🟣 왜 Redux 일까?

리액트에서 상태관리를 할 때,
=> 쉽게 말해 props를 전송하고 state의 데이터를 수정하고 싶을 때, 별다른 방법이 없다면 부모 컴포넌트와 자식 컴포넌트로 이어진 수 억 개의 props를 전달하기 위해 수 억 개의 코드를 일일이 생성하거나 수정해야 한다.
리덕스는 이러한 과정을 축약하고 단순하고 편리하게 상태 관리를 할 수 있게 만드는 도구이다.

하위 컴포넌트에 있는 state와 state를 바꾸는 event를 (유선->)무선으로 간편하게 연결하고 싶다면!
그 꿈을 실현해주는 도구가 redux.

리덕스를 사용하면 사용하는 해당 state의 값만 바뀌고 상위 컴포넌트들은 리렌더링 되지 않는다.

➡️ 리액트를 사용하며 생산성이 높아지는 효과





리덕스, 어떻게 사용하면 되는데?




function reducer(currentState, action) {
  if (currentState === undefined) {
    return {
      number: 1,
    };
  }
  const newState = {...currentState}
  if(action.type === 'PLUS'){
    newState.number++;
  }
  return newState;
}

const store = createStore();
  • createStore를 생성할 때 반드시 같이 생성해야 하는 것은 reducer.

  • reducer함수는 store 안에 있는 state를 어떻게 바꿀 것인지 결정하기 때문에 리듀서는 두 개의 파라미터 받음.
function reducer(현재스테이트값, action(변경 요청받는 값))
=
useState [number, setNumber] 
// 두 가지가 비슷한 역할이라고 이해했다. 


  • 그렇게 받은 값을 리턴해주면 리턴한 값이 새로운 스테이트의 값이 됨.
    이때 리덕스는 각각의 스테이트의 변화를 불변성을 유지해야 하는데, 그러기 위한 방법은 새로운 스테이트를 만들고, 과거의 스테이트를 복제한다. (우리는 복제본을 수정해서 사용하면 불변성을 유지할 수 있다.) 그렇게 변화시킨 스테이트를 리턴한다.
 const newState = {...currentState}
 
  return newState;


  • 만약 currentState 값이 undefined라면 (=스테이트가 정의되지 않았다면) 기본 state 값을 리턴하여 설정해줄 수 있다.
if (currentState === undefined) {
    return {
      number: 1,
    };




리액트 리덕스의 대표 4인방

커넥트는 설명에서 제외한다.

import { Provider, useSelector, useDispatch, connect } from 'react-redux';



Provider

리액트의 Context API 처럼 컴포넌트를 감싸주는 역할을 한다. 프롭으로 꼭 store를 정의해주어야 한다. 프로바이더가 감싼 컴포넌트들은 스토어를 사용할 수 있게 된다.

<Provider store={store}>
      <div>
        <Counter></Counter>
      </div>
</Provider>

useSelector

스테이트를 넣고 싶은 컴포넌트에 사용. 함수를 인자로 받는다.

const number = useSelector(state => state.number);

useDispatch

타입 정의로 reducer 함수를 동작하게 만드는 함수.
dispatch({ type:데이터수정방법 })
dispatch의 사전적 정의는 '보내다'이므로, 저장한 state를 사용할 수 있도록 해당 컴포넌트에 보내는 배달부 함수..?정도로 이해해도 되려나.

function Right3(props) {
  const dispatch = useDispatch();
  return (
    <div>
      <h1>Right3</h1>
      <input type="button" value="+" onClick={() => {
        dispatch({type:'PLUS'})
      }}></input>
    </div>
  );
}

전역적으로 store에 저장되어있는 number state와 하위 컴포넌트의 number를 무선으로 연결한 효과와 같다. (!!!)




사용 방법을 간단히 정리하자면,

1. Store, reducer 생성 (일종의 저장소와 실행 함수 모음집)
2. Provider 감싸기 (우산 씌우기)
3. useSelector로 State 사용
4. dispatch 함수 사용

기존 리액트의 useState는 구조분해할당으로 정의만 해놓고 사용할 함수를 컴포넌트에 직접 정의했다면,

redux는 'reducer함수는 state의 변경 방법을 모두 정의해놓는 종합적인 함수 모음집 같은 것, 변경할 컴포넌트에서 dispatch 함수만 보내서 사용할 타입을 정의하는 것'이라고 생각한다. (틀리면 말해주세요)

리액트에 내장된 useState, Context API 기능들을 편히 사용하던 나로서는 좀.. 이 과정이 복잡해 보이긴 하지만 큰 프로젝트를 다룰 때는 유용할 것 같다. 나중에 비동기 처리를 어떻게 하는지도 궁금해졌다.






🟣 Redux Toolkit의 탄생


탄생 이유

  • redux는 설정이 복잡함
  • 미들웨어 설치가 많음
  • 반복되는 코드가 많음
  • 불변성 유지의 어려움

➡️ 이런 문제를 해결한 도구가 Redux Toolkit이다.



도구들 간의 관계

ReduxReact reduxRedux Toolkit
리액트와 무관한 상태 관리자. 자바스크립트로 된 프로젝트라면 어디서든지 사용 가능리덕스를 리액트에서 사용하기 위해 만들어진 도구사용해야 할 문법이 복잡해짐에 따라 리액트 리덕스를 편리하게 사용하기 위해 만들어짐



설치

  1. 프로젝트 생성 시
# Redux + Plain JS template
npx create-react-app my-app --template redux

# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript
  1. 존재하는 프로젝트에서 사용 시
npm install @reduxjs/toolkit
yarn add @reduxjs/toolkit



동작 원리

기능 별로 작은 store를 slice라고 부른다.
작은 스토어들을 합쳐서 리덕스가 요구하는 큰 스토어로 툴킷이 만들어준다.




사용 방법

Slice 생성

// counterSlice.js

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


const counterSlice = createSlice({
// createSlice에는 필요한 객체를 설정.
  name:'counterSlice',
  // 이름 설정
  initialState:{value:0},
  // 초기값 지정 
  reducers:{
  // 복수형 reducers 공급, 타입별로 함수 정의
    up:(state, action)=>{
      state.value = state.value + action.payload;
 // 복제 X, step -> payload
    }
  }
});

export default counterSlice;
export const {up} = counterSlice.actions;
// 업만 export시키기 




store 생성 w configureStore

  • slice들을 store로 만들 때

// store.js

import {configureStore} from '@reduxjs/toolkit';
import counterSlice from './counterSlice';
// 슬라이스 임포트하기


const store = configureStore({
// 객체 전달 
  reducer:{
  // reducer(단수). 각각 슬라이스의 리듀서들이 들어간다. 
    counter:counterSlice.reducer
  // slice.reducer
  }
});

export default store;

// App.js

import React from "react";
import {createStore} from 'redux';
import {Provider,useSelector,useDispatch} from 'react-redux';
import store from './store';
import {up} from './counterSlice';
// 임포트 해오기 



function Counter(){
  const dispatch = useDispatch();
  const count = useSelector(state=>{
    return state.counter.value;
    // counterSlice의 초기값에 해당 
  });
  return <div>
    <button onClick={()=>{
      dispatch(up(2));
      // counterSlice.actions.up(2) 축약 
    }}>+</button> {count}
  </div>
}
export default function App() {
  return (
    <Provider store={store}>
      <div>
        <Counter></Counter>
      </div>
    </Provider>
  );
}





참고 자료

-생활코딩 redux, redux-toolkit 강의
-React with Redux Toolkit Crash Course

profile
Everything is connected 🐶 좀 더 나은 개발을 위해

0개의 댓글