yarn add redux react-redux // redux , react-redux 라이브러리 설치
import { createStore } from "redux";
import { combineReducers } from "redux";
/*
1. createStore()
리덕스의 가장 핵심이 되는 스토어를 만드는 메소드(함수) 입니다.
리덕스는 단일 스토어로 모든 상태 트리를 관리한다고 설명해 드렸죠?
리덕스를 사용할 시 creatorStore를 호출할 일은 한 번밖에 없을 거예요.
*/
/*
2. combineReducers()
리덕스는 action —> dispatch —> reducer 순으로 동작한다고 말씀드렸죠?
이때 애플리케이션이 복잡해지게 되면 reducer 부분을 여러 개로 나눠야 하는 경우가 발생합니다.
combineReducers은 여러 개의 독립적인 reducer의 반환 값을 하나의 상태 객체로 만들어줍니다.
*/
const rootReducer = combineReducers({});
const store = createStore(rootReducer);
export default store;
module 폴더에는 state들이 모두 모여있을 파일을 생성한다.
예를들어 todo의 모든 state를 관리하기 위해 파일을 만든 후 module 폴더에 넣는다.
index.js에 아래 코드를 복붙한다.
// 원래부터 있던 코드
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
// 우리가 추가할 코드
import store from "./redux/config/configStore";
import { Provider } from "react-redux";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
//App을 Provider로 감싸주고, configStore에서 export default 한 store를 넣어줍니다.
<Provider store={store}>
<App />
</Provider>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
// 초기 상태값
const initialState = {
number: 0,
};
// 리듀서
const counter = (state = initialState, action) => {
switch (action.type) {
default:
return state;
}
};
// 모듈파일에서는 리듀서를 export default 한다.
export default counter;
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;
import React from "react";
import { useSelector } from "react-redux";
const App = () => {
const counterStore = useSelector((state) => state);
const number = useSelector((state) => state.counter.number);
console.log(counterStore);
console.log(number);
return <div></div>;
};
export default App;
//modules/counter.js
// 초기 상태값
const initialState = {
number: 0,
};
// 리듀서
const counter = (state = initialState, action) => {
console.log(action);
switch (action.type) {
case "PLUS_ONE":
return { number: state.number + 1 };
case "MINUS_ONE":
return { number: state.number - 1 };
default:
return state;
}
};
// 모듈파일에서는 리듀서를 export default 한다.
export default counter;
//App.js
import React from "react";
import { useSelector, useDispatch } from "react-redux"; // import 해주세요.
const App = () => {
const dispatch = useDispatch();
const number = useSelector((state) => state.counter.number);
return (
<div>
{number}
<button
onClick={() => {
dispatch({ type: "PLUS_ONE" });
}}
>
+1
</button>
<button
onClick={() => {
dispatch({ type: "MINUS_ONE" });
}}
>
-1
</button>
</div>
);
};
export default App;
//modules/counter.js
const PLUS_ONE = "PLUS_ONE";
const MINUS_ONE = "MINUS_ONE";
export const plusOne = () => {
return {
type: PLUS_ONE,
};
};
export const minusOne = () => {
return {
type: MINUS_ONE,
};
};
const initialState = {
number: 0,
};
const counter = (state = initialState, action) => {
console.log(action);
switch (action.type) {
case "PLUS_ONE":
return { number: state.number + 1 };
case "MINUS_ONE":
return { number: state.number - 1 };
default:
return state;
}
};
// 모듈파일에서는 리듀서를 export default 한다.
export default counter;
//App.js
import React from "react";
import { useSelector, useDispatch } from "react-redux"; // import 해주세요.
import { minusOne, plusOne } from "./redux/modules/counter";
const App = () => {
const dispatch = useDispatch();
const number = useSelector((state) => state.counter.number);
return (
<div>
{number}
<button
onClick={() => {
dispatch(plusOne());
}}
>
+1
</button>
<button
onClick={() => {
dispatch(minusOne());
}}
>
-1
</button>
</div>
);
};
export default App;
//modules/counter.js
//Action Value
const ADD_NUMBER = "ADD_NUMBER";
const DEL_NUMBER = "DEL_NUMBER";
//Action Creator
export const addNumber = (payload) => {
return {
type: ADD_NUMBER,
payload,
};
};
export const delNumber = (payload) => {
return {
type: DEL_NUMBER,
payload,
};
};
//Initial State
const InitialState = {
number: 0,
};
//Reducer
const counter = (state = InitialState, action) => {
switch (action.type) {
case ADD_NUMBER: {
return {
number: state.number + action.payload,
};
}
case DEL_NUMBER: {
return {
number: state.number - action.payload,
};
}
default:
return state;
}
};
//export default reducer
export default counter;
//App.js
import React from "react";
import { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addNumber, delNumber } from "./redux/modules/counter";
const App = () => {
const [number, setNumber] = useState(0);
const globalNumber = useSelector((state) => state.counter.number);
const dispatch = useDispatch();
const onClickAddNumberHandler = () => {
dispatch(addNumber(number));
};
const onClickDelNumberHandler = () => {
dispatch(delNumber(number));
};
const onChangeHandler = (e) => {
const { value } = e.target;
setNumber(+value);
};
console.log(number);
return (
<div>
{globalNumber}
<input type="number" onChange={onChangeHandler} />
<button onClick={onClickAddNumberHandler}>더하기</button>
<button onClick={onClickDelNumberHandler}>빼기</button>
</div>
);
};
export default App;