Skip to content

手写简版redux

实现代码

createStore

  1. createStore接收的第一个参数是reducer,需要返回getStatedispatchsubscribe等方法。
  2. getState返回的是当前的状态,可以用一个变量保存该状态:currentState
  3. reducer接收stateaction作为参数,可以通过action匹配不同的方法改变state,最终返回新的state
  4. dispatch的参数action,作为执行reducer的参数,并将reducer返回的新的state更改为当前state
  5. subscribe用于收集回调函数,在currentState改变时触发。
javascript
export const createStore = (reducer) => {
  let currentState
  let currentListeners = []

  const getState = () => {
    return currentState
  }

  const dispatch = (action) => {
    currentState = reducer(currentState, action)
    currentListeners.forEach(listener => listener())
  }

  const subscribe = (listener) => {
    currentListeners.push(listener)
    // 返回取消监听函数
    return () => {
      const index = currentListeners.indexOf(listener)
      currentListeners.splice(index, 1)
    }
  }

  // 更新初始化状态
  dispatch('@@redux/INIT-123456')

  return {
    getState,
    dispatch,
    subscribe
  }
}
export const createStore = (reducer) => {
  let currentState
  let currentListeners = []

  const getState = () => {
    return currentState
  }

  const dispatch = (action) => {
    currentState = reducer(currentState, action)
    currentListeners.forEach(listener => listener())
  }

  const subscribe = (listener) => {
    currentListeners.push(listener)
    // 返回取消监听函数
    return () => {
      const index = currentListeners.indexOf(listener)
      currentListeners.splice(index, 1)
    }
  }

  // 更新初始化状态
  dispatch('@@redux/INIT-123456')

  return {
    getState,
    dispatch,
    subscribe
  }
}

compose

将一个函数的返回结果作为另一个函数的参数,如:

javascript
// 原始写法
fn1(fn2(fn3(args)))

// 使用compose 函数可以改写为
compose(fn1, fn2, fn3)(args)
// 原始写法
fn1(fn2(fn3(args)))

// 使用compose 函数可以改写为
compose(fn1, fn2, fn3)(args)

compose函数的实现:

javascript
export const compose = (...funcs) => {
  if (funcs.length === 0) {
    return args => args
  }

  if (funcs.length === 1) {
    return funcs[0]
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
export const compose = (...funcs) => {
  if (funcs.length === 0) {
    return args => args
  }

  if (funcs.length === 1) {
    return funcs[0]
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

中间件

通过applyMiddleware方法应用中间件,将原有的dispatch方法进行增强。

基本使用方法:

javascript
const store = createStore(countReducer, applyMiddleware(logger, thunk))
const store = createStore(countReducer, applyMiddleware(logger, thunk))

因此createStore可以新增一个参数,叫做enhancer

javascript
export const createStore = (reducer, enhancer) => {
  if (enhancer) {
    // 加强 store
    return enhancer(createStore)(reducer)
  }
  ...
}
export const createStore = (reducer, enhancer) => {
  if (enhancer) {
    // 加强 store
    return enhancer(createStore)(reducer)
  }
  ...
}

接下来实现applyMiddleware方法:

javascript
export const applyMiddleware = (...middlewares) => {
  // createStore,reducer作为参数传入
  return createStore => reducer => {
    // 获取原有的 store,以及原有的一些方法
    const store = createStore(reducer)
    const { dispatch, getState } = store
    // 进行加强
    const middlewareAPI = { getState, dispatch }
    // 给中间件参数中加入 getState,dispatch
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // 增强dispatch方法
    const enhancedDispatch = compose(...chain)(dispatch)
    return {
      ...store,
      dispatch: enhancedDispatch
    }
  }
}
export const applyMiddleware = (...middlewares) => {
  // createStore,reducer作为参数传入
  return createStore => reducer => {
    // 获取原有的 store,以及原有的一些方法
    const store = createStore(reducer)
    const { dispatch, getState } = store
    // 进行加强
    const middlewareAPI = { getState, dispatch }
    // 给中间件参数中加入 getState,dispatch
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // 增强dispatch方法
    const enhancedDispatch = compose(...chain)(dispatch)
    return {
      ...store,
      dispatch: enhancedDispatch
    }
  }
}

redux-thunk中间件实现:github

javascript
export const thunk = () => {
  return dispatch => action => {
    if (typeof action === 'function') {
      return action(dispatch)
    } else {
      return dispatch(action)
    }
  }
}
export const thunk = () => {
  return dispatch => action => {
    if (typeof action === 'function') {
      return action(dispatch)
    } else {
      return dispatch(action)
    }
  }
}