React 实现简单的 redux [dispatch]
创建Store.js 文件
import React, {
createContext,
useCallback,
useReducer,
useContext
} from "react"
// dispatch 命名空间Map
const Dispatch = new Map()
function useStore({ reducers, namespace, effects, state }) {
const run = () => {
const dispatchFn = useCallback(async ({ type, payload }) => {
const fn = effects[type]
if (fn) {
try {
put({
type: "setLoading",
payload: {
[type]: true
}
})
await fn(payload, put)
} finally {
put({
type: "setLoading",
payload: {
[type]: false
}
})
}
} else {
put({
type,
payload
})
}
}, [])
const dispatch = useCallback(
({ type, payload }) => {
if (type.split("/").length) {
const [ns, part] = type.split("/")
const nsDis = Dispatch.get(ns)
if (nsDis) {
const newType = { type: part, ...payload }
nsDis.dispatch(newType)
} else {
dispatchFn({ type, payload })
}
}
},
[dispatchFn]
)
Dispatch.set(namespace, dispatch)
const reducerFn = useCallback((state, action) => {
const { type, payload } = action
if (type === "setLoading") {
return {
...state,
loading: { ...(state.loading || {}), ...payload }
}
} else {
const data = reducers[type](state, payload)
return data
}
}, [])
const [store, put] = useReducer(reducerFn, state)
return [store, dispatch]
}
return run
}
const createStore = () => {
const context = createContext()
const useConnect = mapfn => {
const [val, dispatch] = useContext(context)
return [mapfn ? mapfn(val) : val, dispatch]
}
return [context, useConnect]
}
export { createStore, useStore }
定义一个model.js
import { useStore, createStore } from "./store";
const Model = {
namespace: "count",
state: {
num: 0
},
effects: {
async fetchNum(state, put) {
await new Promise(resolve => {
setTimeout(resolve, 1000);
});
const data = await fetch("/a.json").then(res => res.json());
put({
type: "add",
payload: data.num
});
}
},
reducers: {
add(state, payload) {
return {
num: state.num + payload
};
},
decrement(state, payload) {
return {
...state,
num: state.num - payload
};
}
}
};
const CountStore = useStore(Model);
const Ctx = createStore();
export { CountStore, Ctx };
Demo
import { CountStore, Ctx } from "./model";
import {
memo,
useState,
} from "react";
export default () => {
const [Context] = Ctx;
const store = CountStore();
console.log("context");
return (
<Context.Provider value={store}>
<Counnt></Counnt>
</Context.Provider>
);
};
const Counnt = memo(() => {
const [, useConnect] = Ctx;
const [state, dispatch] = useConnect();
console.log(state);
return (
<>
<Button className='Groupe'></Button>
<Button onClick={() => dispatch({ type: "add", payload: 10 })}>
add
</Button>
<Button onClick={() => dispatch({ type: "decrement", payload: 5 })}>
decrement
</Button>
<Button
loading={(state.loading && state.loading["fetchNum"]) || false}
onClick={() => dispatch({ type: "fetchNum" })}>
fetchNum
</Button>
count is {state.num}
</>
);
});
演示
