JavaScript

[JavaScript] 拆分Redux

2016-08-22  本文已影响111人  何幻

Redux是用来管理程序状态的工具,它提供了一些高阶函数让功能越来越丰富。

1. 用reducer根据action对state进行变换:
reducer(state,action)

// type Action = {Type, Value}
// type ActionCreator = Value -> Action
// actionCreator :: ActionCreator
const actionCreator = v => ({
    type: 'ADD1',
    v
})

// type Reducer = (State, Action) -> State
// reducer :: Reducer
const reducer = (state, action) => {
    switch (action.type) {
        case 'ADD1':
            return state + 1

        default:
            return state
    }
}

// testcase
const initialState = 1
const action = actionCreator(initialState)
const state = reducer(initialState, action)
console.assert(state === 2)

2. 用store保存state,store处理action之后改变状态:
store.dispatch(action)

// type Action = {Type, Value}
// type ActionCreator = Value -> Action
// actionCreator :: ActionCreator
const actionCreator = v => ({
    type: 'ADD1',
    v
})

// type Reducer = (State, Action) -> State
// reducer :: Reducer
const reducer = (state, action) => {
    switch (action.type) {
        case 'ADD1':
            return state + 1

        default:
            return state
    }
}

// type Listener = (State, Action) -> ()
// type GetState = () -> State
// type Subscribe = Listener -> ()
// type Dispatch = Action -> ()
// type Store = {GetState, Subscribe, Dispatch}
// type CreateStore = (Reducer, State) -> Store
// createStore :: CreateStore
const createStore = (reducer, initialState) => {
    let state = initialState,
        listenerList = []

    return {
        getState: () => state,
        subscribe: listener => {
            listenerList.push(listener)
        },
        dispatch: action => {
            listenerList.forEach(listener => listener(state, action))
            state = reducer(state, action)
        }
    }
}

// testcase
const initialState = 1
const store = createStore(reducer, initialState)
console.assert(store.getState() === 1)

const action = actionCreator(initialState)
const listener = (state, action) => {
    console.assert(state === 1)
    console.assert(action.type === 'ADD1')
}
store.subscribe(listener)
store.dispatch(action)
console.assert(store.getState() === 2)

3. 用bindActionCreator得到可根据当前state直接修改store的sideEffectAction:
sideEffectAction(initialState)

// type Action = {Type, Value}
// type ActionCreator = Value -> Action
// actionCreator :: ActionCreator
const actionCreator = v => ({
    type: 'ADD1',
    v
})

// type Reducer = (State, Action) -> State
// reducer :: Reducer
const reducer = (state, action) => {
    switch (action.type) {
        case 'ADD1':
            return state + 1

        default:
            return state
    }
}

// type Listener = (State, Action) -> ()
// type GetState = () -> State
// type Subscribe = Listener -> ()
// type Dispatch = Action -> ()
// type Store = {GetState, Subscribe, Dispatch}
// type CreateStore = (Reducer, State) -> Store
// createStore :: CreateStore
const createStore = (reducer, initialState) => {
    let state = initialState,
        listenerList = []

    return {
        getState: () => state,
        subscribe: listener => {
            listenerList.push(listener)
        },
        dispatch: action => {
            listenerList.forEach(listener => listener(state, action))
            state = reducer(state, action)
        }
    }
}

// bindActionCreator :: (ActionCreator, Dispatch) -> State -> ()
const bindActionCreator = (actionCreator, dispatch) => initialState => dispatch(actionCreator(initialState))

// testcase
const initialState = 1
const store = createStore(reducer, initialState)
const sideEffectAction = bindActionCreator(actionCreator, store.dispatch)
sideEffectAction(initialState)
console.assert(store.getState() === 2)

4. 用applyMiddleware加强createStore,提高store处理action的能力:
storeWithMiddleware.dispatch(action)

// type Action = {Type, Value}
// type ActionCreator = Value -> Action
// actionCreator :: ActionCreator
const actionCreator = v => ({
    type: 'ADD1',
    v
})

// type Reducer = (State, Action) -> State
// reducer :: Reducer
const reducer = (state, action) => {
    switch (action.type) {
        case 'ADD1':
            return state + 1

        default:
            return state
    }
}

// type Listener = (State, Action) -> ()
// type GetState = () -> State
// type Subscribe = Listener -> ()
// type Dispatch = Action -> ()
// type Store = {GetState, Subscribe, Dispatch}
// type CreateStore = (Reducer, State) -> Store
// createStore :: CreateStore
const createStore = (reducer, initialState) => {
    let state = initialState,
        listenerList = []

    return {
        getState: () => state,
        subscribe: listener => {
            listenerList.push(listener)
        },
        dispatch: action => {
            listenerList.forEach(listener => listener(state, action))
            state = reducer(state, action)
        }
    }
}

// compose :: [t -> t] -> (t -> t)
const compose = (...fns) => {
    let last = fns.pop()
    return (...args) => fns.reduceRight((memo, fn) => fn(memo), last(...args))
}

// type Next = Dispatch
// type Middleware = {GetState, Dispatch} -> Next -> Dispatch
// middleware :: Middleware
const middleware = ({ getState, dispatch }) => next => action => {

    // for example: 
    return next(action)
}

// applyMiddleware :: [Middleware] -> CreateStore -> CreateStore
const applyMiddleware = (...middlewares) => createStore => (reducer, initialState) => {
    let store = createStore(reducer, initialState),
        dispatch = store.dispatch,

        // chain :: [Next -> Dispatch]
        chain = middlewares.map(middleware => middleware({
            getState: store.getState,
            dispatch: action => dispatch(action)
        }))

    dispatch = compose(...chain)(dispatch)

    return {
        getState: store.getState,
        subscribe: store.subscribe,
        dispatch
    }
}

// testcase
const initialState = 1
const createStoreWithMiddleware = applyMiddleware(middleware)(createStore)
const store = createStoreWithMiddleware(reducer, initialState)
const action = actionCreator(initialState)
const listener = (state, action) => {
    console.assert(state === 1)
    console.assert(action.type === 'ADD1')
}
store.subscribe(listener)
store.dispatch(action)
console.assert(store.getState() === 2)

参考
GitHub: reactjs/redux
深入到源码:解读 redux 的设计思路与用法

上一篇 下一篇

猜你喜欢

热点阅读