1. ์ ์ญ ์ํ ๊ด๋ฆฌ
1.1 state๋ ?
state: React component์์ ๊ด๋ฆฌ๋๊ณ ์๋ ์ด๋ค ๊ฐ์ ์ญ ์ํ ๊ด๋ฆฌ(global state management)- Globalํ ์ด๋ค๊ฒ์ ๋ฃ๊ณ ๊ฐ์ ๋ฐ๋ก ํ์ํ๊ฒ๋ค๋ง ๋ณด๊ฒ ๋ง๋๋๊ฒ
- ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ (e.g. redux, context API, recoil ๋ฑ)
2. Flux
- Facebook์์ ๋ง๋ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ํ์ฌ๋ ์ ์ง๋ณด์๋ง ๋๋์ค.
- Redux๋ Recoil๋ฑ์ ์ฌ์ฉํ๊ธฐ๋ฅผ ๊ถ์ฅ
- cf. https://facebook.github.io/flux/
2.1 Flux ๊ธฐ๋ณธ ๊ตฌ์ฑ
1โ Action โ2Action โ Dispatcher โ Store โ View
Action, Dispatcher, Store, View ๋ฑ์ผ๋ก ๊ตฌ์ฑ๋จ
Action- ์ฌ์ฉ์์ Input์ ํตํด์, ๋๋ ์ํ๋ฅผ ๋ฐ๊ฟ์ผ๋ง ํ ๋ ๋ฐ์
- Action (type, parameter)
Dispatcher (๋ฐ์ก์ธ)- ๋ชจ๋ ๋ฐ์ดํฐ์ ํ๋ฆ์ ๊ด๋ฆฌํ๋ ์ค์ ํ๋ธ
- Store๋ก์ ์ ๊ทผ์ด ๊ฐ๋ฅ
Store, View- ์ํ ์ ์ฅ์. ์ํ๋ฅผ ์ ๋ฐ์ดํธ ํ ์ ์๋ ํจ์๋ฅผ ์ ๊ณต
- ๋ณ๊ฒฝ๋ ๋ค์๋ View๋ก ์ ๋ฌ
3. Redux
1Action โฏ2โโ Reducer โฏโ Store New State3Prev State โฏ
- Flux์์ Reducer์ ๊ฐ๋ ์ด ๋ค์ด๊ฐ๊ฒ
Reducer: Action๊ณผ ๋ง์ง๋ง Store์ ์ํ๋ฅผ ๊ธฐ์ค์ผ๋ก ์๋ก์ด ์ํ๋ฅผ ๋ง๋ค์ด ์ฃผ๋ ๊ฒ
3.1 Redux ์ฌ์ฉ ๊ท์น
(1) Single source of truth
- ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชจ๋ ์ํ๋ ํ๋์ ์ ์ฅ์ ์์ ์ ์ฅํด์ผ ํ๋ค
- ์ฌ๋ฌ๊ฐ ์ผ ๊ฒฝ์ฐ ์ถฉ๋ ํน์ ๋๊ธฐํ์ ๋ํ ์ด์๊ฐ ๋ฐ์
- ๋๋ฒ๊น ๊ณผ ์์ฐ์ฑ ํฅ์์ ์ด์ ์ ๊ฐ์ง๊ณ ์์
(2) State is read-only
- ์ํ๋ ์ฝ๊ธฐ๋ง ํ์ฉ
- ์ก์ ์ ํตํด์๋ง ๋ณ๊ฒฝ ๊ฐ๋ฅ
- ๋ณํ์ ์๋๋ฅผ ํ์ ํ๊ณ ์ค์์์ ํ๋ฆ ๊ด๋ฆฌ๋ฅผ ์๊ฒฉํ๊ฒ ํ๊ธฐ ์ํจ
(3) Changes are made with pure functions
- ๋ณํ๋ ์์ํจ์๋ก๋ง ํด์ผํจ
์์ํจ์: ์ธ๋ถ ๊ฐ์ ์์กดํ์ง ์๊ณ ๋งค๊ฐ๋ณ์๋ง์ ํตํด์ ๋ฐํ๊ฐ์ ๋ง๋ค์ด ๋ด๋ ๊ฒ
1let c = 32const sum = (a, b) => {3return a + b + c4}5console.log(sum(1, 2)) //return 66c = 57console.log(sum(1, 2)) //return 8
4. Redux middleware
4.1 Redux ๋ฐ์ดํฐ ํ๋ฆ
1โ Action โ2Reducer โ Store โ View
4.2 Middleware
1middleware โ store.dispatch โ Action2โ โ3Reducer โ Store โ View
- store.dispatch ํจ์์ ์คํ ๋ค ์ด๋ ํ ์์ ์ ํ๊ธฐ ์ํด ํธ์ถ
4.3 redux logger
prev state์next state, action๋ฑ์ ๋์ดํด ๋ณด์ฌ์ค- ๋๋ฒ๊น ์ ์ํ์ฌ ์ฌ์ฉ
4.4 thunk
ํน์ ์์ ์ ๋์ค์ ํ๊ธฐ ์ํด์ ๋ง๋ค์ด๋ ํจ์
1const a = 52console.log(a)34const func = () => {5return 56}78console.log(func())
4.5 redux-thunk
- ๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌํ ๋ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ middleware
- ๊ฐ์ฒด ๋์ ํจ์๋ฅผ Dispatch ํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฒ
1const increase = () => {2return {3type: 'INCREASE',4}5}6const increaseCountOnSleep = () => dispatch => {7dispatch({ type: 'WAIT' })8setTimeout(() => {9dispatch(increase())10}, 1000)11}
1const successGetMyInfo = myInfo => dispatch => {2return {3type: 'SUCCESS_MY_INFO',4}5}6const getMyInfo = () => dispatch => {7dispatch({ type: 'REQUEST_MY_INFO' })8try {9//API ํธ์ถ ํ๋ ์ฝ๋10dispatch(successGetMyInfo('๋ด ์ ๋ณด'))11} catch (ex) {12dispatch(failureGetMyInfo())13}14}
4.6 redux-saga
action์ ๋ฐ์์ฌ๋ถ๋ฅผ ๋ชจ๋ํฐ๋ง ํ๋ค๊ฐ ๊ทธ ๋ค ์์ ์ ์งํ ํ๋๋ก ํจ
1const increase = () => ({ type: 'INCREASE' })2function* increaseSaga() {3yield delay(1000)4yield put(increse())5}67function* counterSaga() {8// takeEvery : ์ก์ ์ ๋ชจ๋ํฐ๋ง ํ๊ณ ๋ฐ์ํ๋ฉด increaseSaga ํธ์ถ9yield takeEvery('INCREASE_ASYNC', increaseSaga)10}
4.7 redux-thunk vs redux-saga
๋๋ค ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํ๊ฒ์ผ๋ก, ์ํฉ์ ๋ง๊ฒ ์ฌ์ฉ
redux thunk- pros
- ๋ฎ์ Boilerplate
- ์ดํดํ๊ธฐ ์ฌ์ด ์ฝ๋
- cons
- ์๋ชป ๋ค๋ค์ง๋ฉด ์์์ด ๋ง์ ์ฝ๋ฐฑ ์ง์ฅ์ ๋น ์ง
- pros
redux saga- pros
- ์ด๊ธฐ์ ๊ตฌํํด์ผํ Boilerplate๊ฐ ๋ง์
- ์์ํจ์๋ก ์์ฑ๋๊ธฐ ๋๋ฌธ์ ํ ์คํธ ์ ์ฉ์ด ์ฌ์
- cons
- ๋์ ๋ฌ๋์ปค๋ธ (ES6 ์ ๋๋ ์ดํฐ)
- pros
5. Redux์์ ์์ฃผ ์ฌ์ฉํ๋ hook
5.1 useSelector
store์ ์๋ ๊ฐ์ ๊ฐ์ ธ์ค๊ธฐ ์ํจ
1const componentA = () => {2const value = useSelector(state => state.value)3return (4// ๋ ๋ค๋ฅธ View code5<View></View>6)7}
5.2 useDispatch
redux action์ ์ฌ์ฉํ๊ธฐ ์ํ hook
1const componentA = () => {2const dispatch = useDispatch()3const someAction = useCallback(() => {4dispatch(someActions())5}, [])6return (7// ๋๋ค๋ฅธ View code8<View></View>9)10}
5.3 useSelector (before hook)
hook์ด ์๊ธฐ ์ ์๋ connect ํจ์๋ฅผ ํตํ์ฌ ์งํ
1const componentA = () => {2/* ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ฑํ๋ ์ฝ๋ */3}4const mapStateToProps = state => {5return {6/* ๋ด๊ณ ์ถ์ state ์ง์ */7}8}9const mapDispatchToProps = dispatch => {10return {11/*์ฌ์ฉํ action ์ ์ฅ*/12}13}14export default connect(mapStateToProps, mapDidpatchToProps)
5.4 createSelector
- reselect package์ ์๋ ํจ์
- Memoization๋ฑ ์บ์ฑ์ ํ๊ธฐ ์ํด ์ฌ์ฉ
1const valueSelector = createSelector(2state => state.value,3value => {4/* ์ด๋ ํ ์ฐ์ฐ*/5},6)7const componentA = () => {8const value = useSelector(valueSelector)9return (10// ๋๋ค๋ฅธ View code11<View></View>12)13}
6. Context API
- React 16.3 ๋ฒ์ ๋ถํฐ ์ง์
- props-drilling์ ์ ๊ฑฐํ๊ธฐ ์ํด ํ์
- ๊ฐ๋จํ ์ ์ญ๋ณ์(e.g. theme, intl)๋ฅผ ์ ์ธํ ๋ ์ฌ์ฉ
6.1 Context API ๊ตฌ์ฑ์์, Provider
๊ฐ์ ์ ๊ณต ํด์ฃผ๊ธฐ ์ํ์ฌ root component๋ก ์ฌ์ฉ
1const SomeContext = createContext()23const componentA = () => {4return (5// ๋๋ค๋ฅธ View code6<SomeContext.Provider value={'testValue'}>{/* ๊ฐ์ ์ฌ์ฉํด์ผํ๋ ์ปดํผ๋ํธ๋ค */}</SomeContext.Provider>7)8}
6.2 Context API ๊ตฌ์ฑ์์, Consumer
์ ๊ณต๋ ๊ฐ์ ์ ๊ทผ ํ ์ ์๋๋ก ํ๋๊ฒ
1const componentB = () => {2return (3// ๋๋ค๋ฅธ View code4<SomeContext.Consumer>5{context => {6/* child์ ์๋ ์ปดํฌ๋ํธ์์๋ง ๊ฐ ์ฌ์ฉ ๊ฐ๋ฅ */7}}8</SomeContext.Consumer>9)10}
6.3 Redux vs Context API
Context API: ์ํ ๊ด๋ฆฌ ๋๊ตฌ X, ์ ์ญ ๋ณ์ ๊ด๋ฆฌ O- ์ํ๊ด๋ฆฌ ๋๊ตฌ์ ์กฐ๊ฑด
- ์ด๊ธฐ๊ฐ์ ์ ์ฅํ๋๊ฐ?
- ์ค์ค๋ก ๊ฐ์ ์ฝ์ด์ฌ ์ ์๋๊ฐ?
- ์ค์ค๋ก ๊ฐ ์ ๋ฐ์ดํธ๊ฐ ๊ฐ๋ฅํ๊ฐ?
- Context API
- ์ด๊ธฐ๊ฐ์ ์ ์ฅํ๋๊ฐ? (Provider์์ value๋ฑ์ ์ค์ ๊ฐ๋ฅ)
- ์ค์ค๋ก ๊ฐ์ ์ฝ์ด์ฌ ์ ์๋๊ฐ? (์ค์ค๋ก state๋ฅผ ๊ฐ์ง๊ณ ์์ง ์์ ๊ฐ์ ์ ๋ฌ ํด์ค์ผํจ)
- ์ค์ค๋ก ๊ฐ ์ ๋ฐ์ดํธ๊ฐ ๊ฐ๋ฅํ๊ฐ ? (์ค์ค๋ก state๋ฅผ ๊ฐ์ง๊ณ ์์ง ์์ updateํจ์๋ฅผ ํจ๊ป ์ ๋ฌํด์ค์ผ ํจ)
- Redux
- ์ด๊ธฐ๊ฐ์ ์ ์ฅํ๋๊ฐ? (reducer ์์ฑ์ ์ด๊ธฐ๊ฐ ์ง์ ๊ฐ๋ฅ)
- ์ค์ค๋ก ๊ฐ์ ์ฝ์ด์ฌ ์ ์๋๊ฐ? (selector, mapStateToProps ๋ฑ ํจ์๋ฅผ ํตํ์ฌ ์ฝ์ด์ค๊ธฐ ๊ฐ๋ฅ)
- ์ค์ค๋ก ๊ฐ ์ ๋ฐ์ดํธ๊ฐ ๊ฐ๋ฅํ๊ฐ? (dispatch action์ ํตํด์ ๊ฐ๋ฅ)
- ์ธ์ Context API๋ฅผ ์ฌ์ฉํ๋๊ฐ
- ์ฃผ๋ก staticํ ์ ๋ณ๊ฒฝ๋์ง ์๋ ์ ๋ณด์ ๋ํด์ ์ ์ฉ
- App theme ์ ์ฅ (light, dark) ๋ค๊ตญ์ ์ฑ์์ ์ธ์ด ํฉ ๋ฑ
7. Recoil
- 2020๋ ๋ ๋ฐํ, (cf. https://recoiljs.org/ko/ )
- Redux, MobX๋ฑ ๊ธฐ์กด ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์ฌ์ด ์ ๋ค์ ๊ทน๋ณตํ๊ณ ์ ํ์
- Redux์ ์ฅ๋จ์
- pros
- ๊ทธ๋์ ๋ง์ ๊ฒ์ฆ์ ๊ฑฐ์น ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- redux-logger ๋ฑ ๋๋ฒ๊ทธ๋ฅผ ์ํ ํธ์๊ฐ ์ ๊ฐ์ถฐ์ ธ ์์
- cons
- ๋์ ํ์ต๋น์ฉ(๋ฌ๋์ปค๋ธ)
- boilerplate๊ฐ ๋ค์ ์๋ ํธ
- pros
7.1 Recoil ๊ตฌ์ฑ์์
7.1.1 Atom
์ํ์ ๋จ์, ์ ๋ฐ์ดํธ ๋๋ subscribe ๋ฑ์ด ๊ฐ๋ฅ
1const fontSize = atom({2key: 'UNIQUE_KEY',3value: {4/* ์ํ ๊ด๋ฆฌ์ ์ฌ์ฉ ํ value*/5},6})78const componentA = () => {9const [fontSize, setFontSize] = useRecoilState(myState)10return /* View return */ <View></View>11}
7.1.2 selectors
atoms๋ selector์ ํ์๋ฐ์ดํฐ๋ฅผ ๊ณ์ฐํ๋๋ฐ ์ฌ์ฉ
1const fontSizeLabelState = selector({2key: 'UNIQUE_KEY',3get: ({ get }) => {4const fontSize = get(fontSizeState)5return `fontSize is ${fontSize}`6},7})89const componentA = () => {10const fontSizeLabel = useRecoilValue(fontSizeLabelState)11}