๐ข
State๋ฅผ ๊ณต์ํ๊ณ ์ ํ ๋ ๋ถ-๋ชจ ๊ด๊ณ๊ฐ ์๋์ด๋ ๋๊ณ , ์ค๊ฐ์ ๋ถํ์ํ ์ ๋ฌ์ฑ ์ด ํ์์๋ค!
- `

a. Context API
b. Redux
์ฑ๋ฅ์ต์ ํ ์ํ ๋ณ๊ฒฝ ์ ๊ด๋ จ๋ ์ปดํฌ๋ํธ๋ง ์ ํ์ ์ผ๋ก ์
๋ฐ์ดํธ -> ์ ํ๊ด๋ฆฌ ์ฉ์ด์ํ ๋ก์ง์ ์ค์ํ, ์ผ๊ด์ฑ ์ ํ๋ฆฌ์ผ์ด์
์ํ๋ฅผ ํ๋์ ์ ์ฅ์(store)์ ์ ์ฅ -> ์ผ๊ด์ฑ, ์์ธก ๊ฐ๋ฅํ ์ํ ๋ณ๊ฒฝ๋ฏธ๋ค์จ์ด์ ๊ฐ๋ฐ๋๊ตฌ ๋ค์ํ ๋ฏธ๋ค์จ์ด ์ง์. ๋น๋๊ธฐ, ๋ก๊น
, ์ํ ๋ณ๊ฒฝ์ ๋ํ ์ถ๊ฐ ์ฒ๋ฆฌ๋ฑ ๋ณต์กํ ๊ธฐ๋ฅ ๊ตฌํ
์ค์ state ๊ด๋ฆฌ์๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋์์ฃผ๋ ํจํค์ง(๋ผ์ด๋ธ๋ฌ๋ฆฌ)
yarn add redux react-redux
์๋์ ๊ฐ์ ์๋ฏธ
yarn add redux
yarn add react-redux

srcํด๋ ์์reduxํด๋๋ฅผ ์์ฑreduxํด๋ ์์config,modulesํด๋๋ฅผ ์์ฑconfigํด๋ ์์configStore.jsํ์ผ์ ์์ฑ
redux : ๋ฆฌ๋์ค์ ๊ด๋ จ๋ ์ฝ๋๋ฅผ ๋ชจ๋ ๋ชจ์ ๋์ ํด๋config : ๋ฆฌ๋์ค ์ค์ ๊ณผ ๊ด๋ จ๋ ํ์ผ๋ค์ ๋์ ํด๋configStore : โ์ค์ state ๊ด๋ฆฌ์" ์ธ Store๋ฅผ ๋ง๋๋ ์ค์ ์ฝ๋๋ค์ด ์๋ ํ์ผmodules : State๋ค์ ๊ทธ๋ฃน. ์๋ฅผ ๋ค์ด ํฌ๋๋ฆฌ์คํธ๋ฅผ ๋ง๋ ๋ค๊ณ ํ๋ค๋ฉด, ํฌ๋๋ฆฌ์คํธ์ ํ์ํ state๋ค์ด ๋ชจ๋ ๋ชจ์ฌ์์ todos.js๋ฅผ ์์ฑํ๋๋ฐ, ์ด todos.js ํ์ผ์ด ๊ณง ํ๋์ ๋ชจ๋์ด ๋จsrc/configStore.js
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;
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();
์นด์ดํฐ ํ๋ก๊ทธ๋จ ๋ง๋ค๊ธฐ ๋ ์ธ ๊ณ
๋ชจ๋? state์ ๊ทธ๋ฃน.
modulesํด๋์ counter.js ํ์ผ ์์ฑ// src/redux/modules/counter.js
// ์ด๊ธฐ ์ํ๊ฐ
const initialState = {
number: 0,
};
// ๋ฆฌ๋์
const counter = (state = initialState, action) => {
switch (action.type) {
default:
return state;
}
};
// ๋ชจ๋ํ์ผ์์๋ ๋ฆฌ๋์๋ฅผ export default ํ๋ค.
export default counter;
// ์ด๊ธฐ ์ํ๊ฐ
// ์ด๊ธฐ ์ํ๊ฐ
const initialState = {
number: 0,
};
์ด๊ธฐ๊ฐ์ { } (๊ฐ์ฒด) ์ด๊ณ , ๊ทธ ์์ number ๋ผ๋ ๋ณ์์ ์ด๊ธฐ๊ฐ 0์ ํ ๋นํด์ค ๊ฒ
์ด๊ธฐ๊ฐ์ ๊ผญ ๊ฐ์ฒด๊ฐ ์๋์ด๋ ๋๋ค. ๋ฐฐ์ด, ์์๋ฐ์ดํฐ ์ ๋ถ OK
๊ฐ์ฒด์๋ ์ฌ๋ฌ๊ฐ์ ๋ณ์๋ฅผ ๋ฃ์ด์ค ์ ์์
// ์ด๊ธฐ๊ฐ์ด 0
const initialState = 0;
// ์ด๊ธฐ๊ฐ์ด 0์ด ์๋ ๋ฐฐ์ด
const initialState = [0];
// ์ด๊ธฐ๊ฐ์ด number = 0, name = '์งฑ๊ตฌ'์ธ ๊ฐ์ฒด
const initialState = {
number: 0,
name: '์งฑ๊ตฌ'
};
// useState ๋ฒ์
const [number, setNumber] = useState(0) // < ์ด๊ฑฐ๋ ๊ฐ๋ค
useState๋ฅผ ์ฌ์ฉํ์ ๋ ๊ดํธ ์์ ์ด๊ธฐ๊ฐ์ ์ง์ ํด์ฃผ๋ ๊ฒ๊ณผ ๊ฐ์
๋ณํ๋ฅผ ์ผ์ผํค๋
ํจ์๋ค
// ๋ฆฌ๋์
const counter = (state = initialState, action) => {
switch (action.type) {
default:
return state;
}
};
์๋๋ useState ๋ฒ์ .
// useState ๋ฒ์
const onClickHandler = () => {
setNumber(number + 1); // setState๋ฅผ ์ด์ฉํด์ state ๋ณ๊ฒฝ
}
useState ๋ฅผ ์ฌ์ฉํ ๋ ๊ฐ์ ๋ฐ๊พธ๊ณ ์ถ์ผ๋ฉด setNumber๋ฅผ ์ฌ์ฉํ๋ค.
๋ฆฌ๋์ค์์๋ ๋ฆฌ๋์ค๊ฐ ์ด ์ญํ ์ ํ๋ค.
// src/redux/modules/counter.js
// counter ๋ฆฌ๋์
const counter = (state = initialState, action) => {
switch (action.type) {
default:
return state;
}
};
export default counter; // ์ฌ๊ธฐ
๋ฆฌ๋์์ ์ธ์์ ์๋ (state = intialState, action)
์ฒซ๋ฒ์งธ ์๋ฆฌ์์๋state๋ฅผ, ๋๋ฒ์งธ ์๋ฆฌ์์๋action์ด๋ผ๋ ๊ฒ์ ๊บผ๋ด์ ์ฌ์ฉํ ์ ์๋ค.
๐กstate = intialState์ฒ๋ผstate์initialState๋ฅผ ํ ๋นํด์ค์ผ ํ๋ ๊ฒ๋ง ๊ธฐ์ต.
๋ง๋ ๋ชจ๋์ ์คํ ์ด์ ์ฐ๊ฒฐ ์์ผ์ผ ํ๋ค! ์์ง์ state๋ฅผ ์คํ ์ด์์ ๊บผ๋ผ ์ ์๋ ์ํ
configStore.js ์์ ์๋ ์ฝ๋ ์ถ๊ฐ
// src/redux/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;
๐ข ์ปดํฌ๋ํธ์์ ์คํ ์ด๋ฅผ ์ง์ ์กฐํํ ๋
react-redux์์ ์ ๊ณตํ๋useSelector๋ผ๋ ํ ์ ์ฌ์ฉ
// 1. store์์ ๊บผ๋ธ ๊ฐ์ ํ ๋น ํ ๋ณ์๋ฅผ ์ ์ธํฉ๋๋ค.
const number =
// 2. useSelector()๋ฅผ ๋ณ์์ ํ ๋นํด์ค๋๋ค.
const number = useSelector()
// 3. useSelector์ ์ธ์์ ํ์ดํ ํจ์๋ฅผ ๋ฃ์ด์ค๋๋ค.
const number = useSelector( ()=>{} )
// 4. ํ์ดํ ํจ์์ ์ธ์์์ ๊ฐ์ ๊บผ๋ด return ํฉ๋๋ค.
// ์ฐ๋ฆฌ๊ฐ useSelector๋ฅผ ์ฒ์ ์ฌ์ฉํด๋ณด๋ ๊ฒ์ด๋, state๊ฐ ์ด๋ค ๊ฒ์ธ์ง ์ฝ์๋ก ํ์ธํด๋ณผ๊น์?
const number = useSelector((state) => {
console.log(state)
return state
});
App.js
// src/App.js
import React from "react";
import { useSelector } from "react-redux"; // import ํด์ฃผ์ธ์.
const App = () => {
const counterStore = useSelector((state) => state); // ์ถ๊ฐํด์ฃผ์ธ์.
console.log(counterStore); // ์คํ ์ด๋ฅผ ์กฐํํด๋ณผ๊น์?
return <div></div>;
}
export default App;

๋ธ๋ผ์ฐ์ ๋ฅผ ์ผ๊ณ , ์ฝ์์ ๋ณด๋ฉด ์๋ ์ด๋ฏธ์ง์ฒ๋ผ ๊ฐ์ฒด๊ฐ ๋ณด์ด๊ณ , ๊ทธ ์์ counter ๋ผ๋ ๊ฐ์ด ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค. ์ฐ๋ฆฌ๊ฐ ๋ง๋ counter ๋ผ๋ ๋ชจ๋์ state๊ฐ ๋ณด์ด๋ ๊ฒ์ ์ ์ ์๋ค. ์ด๋ ๊ฒ ํ์ดํ ํจ์์์ ๊บผ๋ธ state๋ผ๋ ์ธ์๋ ๋ชจ๋ ๋ฆฌ๋์ค ๋ชจ๋์ ์ต์์ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ Root State์ธ ๊ฒ
์ปดํฌ๋ํธ์์
number๋ผ๋ ๊ฐ์ ์ฌ์ฉํ๊ณ ์ ํ๋ค๋ฉด ์๋ ์ฝ๋์ฒ๋ผ ๊บผ๋ด์ ์ฌ์ฉconst number = useSelector(state => state.counter.number); // 0