Notice
Recent Posts
Recent Comments
Link
์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
Tags
- JavaScript
- jsx
- git
- State
- fetch api
- ๊ณ ์ฐจํจ์
- Cmarket
- ์๋งจํฑ์์
- html
- prototype
- ๋ฒ์ง ๋ชจํ
- React
- BFS์ DFS
- Effect Hook
- ํ๋ก๊ทธ๋๋จธ์ค
- ์คํ ์ด์ธ ์ฝ๋
- css
- ์คํ ์ด์ธ ์ฝ๋42๊ธฐ
- ํ ์คํธ ์์
- ํผํฐ ๋ชจ๋น
- Lifting state
- WEB
- Study
- ๋ฒ๋ค๋ง
- ์ปดํจํฐ ๊ณตํ
- css animation
- ์ ์ด์ฝฅ ๋์จ
- wai-aria
- ํผํฐ ๋ชจ๋น์ ๋ฒ์ง ๋ชจํ
- props drilling
Archives
- Today
- Total
roqkf
[React] Redux ๋ณธ๋ฌธ

โจ Intro

๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง React ์ ํ๋ฆฌ์ผ์ด์
์ด ์๋ค๊ณ ๊ฐ์ ํ์ ๋, ์ปดํฌ๋ํธ 3, ์ปดํฌ๋ํธ 6์๋ง ์ฌ์ฉ๋๋ ์ํ๊ฐ ์๋ค. ์ด ์ํ๋ ์ด๋ ์ปดํจ๋ํธ์ ์์น์์ผ์ผ ํ ๊น? ๋ต์ React ๋ฐ์ดํฐ ํ๋ฆ์ ๋จ๋ฐฉํฅ์ผ๋ก ํ๋ฅด๊ธฐ ๋๋ฌธ์ ์ต์์ ์ปดํฌ๋ํธ์ ์์น์ํค๋ ๊ฒ์ด ์ ์ ํ๋ค. ํ์ง๋ง ์ด๋ฐ ์ํ ๋ฐฐ์น๋ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ๋นํจ์จ์ ์ด๋ผ๊ณ ๋๊ปด์ง ์ ์๋ค.
- ์ปดํฌ๋ํธ 1, 2๋ ํด๋น ์ํ๋ฅผ ์ฌ์ฉํ์ง ์๋๋ฐ ์ํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง
- ์ํ ๋์ด์ฌ๋ฆฌ๊ธฐ, Props ๋ด๋ ค์ฃผ๊ธฐ๋ฅผ ์ฌ๋ฌ ๋ฒ ๊ฑฐ์นจ
- ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ณต์ก์ฑ์ ๋ฐ๋ผ ๋ฐ์ดํฐ ํ๋ฆ๋ ๋ณต์กํด์ง
- ์ปดํฌ๋ํธ ๊ตฌ์กฐ ๋ณ๋ ์, ํ์ฌ ๋ฐ์ดํฐ ํ๋ฆ์ ๋ฐ๊ฟ์ผ ํ ์๋ ์์
[React ์ฌ์ฉํ์ ๋์ ๋ฐ์ดํฐ ํ๋ฆ]

[Redux ์ฌ์ฉํ์ ๋์ ๋ฐ์ดํฐ ํ๋ฆ]

- ๋ ๋ฐ์ดํฐ ํ๋ฆ์ ๋น๊ตํด ๋ณด๋ฉด React๋ฅผ ์ฌ์ฉํ์ ๋๋ณด๋ค Redux๋ฅผ ์ฌ์ฉํ์ ๋์ ๋ฐ์ดํฐ ํ๋ฆ์ด ๋ณด๋ค ๊น๋ํด์ง ๊ฒ์ ํ์ธํ ์ ์๋ค. Redux๋ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ์ ์ญ ์ํ๋ฅผ ๊ด๋ฆฌํ ์ ์๋ ์ ์ฅ์์ธ Store์ ์ ๊ณตํ์ฌ Props Drilling์ ํด๊ฒฐํด ์ค๋ค.
โค๏ธ๐ฅ Redux
- React ์์ด๋ ์ฌ์ฉํ ์ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ์๋ฐ์คํฌ๋ฆฝํธ ์ฑ์ ์ํ ์์ธก ๊ฐ๋ฅํ ์ํ ์ปจํ ์ด๋
- ์๋ก ๋ค๋ฅธ ํ๊ฒฝ์์ ์๋ํ๊ณ , ํ ์คํธํ๊ธฐ ์ฌ์ด ์ฑ์ ์์ฑํ๋๋ก ๋์์ค๋ค.
๐ Redux | ์ธ ๊ฐ์ง ์์น
1. Single source of truth
- ๋์ผํ ๋ฐ์ดํฐ๋ ํญ์ ๊ฐ์ ๊ณณ์์ ๊ฐ์ง๊ณ ์จ๋ค.
- Redux์๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ Store ๋จ ํ๋๋ฟ์ธ ๊ณต๊ฐ์ด ์๋ค๋ ์์น
2. State is read-only
- ์ํ๋ ์ฝ๊ธฐ ์ ์ฉ, React์์ ์ํ๊ฐฑ์ ํจ์๋ก๋ง ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์์๋ ๊ฒ๊ณผ ๊ฐ์ด Redux์ ์ํ๋ ์ง์ ๋ณ๊ฒฝํ ์ ์์์ ์๋ฏธํ๋ค.
- ์ฆ, React์์ setState ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๊ฒ๊ณผ ๊ฐ์ด Redux์์๋ Action์ด๋ผ๋ ๊ฐ์ฒด๋ฅผ ํตํด์๋ง ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค.
3. Changes are made with pure functions
- ๋ณ๊ฒฝ์ ์์ํจ์๋ก๋ง ๊ฐ๋ฅํ๋ค.
- ์ํ๊ฐ ์๋ฑํ ๊ฐ์ผ๋ก ๋ณ๊ฒฝ๋๋ ์ผ์ด ์๋๋ก ์์ํจ์๋ก๋ง ์์ฑ๋์ด์ผ ํ๋ Reducer์ ์ฐ๊ฒฐ๋๋ ์์น
- Store - Action - Reducer
๐ Redux | ๊ธฐ๋ณธ ์ฉ์ด
1. Action
- ์ด๋ค ์ก์ ์ ์ทจํ ๊ฒ์ธ์ง ์ ์ํด ๋์ ๊ฐ์ฒด
- ์๋์ ๊ฐ์ ํ์์ผ๋ก ๊ตฌ์ฑ
// payload๊ฐ ํ์ ์๋ ๊ฒฝ์ฐ
{ type: 'INCREASE' }
// payload๊ฐ ํ์ํ ๊ฒฝ์ฐ
{ type: 'SET_NUMBER', payload: 5
- type์ ์ง์ ์ ํ์์ด๋ฉฐ Snake Case๋ก ์์ฑ, ํด๋น Action ๊ฐ์ฒด๊ฐ ์ด๋ค ๋์์ ํ๋์ง ๋ช ์ํด ์ฃผ๋ ์ญํ ์ ํ๋ค.
- ํ์์ ๋ฐ๋ผ payload๋ฅผ ์์ฑํด ๊ตฌ์ฒด์ ์ธ ๊ฐ ์ ๋ฌ
// payload๊ฐ ํ์ ์๋ ๊ฒฝ์ฐ
const increase = () => {
return {
type: 'INCREASE'
}
}
// payload๊ฐ ํ์ํ ๊ฒฝ์ฐ
const setNumber = (num) => {
return {
type: 'SET_NUMBER',
payload: num
}
}
- ๋ณดํต Action์ ์ง์ ์์ฑํ๊ธฐ๋ณด๋ค Action ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ํจ์๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค. ์ด๋ฌํ ํจ์๋ฅผ Action Creator(์ก์ ์์ฑ์)๋ผ๊ณ ๋ ํ๋ค.
โ payload
- ์ ์ก๋๋ ๋ฐ์ดํฐ, ๋ณด๋ด๊ณ ์ ํ๋ ๋ฐ์ดํฐ ์์ฒด๋ฅผ ์๋ฏธ
- ์ฐธ๊ณ ํ๊ธฐ
2. Reducer
- Dispatch์๊ฒ์ ์ ๋ฌ๋ฐ์ Action ๊ฐ์ฒด์ type ๊ฐ์ ๋ฐ๋ผ ์ํ๋ฅผ ๋ณ๊ฒฝ์ํค๋ ํจ์
const count = 1
// Reducer๋ฅผ ์์ฑํ ๋์๋ ์ด๊ธฐ ์ํ๋ฅผ ์ธ์๋ก ์๊ตฌํฉ๋๋ค.
const counterReducer = (state = count, action) => {
// Action ๊ฐ์ฒด์ type ๊ฐ์ ๋ฐ๋ผ ๋ถ๊ธฐํ๋ switch ์กฐ๊ฑด๋ฌธ์
๋๋ค.
switch (action.type) {
//action === 'INCREASE'์ผ ๊ฒฝ์ฐ
case 'INCREASE':
return state + 1
// action === 'DECREASE'์ผ ๊ฒฝ์ฐ
case 'DECREASE':
return state - 1
// action === 'SET_NUMBER'์ผ ๊ฒฝ์ฐ
case 'SET_NUMBER':
return action.payload
// ํด๋น ๋๋ ๊ฒฝ์ฐ๊ฐ ์์ ๋ ๊ธฐ์กด ์ํ๋ฅผ ๊ทธ๋๋ก ๋ฆฌํด
default:
return state;
}
}
// Reducer๊ฐ ๋ฆฌํดํ๋ ๊ฐ์ด ์๋ก์ด ์ํ๊ฐ ๋ฉ๋๋ค.
- ์ด๋, Reducer๋ ์์ํจ์์ฌ์ผ ํ๋ค. ์ธ๋ถ ์์ธ์ผ๋ก ์ธํด ๊ธฐ๋๊ฐ์ด ์๋ ์๋ฑํ ๊ฐ์ผ๋ก ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ ์ผ์ด ์์ด์ผ ๋๊ธฐ ๋๋ฌธ์ด๋ค.
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { legacy_createStore as createStore } from 'redux';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
{
/*
Reducer ํจ์์ ์ฒซ๋ฒ์งธ ์ธ์์๋ ๊ธฐ์กด state๊ฐ ๋ค์ด์ค๊ฒ ๋๋ค.
์ฒซ๋ฒ์งธ ์ธ์์ default value๋ฅผ ๊ผญ ์ค์ ํด์ผ ํ๋ค.
=> ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ, undefined๊ฐ ํ ๋น๋ผ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์๋ค.
๋๋ฒ์งธ ์ธ์์๋ action ๊ฐ์ฒด๊ฐ ๋ค์ด์ค๊ฒ ๋๋ค.
*/
}
const count = 1;
// Reducer๋ฅผ ์์ฑํ ๋์๋ ์ด๊ธฐ ์ํ๋ฅผ ์ธ์๋ก ์๊ตฌ
const counterReducer = (state = count, action) => {
// Action ๊ฐ์ฒด์ type ๊ฐ์ ๋ฐ๋ผ ๋ถ๊ธฐํ๋ switch ์กฐ๊ฑด๋ฌธ
switch (action.type) {
//action === 'INCREASE'์ผ ๊ฒฝ์ฐ
case 'INCREASE':
return state + 1;
// action === 'DECREASE'์ผ ๊ฒฝ์ฐ
case 'DECREASE':
return state - 1;
// action === 'SET_NUMBER'์ผ ๊ฒฝ์ฐ
case 'SET_NUMBER':
return action.payload;
// ํด๋น ๋๋ ๊ฒฝ์ฐ๊ฐ ์์ ๋ ๊ธฐ์กด ์ํ๋ฅผ ๊ทธ๋๋ก ๋ฆฌํด
default:
return state;
}
};
// Reducer๊ฐ ๋ฆฌํดํ๋ ๊ฐ์ด ์๋ก์ด ์ํ๊ฐ ๋๋ค.
// conterReducer๋ฅผ createStore์ ์ ๋ฌ
const store = createStore(counterReducer);
root.render(
<Provider store={store}>
<App />
</Provider>
);
- ์ฌ๋ฌ ๊ฐ์ Reducer๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, Redux์ combineReducers ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ํ๋์ Reducer๋ก ํฉ์ณ์ค ์ ์๋ค.
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
counterReducer,
anyReducer,
...
});
3. store
- ์ํ๊ณผ ๊ด๋ฆฌ๋๋ ์ค์ง ํ๋๋ฟ์ธ ์ ์ฅ์์ ์ญํ
- Redux ์ฑ์ state๊ฐ ์ ์ฅ๋ผ ์๋ ๊ณต๊ฐ, createStore ๋ฉ์๋๋ฅผ ํ์ฉํด Reducer๋ฅผ ์ฐ๊ฒฐํด Store๋ฅผ ์์ฑํ ์ ์๋ค.
import { createStore } from 'redux';
const store = createStore(rootReducer);
โ ์ ์ญ ๋ณ์ ์ ์ฅ์ ์ค์ ๋ฐฉ๋ฒ
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
{/*
react-redux์์ Provider ๋ถ๋ฌ์ค๊ธฐ
Provider๋ store๋ฅผ ์์ฝ๊ฒ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ ์ปดํฌ๋ํธ
Store๋ฅผ ์ฌ์ฉํ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ธ์ค ํ, Provider ์ปดํฌ๋ํธ์ Props๋ก store ์ค์
*/}
import { Provider } from 'react-redux';
{/*
redux์์ createStore ๋ถ๋ฌ์ค๊ธฐ
*/}
import { legacy_createStore as createStore } from 'redux';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
const reducer = () => {};
{/*
๋ณ์ store์ createStore ๋ฉ์๋๋ฅผ ํตํด store ๋ง๋ค์ด ์ฃผ๊ณ createStore์ ์ธ์๋ก reducer ํจ์ ์ ๋ฌ
*/}
const store = createStore(reducer);
root.render(
{/*
์ ์ญ ์ํ ์ ์ฅ์ store ์ฌ์ฉ์ ์ํด App ์ปดํฌ๋ํธ๋ฅผ Provider๋ก ๊ฐ์ผ ํ, Props๋ก ๋ณ์ store ์ ๋ฌ
*/}
<Provider store={store}>
<App />
</Provider>
);
๐ Dispatch
- Reducer๋ก Action์ ์ ๋ฌํด ์ฃผ๋ ํจ์
- Duspatch์ ์ ๋ฌ์ธ์๋ก Action ๊ฐ์ฒด๊ฐ ์ ๋ฌ
- Action ๊ฐ์ฒด๋ฅผ ์ ๋ฌ๋ฐ์ Dispatch ํจ์๋ Reducer๋ฅผ ํธ์ถ
// Action ๊ฐ์ฒด๋ฅผ ์ง์ ์์ฑํ๋ ๊ฒฝ์ฐ
dispatch( { type: 'INCREASE' } );
dispatch( { type: 'SET_NUMBER', payload: 5 } );
// ์ก์
์์ฑ์(Action Creator)๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
dispatch( increase() );
dispatch( setNumber(5) );
๐ Redux Hooks
- React-Redux์์ Redux๋ฅผ ์ฌ์ฉํ ๋ ํ์ฉํ ์ ์๋ Hooks ๋ฉ์๋๋ฅผ ์ ๊ณต
- useDispatch()
- Action ๊ฐ์ฒด๋ฅผ Reducer๋ก ์ ๋ฌํด ์ฃผ๋ Dispatch ํจ์๋ฅผ ๋ฐํํ๋ ๋ฉ์๋
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
dispatch( increase() )
console.log(counter) // 2
dispatch( setNumber(5) )
console.log(counter) // 5
[useDispatch ์ค์ต]
import React from 'react';
import './style.css';
// react-redux์์ useDispatch ๋ถ๋ฌ์ค๊ธฐ
import { useDispatch } from 'react-redux';
// Action Creater ํจ์ increase, decrease ๋ถ๋ฌ์ค๊ธฐ
import { increase, decrease } from './index.js';
export default function App() {
// useDispatch์ ์คํ ๊ฐ๋ฅผ ๋ณ์์ ์ ์ฅํด์ dispatch ํจ์๋ฅผ ์ฌ์ฉ
const dispatch = useDispatch();
console.log(dispatch);
const plusNum = () => {
// ์ด๋ฒคํธ ํธ๋ค๋ฌ ์์์ dispatch๋ฅผ ํตํด action ๊ฐ์ฒด๋ฅผ Reducer ํจ์๋ก ์ ๋ฌ
dispatch(increase());
};
const minusNum = () => {
// ์ด๋ฒคํธ ํธ๋ค๋ฌ ์์์ dispatch๋ฅผ ํตํด action ๊ฐ์ฒด๋ฅผ Reducer ํจ์๋ก ์ ๋ฌ
dispatch(decrease());
};
return (
<div className="container">
<h1>{`Count: ${1}`}</h1>
<div>
<button className="plusBtn" onClick={plusNum}>
+
</button>
<button className="minusBtn" onClick={minusNum}>
-
</button>
</div>
</div>
);
}
- useSelector()
- ์ปดํฌ๋ํธ์ state๋ฅผ ์ฐ๊ฒฐํ์ฌ Redux์ state์ ์ ๊ทผํ ์ ์๊ฒ ํด์ฃผ๋ ๋ฉ์๋
// Redux Hooks ๋ฉ์๋๋ 'redux'๊ฐ ์๋๋ผ 'react-redux'์์ ๋ถ๋ฌ์ต๋๋ค.
import { useSelector } from 'react-redux'
const counter = useSelector(state => state)
console.log(counter) // 1
[useSelector ์ค์ต]
import React from 'react';
import './style.css';
// react-redux์์ useDispatch, useSeletor ๋ถ๋ฌ์ค๊ธฐ
import { useDispatch, useSelector } from 'react-redux';
import { increase, decrease } from './index.js';
export default function App() {
const dispatch = useDispatch();
{
/* useSelector์ ์ฝ๋ฐฑ ํจ์์ ์ธ์์ Store์ ์ ์ฅ๋ ๋ชจ๋ state๊ฐ
๋ด๊ธด๋ค. ๊ทธ๋๋ก return์ ํ๊ฒ ๋๋ฉด Store์ ์ ์ฅ๋ ๋ชจ๋ state๋ฅผ
์ฌ์ฉํ ์ ์๋ค. */
}
const state = useSelector((state) => state);
{
/* ๋ณ์ state๋ฅผ ์ฝ์์์ ํ์ธ, Store์ ์ ์ฅ๋ ๊ธฐ์กด state ๊ฐ์ธ
1์ด ์ฐํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. */
}
console.log(state);
const plusNum = () => {
dispatch(increase());
};
const minusNum = () => {
dispatch(decrease());
};
return (
<div className="container">
{/* Store์์ ๊บผ๋ด์จ state๋ฅผ ํ๋ฉด์ ๋ํ๋ด๊ธฐ ์ํด ๋ณ์ state๋ฅผ ํ์ฉ */}
<h1>{`Count: ${state}`}</h1>
<div>
<button className="plusBtn" onClick={plusNum}>
+
</button>
<button className="minusBtn" onClick={minusNum}>
-
</button>
</div>
</div>
);
}
// +, - ๋ฒํผ์ ๋๋ฅผ ๋๋ง๋ค state๊ฐ ๋ณ๊ฒฝ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค!
'๐ป Development > React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[React] React Diffing Algorithm (0) | 2023.03.01 |
---|---|
[React] Virtual DOM (0) | 2023.03.01 |
[React] Props Drilling (0) | 2022.12.27 |
[React] Cmarket Hooks (0) | 2022.12.27 |
[React] ์ํ๊ด๋ฆฌ (0) | 2022.12.27 |