전역 상태관리 라이브러리(Global State를 의미하고 그것을 관리하게 도와주는 라이브러리)
useState를 사용시 발생하는 불편함을 해소해준다.
yarn add redux react-redux
├── public
├── src
| ├── redux
| | ├── config
| | | └── configStore.js
| | ├── modules
| | | ├── counter.js
| | | └── todos.js
│ ├── App.js
│ ├── App.test.js
│ ├── index.css
│ ├── index.js
│ ├── reportWebVitals.js
│ └── setipTests.js
├── .gitignore
├── package.json
├── yarn.lock
└── README.md
모듈 만들기 → 스토어에 연결(configStore.js) → 컴포넌트에서 Store 조회, 수정, 삭제
모듈을 밑의 순서로 작성한다.
// Action Value
// Action Creator
// Initial State
// Reducer
// export default Reducer
const PLUS_ONE = "PLUS_ONE";
const MINUS_ONE = "MINUS_ONE";
const ADD_NUMBER = "ADD_NUMBER";
const SUB_NUMBER = "SUB_NUMBER";
type 이란 key를 가져야 하는 객체. 리듀서로 보낼 명령ES6에서는 객체의 key와 value가 값으면 한 번만 작성하면 된다.export const plusOne = () => {
return {
type: PLUS_ONE,
};
};
export const minusOne = () => {
return {
type: MINUS_ONE,
};
};
export const addNumber = (payload) => {
return {
type: ADD_NUMBER,
payload, // === payload: payload
};
};
export const subNumber = (payload) => {
return {
type: SUB_NUMBER,
payload,
};
};
// 초기값이 0
const initialState = 0;
// 초기값이 0이 있는 배열
const initialState = [0];
// 초기값이 number = 0, name = 'Jane'인 객체
const initialState = {
number: 0,
name: 'Jane'
};
const counter = (state = initialState, action) => {
switch(state.type) {
case PLUS_ONE:
return {
number: state.number + 1;
};
case MINUS_ONE:
return {
number: state.number - 1;
};
case ADD_NUMBER:
return {
number: state.number + action.payload,
};
case SUB_NUMBER:
return {
number: state.number - action.payload,
};
default:
return state;
}
};
export defaultexportapp/reducer/ACTION_TYPE 형태로 작성한다.modules/counter.js
// Action Value
const PLUS_ONE = "PLUS_ONE";
const MINUS_ONE = "MINUS_ONE";
const ADD_NUMBER = "ADD_NUMBER";
const SUB_NUMBER = "SUB_NUMBER";
// Action Creator
export const plusOne = () => {
return {
type: PLUS_ONE,
};
};
export const minusOne = () => {
return {
type: MINUS_ONE,
};
};
export const addNumber = (payload) => {
return {
type: ADD_NUMBER,
payload, // === payload: payload
};
};
export const subNumber = (payload) => {
return {
type: SUB_NUMBER,
payload,
};
};
// Initial State
const initialState = {
number: 0,
};
// Reducer
const counter = (state = initialState, action) => {
switch(state.type) {
case PLUS_ONE:
return {
number: state.number + 1;
};
case MINUS_ONE:
return {
number: state.number - 1;
};
case ADD_NUMBER:
return {
number: state.number + action.payload,
};
case SUB_NUMBER:
return {
number: state.number - action.payload,
};
default:
return state;
}
};
// export default Reducer
export default counter;
Module - Store 연결하기
combineReducers() 함수 안에 모듈을 작성한다.
config/configStore.js
import { createStore } from "redux";
import { combineReducers } from "redux";
import counter from "../modules/counter";
const rootReducer = combineReducers({
counter: counter,
});
const store = createStore(rootReducer);
export default store;
Module - Store 연결 확인
App.js
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { addNumber, subNumber, minusOne, plusOne } from "./redux/modules/counter";
const App = () => {
const [number, setNumber] = useState(0);
const counterStore = useSelector((state) => state);
const globalNumber = useSelector(state => state.counter.number);
console.log(counterStore);
const dispatch = useDispatch();
const onChangeHandler = (evnet) => {
const { value } = evnet.target;
setNumber(+value); // string to number -> +str
};
const onClickAddNumberHandler = () => {
dispatch(addNumber(number));
};
const onClickSubNumberHandler = () => {
dispatch(subNumber(number));
};
return (
<div>
<input type="number" onChange={onChangeHandler}/>
{globalNumber}
<button onClick={() => dispatch(plusOne)}>+1</button>
<button onClick={() => dispatch(minusOne)}>-1</button>
<button onClick={onClickAddNumberHandler}>더하기</button>
<button onClick={onClickSubNumberHandler}>빼기</button>
</div>
);
}
export default App;