Skip to content

Commit c25cd11

Browse files
fix(stateupdater): fix the issue that setState on unmounted component (#153)
1 parent f745d03 commit c25cd11

File tree

5 files changed

+41
-22
lines changed

5 files changed

+41
-22
lines changed

__test__/depActions.spec.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ describe('', () => {
1818
expect(stateFirst.count).toBe(0)
1919
expect(stateSecond.count).toBe(0)
2020
await actionsFirst.increment(3)
21-
expect(stateFirst.count).toBe(3)
21+
expect(stateFirst.count).toBe(0)
2222
expect(stateSecond.count).toBe(3)
2323
await actionsSecond.increment(4)
24-
expect(stateFirst.count).toBe(3)
24+
expect(stateFirst.count).toBe(0)
2525
expect(stateSecond.count).toBe(7)
2626
await actions.increment(4)
27-
expect(stateFirst.count).toBe(3)
27+
expect(stateFirst.count).toBe(0)
2828
expect(stateSecond.count).toBe(11)
29+
await actions.add(1)
30+
expect(stateFirst.count).toBe(12)
31+
expect(stateSecond.count).toBe(12)
2932
})
3033
})

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-model",
3-
"version": "3.1.0",
3+
"version": "3.1.1",
44
"description": "The State management library for React",
55
"main": "./dist/react-model.js",
66
"umd:main": "./dist/react-model.umd.js",
@@ -38,6 +38,7 @@
3838
"cz-conventional-changelog": "^3.0.0",
3939
"husky": "^4.0.2",
4040
"jest": "^24.1.0",
41+
"microbundle": "^0.11.0",
4142
"prettier": "^2.0.0",
4243
"react": "^16.8.4",
4344
"react-dom": "^16.8.4",

src/index.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ interface BaseContext<S = {}> {
8484
interface InnerContext<S = {}> extends BaseContext<S> {
8585
// Actions with function type context will always invoke current component's reload.
8686
type?: 'function' | 'outer' | 'class'
87-
setState?: Dispatch<SetStateAction<S>>
87+
__hash?: string
8888
}
8989

90-
type Context<S = {}> = (InnerContext<S>) & {
90+
type Context<S = {}> = InnerContext<S> & {
9191
next: Function
9292
modelMiddlewares?: Middleware[]
9393
}

src/index.tsx

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// <reference path="./index.d.ts" />
22
import * as React from 'react'
3-
import { PureComponent, useEffect, useState } from 'react'
3+
import { PureComponent, useEffect, useState, useRef } from 'react'
44
import Global from './global'
55
import {
66
Consumer,
@@ -51,12 +51,12 @@ function Model<M extends Models, MT extends ModelType, E>(
5151
subscribe: (
5252
actionName: keyof MT['actions'] | Array<keyof MT['actions']>,
5353
callback: () => void
54-
) => subscribe(hash, actionName as (string | string[]), callback),
54+
) => subscribe(hash, actionName as string | string[], callback),
5555
unsubscribe: (
5656
actionName: keyof MT['actions'] | Array<keyof MT['actions']>
57-
) => unsubscribe(hash, actionName as (string | string[])),
57+
) => unsubscribe(hash, actionName as string | string[]),
5858
useStore: (depActions?: Array<keyof MT['actions']>) =>
59-
useStore(hash, depActions as (string[] | undefined))
59+
useStore(hash, depActions as string[] | undefined)
6060
}
6161
} else {
6262
if (models.actions) {
@@ -151,7 +151,7 @@ const subscribe = (
151151
callback?: () => void
152152
) => {
153153
if (Array.isArray(actions)) {
154-
actions.forEach(actionName => {
154+
actions.forEach((actionName) => {
155155
if (!Global.subscriptions[`${modelName}_${actionName}`]) {
156156
Global.subscriptions[`${modelName}_${actionName}`] = []
157157
}
@@ -207,21 +207,29 @@ const getActions = (
207207
}
208208

209209
const useStore = (modelName: string, depActions?: string[]) => {
210-
const setState = useState(Global.State[modelName])[1]
210+
const setState = useState({})[1]
211+
const hash = useRef<string>('')
211212

212213
useEffect(() => {
213214
Global.uid += 1
214-
const hash = '' + Global.uid
215+
const local_hash = '' + Global.uid
216+
hash.current = local_hash
215217
if (!Global.Setter.functionSetter[modelName]) {
216218
Global.Setter.functionSetter[modelName] = {}
217219
}
218-
Global.Setter.functionSetter[modelName][hash] = { setState, depActions }
220+
Global.Setter.functionSetter[modelName][local_hash] = {
221+
setState,
222+
depActions
223+
}
219224
return function cleanup() {
220-
delete Global.Setter.functionSetter[modelName][hash]
225+
delete Global.Setter.functionSetter[modelName][local_hash]
221226
}
222227
}, [])
223228

224-
const updaters = getActions(modelName, { setState, type: 'function' })
229+
const updaters = getActions(modelName, {
230+
__hash: hash.current,
231+
type: 'function'
232+
})
225233
return [getState(modelName), updaters]
226234
}
227235

@@ -249,7 +257,7 @@ const connect = (
249257
const { state: prevState = {}, actions: prevActions = {} } = this.props
250258
return (
251259
<Consumer>
252-
{models => {
260+
{(models) => {
253261
const { [`${modelName}`]: state } = models as any
254262
const actions = Global.Actions[modelName]
255263
return (

src/middlewares.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,16 @@ const setNewState: Middleware = async (context, restMiddlewares) => {
5151
}
5252

5353
const stateUpdater: Middleware = async (context, restMiddlewares) => {
54-
const { modelName, next, Global } = context
55-
if (context.type === 'function' && context.setState) {
56-
context.setState(Global.State[modelName])
54+
const { modelName, next, Global, __hash } = context
55+
const setter = Global.Setter.functionSetter[modelName]
56+
if (
57+
context.type === 'function' &&
58+
__hash &&
59+
setter &&
60+
setter[__hash] &&
61+
setter[__hash].setState
62+
) {
63+
setter[__hash].setState(Global.State[modelName])
5764
}
5865
await next(restMiddlewares)
5966
}
@@ -62,7 +69,7 @@ const subscription: Middleware = async (context, restMiddlewares) => {
6269
const { modelName, actionName, next, Global } = context
6370
const subscriptions = Global.subscriptions[`${modelName}_${actionName}`]
6471
if (subscriptions) {
65-
subscriptions.forEach(callback => {
72+
subscriptions.forEach((callback) => {
6673
callback()
6774
})
6875
}
@@ -115,7 +122,7 @@ const communicator: Middleware = async (context, restMiddlewares) => {
115122
Global.Setter.classSetter(Global.State)
116123
}
117124
if (Global.Setter.functionSetter[modelName]) {
118-
Object.keys(Global.Setter.functionSetter[modelName]).map(key => {
125+
Object.keys(Global.Setter.functionSetter[modelName]).map((key) => {
119126
const setter = Global.Setter.functionSetter[modelName][key]
120127
if (setter) {
121128
if (

0 commit comments

Comments
 (0)