From 262971da427c60435a0b88bfcd2783169595fd38 Mon Sep 17 00:00:00 2001 From: ArrayZoneYour Date: Wed, 1 Apr 2020 16:26:33 +0800 Subject: [PATCH] fix(stateupdater): fix the issue that setState on unmounted component --- __test__/depActions.spec.ts | 9 ++++++--- package.json | 3 ++- src/index.d.ts | 4 ++-- src/index.tsx | 30 +++++++++++++++++++----------- src/middlewares.ts | 17 ++++++++++++----- 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/__test__/depActions.spec.ts b/__test__/depActions.spec.ts index 0dff1d5..442d568 100644 --- a/__test__/depActions.spec.ts +++ b/__test__/depActions.spec.ts @@ -18,13 +18,16 @@ describe('', () => { expect(stateFirst.count).toBe(0) expect(stateSecond.count).toBe(0) await actionsFirst.increment(3) - expect(stateFirst.count).toBe(3) + expect(stateFirst.count).toBe(0) expect(stateSecond.count).toBe(3) await actionsSecond.increment(4) - expect(stateFirst.count).toBe(3) + expect(stateFirst.count).toBe(0) expect(stateSecond.count).toBe(7) await actions.increment(4) - expect(stateFirst.count).toBe(3) + expect(stateFirst.count).toBe(0) expect(stateSecond.count).toBe(11) + await actions.add(1) + expect(stateFirst.count).toBe(12) + expect(stateSecond.count).toBe(12) }) }) diff --git a/package.json b/package.json index 761b44a..d74ddd3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-model", - "version": "3.1.0", + "version": "3.1.1", "description": "The State management library for React", "main": "./dist/react-model.js", "umd:main": "./dist/react-model.umd.js", @@ -38,6 +38,7 @@ "cz-conventional-changelog": "^3.0.0", "husky": "^4.0.2", "jest": "^24.1.0", + "microbundle": "^0.11.0", "prettier": "^2.0.0", "react": "^16.8.4", "react-dom": "^16.8.4", diff --git a/src/index.d.ts b/src/index.d.ts index 87f4417..c0aa446 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -84,10 +84,10 @@ interface BaseContext { interface InnerContext extends BaseContext { // Actions with function type context will always invoke current component's reload. type?: 'function' | 'outer' | 'class' - setState?: Dispatch> + __hash?: string } -type Context = (InnerContext) & { +type Context = InnerContext & { next: Function modelMiddlewares?: Middleware[] } diff --git a/src/index.tsx b/src/index.tsx index 4bb85d7..3a0629c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,6 +1,6 @@ /// import * as React from 'react' -import { PureComponent, useEffect, useState } from 'react' +import { PureComponent, useEffect, useState, useRef } from 'react' import Global from './global' import { Consumer, @@ -51,12 +51,12 @@ function Model( subscribe: ( actionName: keyof MT['actions'] | Array, callback: () => void - ) => subscribe(hash, actionName as (string | string[]), callback), + ) => subscribe(hash, actionName as string | string[], callback), unsubscribe: ( actionName: keyof MT['actions'] | Array - ) => unsubscribe(hash, actionName as (string | string[])), + ) => unsubscribe(hash, actionName as string | string[]), useStore: (depActions?: Array) => - useStore(hash, depActions as (string[] | undefined)) + useStore(hash, depActions as string[] | undefined) } } else { if (models.actions) { @@ -151,7 +151,7 @@ const subscribe = ( callback?: () => void ) => { if (Array.isArray(actions)) { - actions.forEach(actionName => { + actions.forEach((actionName) => { if (!Global.subscriptions[`${modelName}_${actionName}`]) { Global.subscriptions[`${modelName}_${actionName}`] = [] } @@ -207,21 +207,29 @@ const getActions = ( } const useStore = (modelName: string, depActions?: string[]) => { - const setState = useState(Global.State[modelName])[1] + const setState = useState({})[1] + const hash = useRef('') useEffect(() => { Global.uid += 1 - const hash = '' + Global.uid + const local_hash = '' + Global.uid + hash.current = local_hash if (!Global.Setter.functionSetter[modelName]) { Global.Setter.functionSetter[modelName] = {} } - Global.Setter.functionSetter[modelName][hash] = { setState, depActions } + Global.Setter.functionSetter[modelName][local_hash] = { + setState, + depActions + } return function cleanup() { - delete Global.Setter.functionSetter[modelName][hash] + delete Global.Setter.functionSetter[modelName][local_hash] } }, []) - const updaters = getActions(modelName, { setState, type: 'function' }) + const updaters = getActions(modelName, { + __hash: hash.current, + type: 'function' + }) return [getState(modelName), updaters] } @@ -249,7 +257,7 @@ const connect = ( const { state: prevState = {}, actions: prevActions = {} } = this.props return ( - {models => { + {(models) => { const { [`${modelName}`]: state } = models as any const actions = Global.Actions[modelName] return ( diff --git a/src/middlewares.ts b/src/middlewares.ts index 4d44779..b3341db 100644 --- a/src/middlewares.ts +++ b/src/middlewares.ts @@ -51,9 +51,16 @@ const setNewState: Middleware = async (context, restMiddlewares) => { } const stateUpdater: Middleware = async (context, restMiddlewares) => { - const { modelName, next, Global } = context - if (context.type === 'function' && context.setState) { - context.setState(Global.State[modelName]) + const { modelName, next, Global, __hash } = context + const setter = Global.Setter.functionSetter[modelName] + if ( + context.type === 'function' && + __hash && + setter && + setter[__hash] && + setter[__hash].setState + ) { + setter[__hash].setState(Global.State[modelName]) } await next(restMiddlewares) } @@ -62,7 +69,7 @@ const subscription: Middleware = async (context, restMiddlewares) => { const { modelName, actionName, next, Global } = context const subscriptions = Global.subscriptions[`${modelName}_${actionName}`] if (subscriptions) { - subscriptions.forEach(callback => { + subscriptions.forEach((callback) => { callback() }) } @@ -115,7 +122,7 @@ const communicator: Middleware = async (context, restMiddlewares) => { Global.Setter.classSetter(Global.State) } if (Global.Setter.functionSetter[modelName]) { - Object.keys(Global.Setter.functionSetter[modelName]).map(key => { + Object.keys(Global.Setter.functionSetter[modelName]).map((key) => { const setter = Global.Setter.functionSetter[modelName][key] if (setter) { if (