Redux 스타일 Store 직접 구현

type Reducer<S, A> = (state: S, action: A) => S
type Listener<S> = (state: S) => void

interface Store<S, A> {
  getState: () => S
  subscribe: (listener: Listener<S>) => () => void
  dispatch: (action: A) => A
}

function createStore<S, A>(
  reducer: Reducer<S, A>,
  preloadedState: S
): Store<S, A> {
  let currentState: S = preloadedState
  let listeners: Listener<S>[] = []

  function getState(): S {
    return currentState
  }

  function subscribe(listener: Listener<S>): () => void {
    listener(currentState)

    listeners.push(listener)

    return function unsubscribe() {
      listeners = listeners.filter((l) => l !== listener)
    }
  }

  function dispatch(action: A): A {
    currentState = reducer(currentState, action)

    listeners.forEach((listener) => {
      listener(currentState)
    })

    return action
  }

  return {
    subscribe,
    getState,
    dispatch,
  }
}

type Item = {
  body: string
}

type State = {
  items: Item[]
}

type Action = {
  type: 'ADD'
  payload: Item
}

const store = createStore<State, Action>(
  (state, action) => {
    switch (action.type) {
      case 'ADD':
        return {
          ...state,
          items: state.items.concat(action.payload),
        }
      default:
        return state
    }
  },
  {
    items: [],
  }
)

store.subscribe((state) => {
  console.log(state.items)
})

store.dispatch({
  type: 'ADD',
  payload: {
    body: 'hello',
  },
})
#484

redux 에서 trace 가 필요하면 redux-devtools 의 trace 설정을 켠다. 다만 메모리 릭 가능성이 있어서 상시로 켜두긴 어렵다 — 우회한다면 무식하지만 의심 지점에 console.trace()를 직접 넣는다.

#71