使用Hook寫Redux

藤蔓繞竹發表於2019-07-29

import * as React from 'react'
const { useContext, useReducer, createContext } = React
//一定要返回狀態
function reducerInAction(state, action) {
    if (typeof action.reducer == 'function') {
        return action.reducer(state)
    }
    return state
}
//公用的資料處理
export default function createStore(params) {
    const { initialState = {}, reducer
    } = {
        ...params,
        reducer: reducerInAction
    }
    //實際是由createContext所有狀態版本的管理
    const Appcontext = createContext()
    const middleWareReducer = (lastState, action) => {
        //更新資料
        let netxState = reducer(lastState, action)
        store._state = netxState
        return netxState
    }
    const store = {
        _state: initialState,
        dispatch: undefined,
        getState: () => {
            return store._state
        },
        useContext: () => {
            return useContext(Appcontext)
        }
    }
    //資料包裹返回
    const Provider = props => {
        const [state, dispatch] = useReducer(middleWareReducer, initialState)
        if (!store.dispatch) {
            store.dispatch = async (action) => {
                if (typeof action === 'function') {
                    await action(dispatch, store.getState())
                } else {
                    dispatch(action)
                }

            }
        }
        return <Appcontext.Provider {...props} value={state} />
    }

    return {
        Provider,
        store
    }
}


複製程式碼

引用案例

import * as React from 'react'
import HooksRedux from './HooksRedux'
const {
    Provider,
    store
} = HooksRedux({
    initialState: { name: '微微', age: 0 }
})
const Home = () => {
    const state = store.useContext()
    return (
        < div >
            Home元件Age: {state.age}
            <br />
            <Button />
        </div >
    )
}
//同步請求
const actionOfAdd = () => {
    return {
        type: 'addCount',
        reducer(state) {
            return {
                ...state,
                age: state.age + 1
            }
        }
    }
}
function timeOutAdd(a) {
    return new Promise(cb => setTimeout(() => cb(a - 1), 500))
}
//非同步請求
const actionAsyncOfDelete = () => async (dispatch, ownState) => {
    const age = await timeOutAdd(ownState.age)
    dispatch({
        type: 'addCount',
        reducer(state) {
            return {
                ...state,
                age
            }
        }
    })
}
//出發請求
const Button = () => {
    function handleAdd() {
        //返回給dispatch的是一個物件        store.dispatch(actionOfAdd())
    }
    function handleAsyncDelete() {
        //返回給dispatch的是一個物件        store.dispatch(actionAsyncOfDelete())
    }
    return <>
        <button onClick={handleAdd} >點選增加</button>
        <button onClick={handleAsyncDelete} >點選非同步減少</button>
    </>
}
const WarpHome = () => {

    return (
        <Provider>
            <Home />
        </Provider>
    )
}
export default WarpHome


複製程式碼


相關文章