1. Redux๋ฅผ ์ ์ฐ๋๊ฐ?
- ํด๋น ์ํ๋ฅผ ์ง์ ์ฌ์ฉํ์ง ์๋ ์ต์์ ์ปดํฌ๋ํธ, ์ปดํฌ๋ํธ1, ์ปดํฌ๋ํธ2๋ ์ํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง
- ์ํ ๋์ด์ฌ๋ฆฌ๊ธฐ, Props ๋ด๋ ค์ฃผ๊ธฐ๋ฅผ ์ฌ๋ฌ ๋ฒ ๊ฑฐ์ณ์ผ ํจ
- ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ณต์กํด์ง์๋ก ๋ฐ์ดํฐ ํ๋ฆ๋ ๋ณต์กํด์ง
- ์ปดํฌ๋ํธ ๊ตฌ์กฐ๊ฐ ๋ฐ๋๋ค๋ฉด, ์ง๊ธ์ ๋ฐ์ดํฐ ํ๋ฆ์ ์์ ํ ๋ฐ๊ฟ์ผ ํ ์๋ ์์
โฅ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ Redux๋, ์ ์ญ ์ํ๋ฅผ ๊ด๋ฆฌํ ์ ์๋ ์ ์ฅ์์ธ Store๋ฅผ ์ ๊ณตํด์ ๋ฐ์ดํฐ ํ๋ฆ์ ๊น๋ํ๊ฒ ๋ง๋ค์ด์ค๋ค.
2. Redux์ ๊ตฌ์กฐ
Action ๊ฐ์ฒด ⇒ Dispatch ํจ์ ⇒ Reducer ํจ์ ⇒ ์ ์ญ ์ํ ์ ์ฅ์ Store ์ํ๋ฅผ ๋ณ๊ฒฝ ⇒ ํ๋ฉด ๋ฆฌ๋ ๋๋ง
- ์ํ๊ฐ ๋ณ๊ฒฝ๋์ด์ผ ํ๋ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด, ๋ณ๊ฒฝ๋ ์ํ์ ๋ํ ์ ๋ณด๊ฐ ๋ด๊ธด Action ๊ฐ์ฒด๊ฐ ์์ฑ๋ฉ๋๋ค.
- ์ด Action ๊ฐ์ฒด๋ Dispatch ํจ์์ ์ธ์๋ก ์ ๋ฌ๋ฉ๋๋ค.
- Dispatch ํจ์๋ Action ๊ฐ์ฒด๋ฅผ Reducer ํจ์๋ก ์ ๋ฌํด์ค๋๋ค.
- Reducer ํจ์๋ Action ๊ฐ์ฒด์ ๊ฐ์ ํ์ธํ๊ณ , ๊ทธ ๊ฐ์ ๋ฐ๋ผ ์ ์ญ ์ํ ์ ์ฅ์ Store์ ์ํ๋ฅผ ๋ณ๊ฒฝํฉ๋๋ค.
- ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ฉด, React๋ ํ๋ฉด์ ๋ค์ ๋ ๋๋ง ํฉ๋๋ค.
3. Redux ๋ ์์ธํ ๊ณต๋ถํ๊ธฐ
1) **Action // type ์ง์ ํ์!
(๊ฐ์ฒด๋ก ๋ง๋ค๊ธฐ)
// payload๊ฐ ํ์ ์๋ ๊ฒฝ์ฐ
{ type: 'INCREASE' }
// payload๊ฐ ํ์ํ ๊ฒฝ์ฐ
{ type: 'SET_NUMBER', payload: 5 }
(Action ๊ฐ์ฒด ์์ฑํ๋ ํจ์๋ก ๋ง๋ค๊ธฐ = Action Creator)
// payload๊ฐ ํ์ ์๋ ๊ฒฝ์ฐ
const increase = () => {
return {
type: 'INCREASE'
}
}
// payload๊ฐ ํ์ํ ๊ฒฝ์ฐ
const setNumber = (num) => {
return {
type: 'SET_NUMBER',
payload: num
}
}
2) Dispatch = Reducer๋ก Action์ ์ ๋ฌํด์ฃผ๋ ํจ์ // Dispatch์ ์ ๋ฌ์ธ์๋ก Action ๊ฐ์ฒด๊ฐ ์ ๋ฌ๋๋ค.
// Action ๊ฐ์ฒด๋ฅผ ์ง์ ์์ฑํ๋ ๊ฒฝ์ฐ
dispatch( { type: 'INCREASE' } );
dispatch( { type: 'SET_NUMBER', payload: 5 } );
// ์ก์
์์ฑ์(Action Creator)๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
dispatch( increase() );
dispatch( setNumber(5) );
3) Reducer = Dispatch์๊ฒ์ ์ ๋ฌ๋ฐ์ Action ๊ฐ์ฒด์ type ๊ฐ์ ๋ฐ๋ผ์ ์ํ๋ฅผ ๋ณ๊ฒฝ์ํค๋ ํจ์
Reducer๋ ์์ํจ์์ฌ์ผ ํ๋ค.
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๊ฐ ๋ฆฌํดํ๋ ๊ฐ์ด ์๋ก์ด ์ํ๊ฐ ๋ฉ๋๋ค.
4) Store = ์ํ๊ฐ ๊ด๋ฆฌ๋๋ ์ค์ง ํ๋๋ฟ์ธ ์ ์ฅ์์ ์ญํ
createStore ๋ก ์์ฑํ๊ฑฐ๋ import ํ ์ ์๋ค.
const store = createStore(rootReducer);
import { createStore } from 'redux';
5) Redux Hooks
useSelector() = ์ปดํฌ๋ํธ์ state๋ฅผ ์ฐ๊ฒฐํ์ฌ Redux์ state์ ์ ๊ทผํ ์ ์๊ฒ ํด์ฃผ๋ ๋ฉ์๋
// Redux Hooks ๋ฉ์๋๋ 'redux'๊ฐ ์๋๋ผ 'react-redux'์์ ๋ถ๋ฌ์ต๋๋ค.
import { useSelector } from 'react-redux'
const counter = useSelector(state => state.counterReducer)
console.log(counter) // 1
useDispatch() = Action ๊ฐ์ฒด๋ฅผ Reducer๋ก ์ ๋ฌํด ์ฃผ๋ ๋ฉ์๋
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
dispatch( increase() )
console.log(counter) // 2
dispatch( setNumber(5) )
console.log(counter) // 5
Redux์ ์ธ ๊ฐ์ง ์์น
1. Single source of truth
๋์ผํ ๋ฐ์ดํฐ๋ ํญ์ ๊ฐ์ ๊ณณ์์ ๊ฐ์ง๊ณ ์์ผ ํ๋ค๋ ์๋ฏธ์ ๋๋ค. ์ฆ, Redux์๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ Store๋ผ๋ ๋จ ํ๋๋ฟ์ธ ๊ณต๊ฐ์ด ์์๊ณผ ์ฐ๊ฒฐ์ด ๋๋ ์์น์ ๋๋ค.
2. State is read-only
์ํ๋ ์ฝ๊ธฐ ์ ์ฉ์ด๋ผ๋ ๋ป์ผ๋ก, React์์ ์ํ๊ฐฑ์ ํจ์๋ก๋ง ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์์๋ ๊ฒ์ฒ๋ผ, Redux์ ์ํ๋ ์ง์ ๋ณ๊ฒฝํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ฆ, Action ๊ฐ์ฒด๊ฐ ์์ด์ผ๋ง ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์์๊ณผ ์ฐ๊ฒฐ๋๋ ์์น์ ๋๋ค.
3. Changes are made with pure functions
๋ณ๊ฒฝ์ ์์ํจ์๋ก๋ง ๊ฐ๋ฅํ๋ค๋ ๋ป์ผ๋ก, ์ํ๊ฐ ์๋ฑํ ๊ฐ์ผ๋ก ๋ณ๊ฒฝ๋๋ ์ผ์ด ์๋๋ก ์์ํจ์๋ก ์์ฑ๋์ด์ผํ๋ Reducer์ ์ฐ๊ฒฐ๋๋ ์์น์ ๋๋ค.