Skip to main content

创建支持异步的插件

主要 API

  • createStore
  • getState
  • dispatch
  • subscribe
  • combineReducers
  • applyMiddleware
  • thunk // 新增

Core

const combineReducers = (reducers) => {
return (state, action) => {
const combineState = {}
const keys = Object.keys(reducers)
for (let key of keys) {
const partial = reducers[key](state === undefined ? state : state[key], action)
combineState[key] = partial
}
return combineState
}
}

const applyMiddleware = (...middlewares) => {
return (store) => {
let dispatch = store.dispatch
middlewares.forEach(middleware => {
dispatch = middleware(store)(dispatch)
})
return {
...store,
dispatch
}
}
}

const createStore = (reducer, applyMiddleware) => {
let state = reducer(undefined, {})
const listener = []

const store = {
getState: () => {
return state
},
subscribe: (fn) => {
listener.push(fn)
},
dispatch: (action) => {
state = reducer(state, action)
for (let fn of listener) {
fn && fn()
}
}
}
return applyMiddleware(store)
}

创建thunk插件

基本原理:

  • 根据redux的概念,dispatch的时候,是传入一个action,那么它没法支持异步
  • 我们让dispatch支持传入一个方法,在方法内部再去dispatch一个action,这样就实现了支持异步
const thunk = store => dispatch => action => {
if (typeof action === 'function') {
action(store.getState, dispatch)
}
return dispatch(action)
}

测试代码

const initCounterState = {
value: 0,
name: 'counter reducer'
}

const initTodoState = {
value: 0,
name: 'todo reducer'
}

const counterReducer = (state = initCounterState, action) => {
switch (action.type) {
case 'COUNTER/INCREMENT':
return {
...state,
value: state.value + (action.payload || 1)
}
case 'COUNTER/DECREMENT':
return {
...state,
value: state.value - (action.payload || 1)
}
default:
return {
...state
}
}
}

const todoReducer = (state = initTodoState, action) => {
switch (action.type) {
case 'TODO/INCREMENT':
return {
...state,
value: state.value + (action.payload || 1)
}
case 'TODO/DECREMENT':
return {
...state,
value: state.value - (action.payload || 1)
}
default:
return {
...state
}
}
}

const reducer = combineReducers({
counterReducer,
todoReducer,
})

const store = createStore(reducer, applyMiddleware(thunk))

store.subscribe(() => {
const state = store.getState()
})

store.dispatch({
type: 'TODO/INCREMENT',
payload: 10
})

store.dispatch({
type: 'COUNTER/INCREMENT',
payload: 5
})

store.dispatch({
type: 'TODO/DECREMENT',
payload: 2
})

// 测试异步操作案例一
store.dispatch(() => {
console.log('dispatching')
setTimeout(() => {
console.log('got new data')
const value = 100
store.dispatch({
type: 'TODO/INCREMENT',
payload: value
})
}, 2000)
})

// 给异步操作一个正当的名字
const addCounterByValue = (params) => {
return (getState, dispatch) => {
console.log(params, getState())
setTimeout(() => {
const value = 2000
dispatch({
type: 'COUNTER/INCREMENT',
payload: value
})
}, 3000)
}
}

store.dispatch(addCounterByValue('params'))