Redux

May 24, 2022

build your own redux

明确需求

以下是一段 redux 的简单使用例子

import { createStore } from 'redux'

const initState = {
  name: 'hutchins',
  age: 25
}

const reducer = (state = initState, action) => {
  if (!state) {
    return initState
  }

  if (action.type === 'UPDATE_NAME') {
    return {
      ...state,
      name: action.payload
    }
  } else if (action.type === 'UPDATE_AGE') {
    return {
      ...state,
      age: action.payload
    }
  } else {
    return state
  }
}

const store = createStore(reducer)

const actions = {
  updateName: (name) =>
    store.dispatch({
      type: 'UPDATE_NAME',
      payload: name
    }),
  updateAge: (age) =>
    store.dispatch({
      type: 'UPDATE_AGE',
      payload: age
    })
}

store.subscribe(() => {
  console.info(store.getState())
})

actions.updateAge(20) // {name: "hutchins", age: 20}
actions.updateName('hengheng') // {name: "hengheng", age: 20}

通过上述例子,我们总结出,我们需要实现的方法只有一个,那就是 createStore,这个方法接受一个 reducer 方法作为参数,返回一个 store 对象,store 对象中包含 subscribe、dispatch、getState 方法。

interface Action<T = any> {
  type: T
}

interface AnyAction extends Action {
  // Allows any extra properties to be defined in an action.
  [extraProps: string]: any
}

type Reducer<S = any, A extends Action = AnyAction> = (state: S, action: A) => S

type Store = {
  getState: () => any
  dispatch: (action: AnyAction) => void
  subscribe: (listener: () => void) => { unsubscribe: () => void }
}

const createStore = (reducer: Reducer): Store

需求实现

export const createStore = (reducer: Reducer): Store => {
  let state: any = null
  let listeners: any[] = []
  // 订阅
  const subscribe = (listener: any) => {
    listeners.push(listener)
    return {
      unsubscribe: () => {
        listeners = listeners.filter((l) => l !== listener)
      }
    }
  }
  // 触发
  const dispatch = (action: AnyAction) => {
    state = reducer(state, action)
    listeners.forEach((l) => l(state))
  }
  // 初始化 state
  dispatch({ type: Symbol('redux init') })

  const getState = () => state

  return {
    getState,
    subscribe,
    dispatch
  }
}

可以看到,redux 就是一个非常经典的订阅发布模式,subscribe 订阅,dispatch 获得 action 的给 reducer 去更新 state 并通知所有订阅者