From 08de976469fa5d942879bfbc1ccdd8b1e55a019d Mon Sep 17 00:00:00 2001 From: MrWangJustToDo <2711470541@qq.com> Date: Wed, 22 Nov 2023 15:43:49 +0800 Subject: [PATCH] fix asyncAction for devTools --- .../createStateWithActionsMiddleware.vue | 2 +- packages/r-store/package.json | 2 +- packages/r-store/src/shared/dev.ts | 48 +++++++++++++++---- packages/r-store/src/state/_internal.ts | 4 +- 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/app/.vitepress/theme/components/createStateWithActionsMiddleware.vue b/app/.vitepress/theme/components/createStateWithActionsMiddleware.vue index 88e444a..1d61315 100644 --- a/app/.vitepress/theme/components/createStateWithActionsMiddleware.vue +++ b/app/.vitepress/theme/components/createStateWithActionsMiddleware.vue @@ -11,7 +11,7 @@ const useCountState_v2 = createState(withActions(() => ({ count: 1 }), { generat const useCountState_v3 = createState(withActions(() => ({ count: 1 }), { generateActions: (state) => { return { add: (v) => { console.log(v); state.count++ }, del: () => state.count-- } } })); -const useCountState_v4 = createState(withNamespace(() => ({ count: 1 }), { namespace: 'foo_2', reduxDevTool: true }), { withActions: (state) => { return { add: (v) => { console.log(v); state.count++ }, del: () => state.count-- } }, withNamespace: 'count_4' }); +const useCountState_v4 = createState(withNamespace(() => ({ count: 1 }), { namespace: 'foo_2', reduxDevTool: true }), { withActions: (state) => { return { add: async (v) => { console.log(v); state.count++ }, del: async () => state.count-- } }, withNamespace: 'count_4' }); const App = () => { const { count, add } = useCountState_v4(); diff --git a/packages/r-store/package.json b/packages/r-store/package.json index 6c1dbc2..8355809 100644 --- a/packages/r-store/package.json +++ b/packages/r-store/package.json @@ -1,6 +1,6 @@ { "name": "reactivity-store", - "version": "0.2.7", + "version": "0.2.8", "author": "MrWangJustToDo", "license": "MIT", "description": "a reactive store, make you write reactive logic in react app just like zustand", diff --git a/packages/r-store/src/shared/dev.ts b/packages/r-store/src/shared/dev.ts index 61381f4..33d1b0c 100644 --- a/packages/r-store/src/shared/dev.ts +++ b/packages/r-store/src/shared/dev.ts @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/ban-types */ +import { isPromise } from "@vue/shared"; + import { isServer } from "./env"; import type { Controller } from "./controller"; @@ -73,8 +75,19 @@ const devToolMap: Record = {}; const globalName = "__reactivity-store-redux-devtools__"; +const defaultAction = { type: "unknown", getUpdatedState: () => null }; + +const pendingAction = new Set(); + +let globalAction: { type: string; $payload?: any; getUpdatedState: () => any } = defaultAction; + let globalDevTools = null; +/** + * @internal + */ +export const getDevToolInstance = () => globalDevTools || window.__REDUX_DEVTOOLS_EXTENSION__.connect({ name: globalName }); + /** * @internal */ @@ -96,21 +109,24 @@ export const connectDevTool = (name: string, actions: Record, devTools.init(obj); - const action = { type: `action/change-${name}` }; + const action = { type: name }; return Object.keys(actions).reduce((p, c) => { p[c] = (...args) => { - const re = actions[c](...args); - try { - const len = actions[c].length || 0; + const len = actions[c].length || 0; - const nextObj = { ...devToolMap, [name]: JSON.parse(JSON.stringify(state)) }; + globalAction = { ...action, $payload: args.slice(0, len), getUpdatedState: () => ({ ...devToolMap, [name]: JSON.parse(JSON.stringify(state)) }) }; - devTools.send({ ...action, $payload: args.slice(0, len) }, nextObj); - } catch (e) { - console.log(e); + const re = actions[c](...args); - void 0; + if (isPromise(re)) { + re.finally(() => { + sendToDevTools(true); + globalAction = defaultAction; + }); + } else { + sendToDevTools(false); + globalAction = defaultAction; } return re; }; @@ -120,3 +136,17 @@ export const connectDevTool = (name: string, actions: Record, return actions; } }; + +/** + * @internal + */ +export const sendToDevTools = (asyncAction: boolean) => { + const { getUpdatedState, type, ...action } = globalAction; + try { + getDevToolInstance().send({ ...action, type: asyncAction ? `asyncAction/change-${type}` : `syncAction/change-${type}` }, getUpdatedState()); + } catch (e) { + console.log(e); + } finally { + pendingAction.delete(globalAction); + } +}; diff --git a/packages/r-store/src/state/_internal.ts b/packages/r-store/src/state/_internal.ts index 320b8a0..7b620ea 100644 --- a/packages/r-store/src/state/_internal.ts +++ b/packages/r-store/src/state/_internal.ts @@ -53,6 +53,8 @@ export function internalCreateState, P extends const rawState = toRaw(initialState); + const reduxDevTool = __DEV__ && namespace.reduxDevTool && !isServer; + if (__DEV__ && checkHasReactive(rawState)) { console.error( `[reactivity-store] '${name}' expect receive a plain object but got a reactive object/field %o, this is a unexpected usage. should not use 'reactiveApi' in this 'setup' function`, @@ -74,7 +76,7 @@ export function internalCreateState, P extends ); } - if (__DEV__ && namespace.reduxDevTool && !isServer) { + if (reduxDevTool) { actions = connectDevTool(namespace.namespace, actions, rawState) as P; }