리덕스 툴킷을 배우려면 우선 리액트 리덕스의 동작 원리에 대해 간단히 알아야 한다.
리액트에서 상태관리를 할 때,
=> 쉽게 말해 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();
function reducer(현재스테이트값, action(변경 요청받는 값))
=
useState [number, setNumber]
// 두 가지가 비슷한 역할이라고 이해했다.
const newState = {...currentState}
return newState;
if (currentState === undefined) {
return {
number: 1,
};
커넥트는 설명에서 제외한다.
import { Provider, useSelector, useDispatch, connect } from 'react-redux';
리액트의 Context API 처럼 컴포넌트를 감싸주는 역할을 한다. 프롭으로 꼭 store를 정의해주어야 한다. 프로바이더가 감싼 컴포넌트들은 스토어를 사용할 수 있게 된다.
<Provider store={store}>
<div>
<Counter></Counter>
</div>
</Provider>
스테이트를 넣고 싶은 컴포넌트에 사용. 함수를 인자로 받는다.
const number = useSelector(state => state.number);
타입 정의로 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 | React redux | Redux Toolkit |
---|---|---|
리액트와 무관한 상태 관리자. 자바스크립트로 된 프로젝트라면 어디서든지 사용 가능 | 리덕스를 리액트에서 사용하기 위해 만들어진 도구 | 사용해야 할 문법이 복잡해짐에 따라 리액트 리덕스를 편리하게 사용하기 위해 만들어짐 |
# Redux + Plain JS template
npx create-react-app my-app --template redux
# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript
npm install @reduxjs/toolkit
yarn add @reduxjs/toolkit
기능 별로 작은 store를 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.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