redux란?
useState를 통해 상태를 관리했을 때 발생하는 불편함을 일부 덜어주는 전역 상태(Global State)관리 라이브러리이다. 여러 컴포넌트가 동일한 상태를 공유할 수 있으며, 액션 및 리듀서의 사용으로 상태 변경의 추적 및 디버깅이 쉬워진다.
전역 상태관리에서 state를 생성하고, 만약 어떤 컴포넌트에서 state가 필요하다면 컴포넌트가 어디에 위치하고 있든 상관없이 state를 불러와서 사용할 수 있다.
yarn add react-redux redux
redux 폴더 정리
redux : 리덕스 관련 코드 모두
config : 중앙 state 관리소 -> 설정 코드(.js)
modules : state의 그룹.
[public]
- index.html
[src]
- App.js
- index.js
> [component]
- Counter.js(예시)
> [redux]
> [config]
- configStore.js
> [modules] // reducer 폴더
- counterContainer.js(예시)
- userContainer.js(예시)
configStore.js
과정
1. 사용할 reducer import하기
2. reducer를 합칠 rootReducer 만들기
3. reducer 합치기
4. rootReducer 를 기반으로 중앙 state관리소인 store생성
import { createStore, combineReducers } from "redux"
// reducer import
import counter from '../modules/counterContainer'; // 사용할 reducer
import user from '../modules/userContainer'; // 사용할 reducer(현재 포스팅에서는 사용안함 예시일뿐임)
// rootReducer 생성
const rootReducer = combineReducers({
// reducer들 합치기
counter,
user,
});
// store 생성
const store = createStore(rootReducer);
export default store;
createStore - store를 만드는 API
combineReducers - redux를 하나로 묶어주는 API
index.js
// Provider을 사용하기위한 import
import { Provider } from 'react-redux';
import store from './redux/config/configStore';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
// 사용할 전역상태관리만큼 Provider로 감싸기
// 전역 데이터인 store을 props로 넘겨줌
<Provider store={store}>
<App />
</Provider>
);
reportWebVitals();
Counter.js
과정
1. useSelector를 사용해서 store접근 -> reducer 조회
2. CRUD를 위한 useDispatch사용
3. dispatch를 사용해서 함수 만들기(인자로 액션함수 사용해 reducer 적용하기)
import { plusN, minusN } from '../modules/counterContainer';
import { useState } from 'react';
// 값을 수정하기 위한 import
import { useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';
function Counter() {
// useSelector를 사용해 store(configStore)에 접근해서 reducer 읽어오는 과정
const counter = useSelector((state) => {
return state.counter;
});
// state를 변경(CRUD)하기 위해선 useDispatch를 사용해야함
const dispatch = useDispatch()
const [number, setNumber] = useState(0);
return (
<>
<p>현재 카운트 : {counter.number}</p>
<div>
<input
type="number"
value={number}
onChange={(event) => {
// 비구조분해 할당
const { value } = event.target;
// +를 넣어주면 문자열->숫자열로 형변환됨
setNumber(+value);
}}
/>
</div>
<button
// action 객체를 리턴해주는 함수(액션 함수)를 넣어서 하드코딩 막기
// 액션함수 인자로 payload 넣어주기
onClick={() => dispatch(plusN(number)) }>
+
</button>
<button
onClick={() => dispatch(minusN(number)) }>
-
</button>
</>;
}
export default Counter;
counterContainer.js
과정
1. action value만들기
2. action creater(액션 함수)만들기
3. state의 초기값 지정
4. 리듀서 선언
// (1) 사람의 실수를 방지하기위해 action의 type을 변하지않는 상수로 만들기
const PLUS_N = 'counter/PLUS_N';
const MINUS_N = 'counter/MINUS_N';
// (2) action value를 return 하는 action creater 함수
export const plusN = (payload) => {
return {
type: PLUS_N,
payload,
};
};
export const minusN = (payload) => {
return {
type: MINUS_N,
payload,
};
};
// (3) 초기 상태값(state) 지정
const initialState = {
number: 0,
};
// (4) 리듀서 선언
// 매개변수 - state, action
// state의 초기값을 할당해줌
const counter = (state = initialState, action) => {
// state를 action의 type에 따라 함수가 적용되게 switch case문 사용
switch (action.type) {
case PLUS_N:
return {
number: state.number + action.payload,
};
case MINUS_N:
return {
number: state.number - action.payload,
};
default: // 어디에도 해당되지않은 값
return state;
}
};
export default counter;
import React from 'react';
import Counter from './redux/component/Counter';
function App() {
return (
<div>
<Counter />
</div>
);
}
export default App;
Redux Toolkit?
Redux를 사용하여 상태 관리를 좀 더 쉽고 간단하게 만들어주는 도구 모음이다. Redux-Toolkit을 사용하면 Redux를 사용하여 상태를 관리하는 데 필요한 여러 가지 요소를 쉽게 생성할 수 있다. 이를 통해 Redux를 더 쉽고 간단하게 사용할 수 있으며, 코드의 가독성과 유지 보수성이 향상된다.
Redux-Toolkit의 기능
configStore.js
// 일반 리듀서
const rootReducer = combineReducers({
counter,
user,
});
const store = createStore(rootReducer);
// Redux-Toolkit
const store = configureStore({
reducer: {
counter,
user,
},
});
기존에는 reducer들을 합치기위해 rootReducer를 만들고 이를 기반으로 중앙 state관리소인 store를 생성해야 했다면 Toolkit에서는 combineReducers와 createStore를 합친 configureStore를 활용하여 바로 store로 만들고 store객체안에 reducer를 넣어주면 된다.
reducer
일반 redux
const PLUS_N = 'counter/PLUS_N';
const MINUS_N = 'counter/MINUS_N';
// action creater
export const plusN = (payload) => {
return {
type: PLUS_N,
payload,
};
};
export const minusN = (payload) => {
return {
type: MINUS_N,
payload,
};
};
// 초기 상태값
const initialState = {
number: 0,
};
// reducer
const counter = (state = initialState, action) => {
switch (action.type) {
case PLUS_N:
return {
number: state.number + action.payload,
};
case MINUS_N:
return {
number: state.number - action.payload,
};
default:
return state;
}
};
export default counter;
Redux-Toolkit
// 초기 상태값
const initialState = {
number: 0,
};
//createSlice
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
plusN: (state, action) => {
state.number = state.number + action.payload;
},
minusN: (state, action) => {
state.number = state.number - action.payload;
},
}
})
export default counterSlice.reducer;
export const { plusN, minusN } = counterSlice.actions;
createSlice는 Action creater와 reducer를 한번에 생성할 수 있게 만들어주는 API이다. reducers내의 프로퍼티에는 action creater 이름을 넣고 값에는 콜백함수를 넣어준다.