πŸ“ Redux(1) - κ°œλ… 및 ꡬ쑰

1. why Redux?

λ¦¬λ•μŠ€λŠ” μƒνƒœ 관리 λΌμ΄λΈŒλŸ¬λ¦¬λ‹€. κΈ°μ‘΄ λ¦¬μ•‘νŠΈ ν”„λ‘œμ νŠΈμ—μ„œ A μ»΄ν¬λ„ŒνŠΈκ°€ propsλ₯Ό 톡해 B,C,D,F μ»΄ν¬λ„ŒνŠΈλ₯Ό κ±°μ³μ„œ F μ»΄ν¬λ„ŒνŠΈλ‘œ stateλ₯Ό μ „λ‹¬ν•˜λŠ” λ³΅μž‘ν•œ ꡬ쑰λ₯Ό 지녔닀면, λ¦¬λ•μŠ€λŠ” μŠ€ν† μ–΄(store)λΌλŠ” μƒνƒœ μ €μž₯μ†Œλ₯Ό μ»΄ν¬λ„ŒνŠΈ λ°”κΉ₯(μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μƒμœ„)에 λ‘μ–΄μ„œ, ν”„λ‘œμ νŠΈ μ „μ—­μ—μ„œ κ°„λ‹¨ν•˜κ²Œ μƒνƒœλ₯Ό 관리할 수 있게 ν•΄μ€€λ‹€. λ”°λΌμ„œ λ¦¬λ•μŠ€ μƒνƒœκ΄€λ¦¬ 라이브러리λ₯Ό μ‚¬μš©ν•˜λŠ” λ¦¬μ•‘νŠΈ ν”„λ‘œμ νŠΈμ—μ„œλŠ” A -> μŠ€ν† μ–΄ -> F와 같은 μ‹μœΌλ‘œ, κ°„λ‹¨ν•˜κ²Œ μƒνƒœλ₯Ό μ—…λ°μ΄νŠΈ ν•  수 있게 λ˜λŠ” 것이닀.

redux

사진 좜처 : https://www.tekportal.net/redux/

μ „μ—­ μƒνƒœ κ΄€λ¦¬λŠ” context APIλ‘œλ„ ν•΄κ²°ν•  수 μžˆλ‹€. ν•˜μ§€λ§Œ λ¦¬λ•μŠ€λ₯Ό μ‚¬μš©ν•  경우 μ½”λ“œμ˜ μœ μ§€λ³΄μˆ˜μ  μΈ‘λ©΄κ³Ό μž‘μ—…μ˜ 효율적 μΈ‘λ©΄μ—μ„œ 큰 이점을 λˆ„λ¦΄ 수 μžˆλ‹€κ³  ν•œλ‹€.

ReduxλŠ” React에 μ’…μ†λœ λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ•„λ‹ˆμ–΄μ„œ Vanilla-JS + Redux, Vue + Redux와 같은 λ‹€μ–‘ν•œ ν™œμš©μ΄ κ°€λŠ₯ν•˜λ‹€.

2. λ¦¬λ•μŠ€ κ°œλ…

1) μ•‘μ…˜(Action)

μ•‘μ…˜μ€ type 속성값을 가진 μžλ°”μŠ€ν¬λ¦½νŠΈ 객체닀.

{
    type: 'INCREASE'
}

μ•‘μ…˜μ€ β€˜μƒνƒœλ₯Ό γ…‡γ…‡ν•˜κ²Œ λ³€ν™”μ‹œμΌœλΌβ€™λΌλŠ” λͺ…령과도 κ°™λ‹€. dispatchλΌλŠ” μΌμ’…μ˜ νŠΈλ¦¬κ±°μ— μœ„ μ•‘μ…˜ 객체λ₯Ό λ‹΄μ•„μ„œ μŠ€ν† μ–΄μ— μ „λ‹¬ν•˜λŠ”κ²ƒμ€ μƒνƒœλ₯Ό INCREASE ν•˜λΌκ³  λͺ…λ Ήν•˜λŠ” 것과 κ°™λ‹€.

{
    type: 'ADD_TODO',
    data: {
        id: 1,
        text: 'λ¦¬λ•μŠ€ 배우기'
    }
}

{
    type: 'INCREASE',
    diff: 2
}

μ•‘μ…˜ 객체에 type ν•„λ“œλŠ” ν•„μˆ˜μ μœΌλ‘œ μž…λ ₯ν•΄μ•Ό ν•œλ‹€. type μ΄μ™Έμ˜ ν•„λ“œλ₯Ό μž…λ ₯ν•΄μ„œ μƒνƒœ λ³€ν™”μ‹œ μ°Έκ³ ν•  값듀을 지정해쀄 수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄, INCREASEμ‹œ diff 값을 μ°Έκ³ ν•΄μ„œ 2μ”© INCREASE ν•œλ‹€λ“ κ°€.

2) μ•‘μ…˜ μƒμ„±μž(Action Creator)

μ•‘μ…˜ μƒμ„±μžλŠ” μ•‘μ…˜ 객체λ₯Ό λ§Œλ“€μ–΄μ£ΌλŠ” ν•¨μˆ˜λ‹€.

function addTodo(data){
    return {
        type: 'ADD_TODO',
        data
    };
}

// ν™”μ‚΄ν‘œ ν•¨μˆ˜ ν˜•νƒœ
// export ν‚€μ›Œλ“œλ₯Ό λΆ™μ—¬μ„œ λ‹€λ₯Έ νŒŒμΌμ—μ„œ μ•‘μ…˜ μƒμ„±μžλ₯Ό λΆˆλŸ¬μ™€ μ‚¬μš©ν•  수 μžˆλ‹€.
export const addTodo = data =>({
    type: 'ADD_TODO',
    data
});

μ•‘μ…˜ κ°μ²΄λŠ” 가급적 μ•‘μ…˜ μƒμ„±μžλ‘œ λ§Œλ“œλŠ” 것이 μ’‹λ‹€. 좔후에 μ•‘μ…˜ 객체의 ꡬ쑰λ₯Ό λ³€κ²½ν•  일이 생길 경우 등에 이점을 κ°€μ Έλ‹€μ£ΌκΈ° λ•Œλ¬Έμ΄λ‹€. μ•‘μ…˜ μƒμ„±μžλŠ” redux-actions 라이브러리의 createAction ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ λ”μš± κ°„νŽΈν•˜κ²Œ λ§Œλ“€ 수 μžˆλ‹€. (λ‹€μŒ κ²Œμ‹œκΈ€ μ°Έμ‘°)

3) λ¦¬λ“€μ„œ(Reducer)

λ¦¬λ“€μ„œλŠ” μ•‘μ…˜μ΄ λ°œμƒν–ˆμ„ λ•Œ μƒˆλ‘œμš΄ 상탯값을 λ§Œλ“œλŠ” ν•¨μˆ˜λ‹€. λ¦¬λ“€μ„œλŠ” ν˜„μž¬ μƒνƒœ(state)와 μ•‘μ…˜μ„ νŒŒλΌλ―Έν„°λ‘œ μ „λ‹¬λ°›λŠ”λ‹€. μ•‘μ…˜μ— μ˜κ±°ν•œ μƒνƒœ λ³€ν™” λ‘œμ§μ„ μ •μ˜ν•΄λ‘μ–΄μ„œλŠ”, 전달받은 μ•‘μ…˜λŒ€λ‘œ μƒνƒœλ₯Ό μ—…λ°μ΄νŠΈν•˜μ—¬ λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ‹€.

const initialState = {
    counter:1
};
// λ¦¬λ•μŠ€λŠ” μŠ€ν† μ–΄λ₯Ό 생성할 λ•Œ 상탯값이 μ—†λŠ” μƒνƒœλ‘œ λ¦¬λ“€μ„œλ₯Ό ν˜ΈμΆœν•˜λ―€λ‘œ,
// λ§€κ°œλ³€μˆ˜μ˜ 기본값을 μ‚¬μš©ν•΄μ„œ 초기 상탯값을 μ •μ˜ν•œλ‹€.
function reducer(state = initialState, action){
    switch(action.type){
        case INCREMENT:
            return{
                counter: state.counter +1
            };
        default:
            return state;
    }
}

λ¦¬λ“€μ„œλŠ” λ§ˆμ°¬κ°€μ§€λ‘œ redux-actions 라이브러리의 handleActions ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ λ”μš± κ°„νŽΈν•˜κ²Œ λ§Œλ“€ 수 μžˆλ‹€.

4) μŠ€ν† μ–΄(store)

μŠ€ν† μ–΄λŠ” μ»΄ν¬λ„ŒνŠΈ μ™ΈλΆ€μ—μ„œ λ¦¬λ•μŠ€μ˜ 상탯값을 κ°€μ§€λŠ” 객체닀. μŠ€ν† μ–΄ μ•ˆμ—λŠ” ν˜„μž¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μƒνƒœ(state)와 λ¦¬λ“€μ„œκ°€ λ“€μ–΄κ°€ μžˆλ‹€. μŠ€ν† μ–΄λŠ” dispatch, subscribe, getState와 같은 λ‚΄μž₯ν•¨μˆ˜λ₯Ό κ°–λŠ”λ‹€.

import {createStore} from 'redux';

(...)

const store = createStore(reducer);

5) λ””μŠ€νŒ¨μΉ˜(dispatch)

λ””μŠ€νŒ¨μΉ˜λŠ” μŠ€ν† μ–΄μ˜ λ‚΄μž₯ ν•¨μˆ˜ 쀑 ν•˜λ‚˜λ‘œ, μ•‘μ…˜μ„ λ°œμƒμ‹œν‚€λŠ” 트리거 역할을 λ§‘λŠ”λ‹€. dispatch(action)κ³Ό 같은 ν˜•νƒœλ‘œ ν˜ΈμΆœν•œλ‹€.

6) ꡬ독(Subscribe)

ꡬ독은 μŠ€ν† μ–΄μ˜ λ‚΄μž₯ ν•¨μˆ˜ 쀑 ν•˜λ‚˜λ‘œ, μŠ€ν† μ–΄μ— μ˜ν•œ μƒνƒœ μ—…λ°μ΄νŠΈκ°€ λ°œμƒν•  λ•Œλ§ˆλ‹€ κ΅¬λ…μ‹œ μ§€μ •ν•œ λ¦¬μŠ€λ„ˆ ν•¨μˆ˜κ°€ ν˜ΈμΆœλœλ‹€. 상탯값 λ³€κ²½ μ—¬λΆ€λ₯Ό ν™•μΈν•˜κΈ° μœ„ν•΄ 쓰인닀.

const listener= () => {
    console.log('μƒνƒœκ°€ μ—…λ°μ΄νŠΈλ¨');
}
const unsubscribe = store.subscribe(listener);

unsubscribe(); // μΆ”ν›„ ꡬ독을 λΉ„ν™œμ„±ν™”ν•  λ•Œ ν•¨μˆ˜λ₯Ό 호좜

subscribeλŠ” μœ„μ™€ 같이 μ§μ ‘μ μœΌλ‘œ ν˜ΈμΆœλ˜κΈ°λ³΄λ‹€λŠ” react-redux νŒ¨ν‚€μ§€μ—μ„œ μ œκ³΅ν•˜λŠ” connect() ν•¨μˆ˜λ‘œ λŒ€μ²΄ μ‚¬μš©λ˜λŠ” νŽΈμ΄λ‹€.

3. λ¦¬λ•μŠ€ ꡬ쑰

μ•žμ„œ 배운 κ°œλ…μ„ ν† λŒ€λ‘œ μ’€ 더 μƒμ„Έν•œ λ¦¬λ•μŠ€ μž‘λ™ ꡬ쑰λ₯Ό μ•Œμ•„λ³΄μž. redux2

  1. μ»΄ν¬λ„ŒνŠΈμ— μƒνƒœ λ³€ν™”κ°€ ν•„μš”ν•΄μ‘Œλ‹€. Dispatch(action)λ₯Ό 톡해 μŠ€ν† μ–΄μ— μ•Œλ¦¬μž.
  2. μŠ€ν† μ–΄λŠ” 가지고 있던 μƒνƒœμ •λ³΄μ™€, Dispatchλ₯Ό 톡해 전달받은 μ•‘μ…˜μ„ λ¦¬λ“€μ„œμ—κ²Œ μ „λ‹¬ν•˜λ©° ν˜ΈμΆœν•œλ‹€.
  3. λ¦¬λ“€μ„œλŠ” 전달받은 μ•‘μ…˜λŒ€λ‘œ μƒνƒœλ₯Ό λ³€ν™”μ‹œμΌœ λ°˜ν™˜ν•œλ‹€.
  4. λ³€ν™”λœ μƒνƒœλŠ” μŠ€ν† μ–΄μ— μ €μž₯λœλ‹€.

redux4

B μ»΄ν¬λ„ŒνŠΈμ—μ„œμ˜ λ³€ν™”κ°€ G μ»΄ν¬λ„ŒνŠΈμ— λ°˜μ˜λ˜λŠ” 경우λ₯Ό μƒκ°ν•΄λ³΄μž.

  1. λ¦¬μ•‘νŠΈ ν”„λ‘œμ νŠΈμ— λ¦¬λ•μŠ€ 라이브러리λ₯Ό μ μš©ν•˜λ©΄ Storeκ°€ 생긴닀. G μ»΄ν¬λ„ŒνŠΈλŠ” Store에 Subscribeλ₯Ό ν•œλ‹€. ꡬ독 κ³Όμ •μ—μ„œ GλŠ” μŠ€ν† μ–΄μ— νŠΉμ • ν•¨μˆ˜λ₯Ό μ „λ‹¬ν•˜κ³  subscribe(listener), 이후 μŠ€ν† μ–΄λŠ” μƒνƒœκ°€ μ—…λ°μ΄νŠΈλ  λ•Œλ§ˆλ‹€ ν•΄λ‹Ή ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•΄μ£ΌλŠ” ꡬ쑰닀.
  2. B μ»΄ν¬λ„ŒνŠΈμ— μ΄λ²€νŠΈκ°€ λ°œμƒν•΄μ„œ, μƒνƒœλ₯Ό λ³€ν™”ν•΄μ•Ό ν•˜λŠ” κ²½μš°κ°€ λ°œμƒν–ˆλ‹€. BλŠ” Action을 dispatch ν•¨μˆ˜μ— λ‹΄μ•„μ„œ μŠ€ν† μ–΄μ— μ „λ‹¬ν•œλ‹€.
  3. μ•‘μ…˜ 객체λ₯Ό 전달받은 μŠ€ν† μ–΄λŠ” λ¦¬λ“€μ„œ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœμ‹œν‚¨λ‹€. λ¦¬λ“€μ„œλŠ” λ¦¬λ“€μ„œ ν•¨μˆ˜μ— μ •μ˜λœ λ‘œμ§λŒ€λ‘œ μƒνƒœκ°’μ„ λ³€ν™”μ‹œν‚€κ³ , 이λ₯Ό λ°˜ν™˜ν•œλ‹€.
  4. μƒνƒœ λ³€ν™”κ°€ μƒκ²ΌμœΌλ―€λ‘œ, μŠ€ν† μ–΄λŠ” listener ν•¨μˆ˜λ₯Ό 톡해 μžμ‹ μ„ κ΅¬λ…ν•˜κ³  있던 μ»΄ν¬λ„ŒνŠΈλ“€(G)μ—κ²Œ μ•Œλ¦°λ‹€. 이λ₯Ό 톡해 μ»΄ν¬λ„ŒνŠΈλŠ” μƒˆλ‘œμš΄ μƒνƒœλ₯Ό λ°›κ²Œ 되고, λ¦¬λ Œλ”λ§μ„ ν•œλ‹€.

4. λ¦¬λ•μŠ€ μ‚¬μš© 원칙

1) 단일 μŠ€ν† μ–΄

ν•˜λ‚˜μ˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— ν•˜λ‚˜μ˜ μŠ€ν† μ–΄λ§Œ. μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ‚΄ μ—¬λŸ¬κ°œμ˜ μŠ€ν† μ–΄λ₯Ό λ‘˜ μˆ˜λŠ” μžˆμ§€λ§Œ μƒνƒœ 관리가 λ³΅μž‘ν•΄μ§ˆ 수 μžˆμœΌλ―€λ‘œ ꢌμž₯ν•˜μ§€ μ•ŠμŒ.

2) μƒνƒœλŠ” 읽기 μ „μš© μƒνƒœ

λ¦¬λ•μŠ€ μƒνƒœλŠ” 읽기 μ „μš©μ΄λ‹€. 상탯값을 λΆˆλ³€ 객체둜 관리해야 λ‚΄λΆ€μ μœΌλ‘œ 데이터가 λ³€κ²½λ˜λŠ” 것을 감지할 수 μžˆλ‹€.

3) λ¦¬λ“€μ„œλŠ” 순수 ν•¨μˆ˜

순수 ν•¨μˆ˜λŠ” λΆ€μˆ˜ 효과λ₯Ό λ°œμƒμ‹œν‚€μ§€ μ•Šμ•„μ•Ό ν•œλ‹€. λ˜ν•œ 같은 μΈμˆ˜μ— 항상 같은 값을 λ°˜ν™˜ν•΄μ•Ό ν•œλ‹€. λ”°λΌμ„œ λ¦¬λ“€μ„œ λ‚΄λΆ€μ—μ„œ 랜덀 κ°’ 생성, Date ν•¨μˆ˜ μ‚¬μš©, λ„€νŠΈμ›Œν¬ μš”μ²­ 등은 κΈˆμ§€λœλ‹€.

마무리

λ¦¬λ•μŠ€ μƒνƒœ 관리 라이브러리λ₯Ό κ°œλ… μ€‘μ‹¬μœΌλ‘œ μ‚΄νŽ΄λ³΄μ•˜λ‹€. λ‹€μŒ κΈ€μ—μ„œλŠ” μ½”λ“œλ₯Ό μ€‘μ‹¬μœΌλ‘œ λ¦¬λ•μŠ€ ν™œμš© μ˜ˆμ‹œλ₯Ό μ‚΄νŽ΄λ³΄λ„λ‘ ν•˜κ² λ‹€.

References

λ¦¬λ•μŠ€λŠ” 무엇이고, μ™œ μ‚¬μš©ν•˜λŠ”κ°€?

λ¦¬λ•μŠ€, μ™œ μ“ΈκΉŒ? 쉽고 νŽΈν•˜κ²Œ μ‚¬μš©ν•˜κΈ° μœ„ν•œ λ°œμ•…

<λ¦¬μ•‘νŠΈλ₯Ό λ‹€λ£¨λŠ” 기술 κ°œμ •νŒ>(κΉ€λ―Όμ€€, 2019)

<μ‹€μ „ λ¦¬μ•‘νŠΈ ν”„λ‘œκ·Έλž˜λ° κ°œμ •νŒ>(이재승, 2020)


Written by@Lechuck
초보 개발자

GitHub