Skip to content

Commit 5621226

Browse files
committed
feat(model): create models repeatedly will not override existing models
1 parent b22c2d4 commit 5621226

File tree

5 files changed

+101
-17
lines changed

5 files changed

+101
-17
lines changed

__test__/Model/same-name.spec.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/// <reference path="../index.d.ts" />
2+
import { renderHook } from '@testing-library/react-hooks'
3+
import { NextCounter } from '..'
4+
import { Model } from '../../src'
5+
6+
describe('useStore', () => {
7+
test('create by single model definition', async () => {
8+
let state: any
9+
let actions: any
10+
let mirrorState: any
11+
let mirrorActions: any
12+
let count = 0
13+
const { useStore, subscribe, unsubscribe, getState } = Model({
14+
NextCounter
15+
})
16+
const {
17+
useStore: useMirrorStore,
18+
subscribe: mirrorSubscribe,
19+
unsubscribe: mirrorUnSubscribe,
20+
getState: getMirrorState
21+
} = Model({ NextCounter })
22+
renderHook(() => {
23+
;[state, actions] = useStore('NextCounter')
24+
;[mirrorState, mirrorActions] = useMirrorStore('NextCounter')
25+
})
26+
expect(state).toEqual({ count: 0 })
27+
expect(mirrorState).toEqual({ count: 0 })
28+
29+
mirrorSubscribe('NextCounter', 'increment', () => (count += 1))
30+
31+
await actions.increment(3)
32+
expect(state).toEqual({ count: 3 })
33+
expect(mirrorState).toEqual({ count: 0 })
34+
expect(count).toBe(0)
35+
36+
await mirrorActions.increment(3)
37+
expect(state).toEqual({ count: 3 })
38+
expect(mirrorState).toEqual({ count: 3 })
39+
expect(count).toBe(1)
40+
41+
// test subscribe
42+
subscribe('NextCounter', 'increment', () => (count += 1))
43+
await actions.increment(4)
44+
expect(count).toBe(2)
45+
expect(state.count).toBe(7)
46+
expect(mirrorState.count).toBe(3)
47+
expect(getState('NextCounter').count).toBe(7)
48+
expect(getMirrorState('NextCounter').count).toBe(3)
49+
50+
// test unsubscribe
51+
unsubscribe('NextCounter', 'increment')
52+
mirrorUnSubscribe('NextCounter', 'increment')
53+
await actions.increment(3)
54+
expect(state.count).toBe(10)
55+
expect(mirrorState.count).toBe(3)
56+
expect(getState('NextCounter').count).toBe(10)
57+
expect(getMirrorState('NextCounter').count).toBe(3)
58+
expect(count).toBe(2)
59+
})
60+
})

src/global.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ let withDevTools = false
2525
let uid = 0 // The unique id of hooks
2626
let storeId = 0 // The unique id of stores
2727
let currentStoreId = '0' // Used for useModel
28+
let gid = 0 // The unique id of models' group
2829

2930
export default {
3031
Actions,
@@ -36,6 +37,7 @@ export default {
3637
devTools,
3738
subscriptions,
3839
mutableState,
40+
gid,
3941
uid,
4042
storeId,
4143
currentStoreId,

src/helper.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,19 @@ const timeout = <T>(ms: number, data: T): Promise<T> =>
8484
}, ms)
8585
)
8686

87-
const getInitialState = async <T extends { modelName: string }>(
87+
const getInitialState = async <T extends { modelName: string | string[] }>(
8888
context?: T,
89-
config?: { isServer?: boolean }
89+
config?: { isServer?: boolean; prefix?: string }
9090
) => {
9191
const ServerState: { [name: string]: any } = { __FROM_SERVER__: true }
9292
await Promise.all(
9393
Object.keys(Global.State).map(async (modelName) => {
94+
let prefix = config?.prefix || ''
9495
if (
9596
!context ||
9697
!context.modelName ||
97-
modelName === context.modelName ||
98-
context.modelName.indexOf(modelName) !== -1
98+
modelName === prefix + context.modelName ||
99+
context.modelName.indexOf(prefix + modelName) !== -1
99100
) {
100101
const asyncGetter = Global.AsyncState[modelName]
101102
const asyncState = asyncGetter ? await asyncGetter(context) : {}

src/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ interface Global {
4242
Setter: Setter
4343
devTools: any
4444
withDevTools: boolean
45+
gid: number
4546
uid: number
4647
storeId: number
4748
currentStoreId: string

src/index.tsx

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,16 @@ function Model<M extends Models, MT extends ModelType, E>(
173173
useStore: (selector?: Function) => useStore(hash, selector)
174174
}
175175
} else {
176+
if (initialState) {
177+
// TODO: support multi model group under SSR
178+
Global.gid = 1
179+
} else {
180+
Global.gid += 1
181+
}
182+
let prefix = ''
183+
if (Global.gid > 1) {
184+
prefix = Global.gid + '_'
185+
}
176186
if (models.actions) {
177187
console.error('invalid model(s) schema: ', models)
178188
const errorFn = (fakeReturnVal?: unknown) => (..._: unknown[]) => {
@@ -196,8 +206,10 @@ function Model<M extends Models, MT extends ModelType, E>(
196206
})
197207
}
198208
extContext && (Global.Context['__global'] = extContext)
199-
Object.keys(models).forEach((name) => {
200-
const model = models[name]
209+
let actions: { [name: string]: any } = {}
210+
Object.keys(models).forEach((n) => {
211+
let name = prefix + n
212+
const model = models[n]
201213
if (model.__ERROR__) {
202214
// Fallback State and Actions when model schema is invalid
203215
console.error(name + " model's schema is invalid")
@@ -239,12 +251,9 @@ function Model<M extends Models, MT extends ModelType, E>(
239251
Global.Middlewares[name] = Global.Middlewares[model.__id]
240252
Global.Context[name] = Global.Context[model.__id]
241253
}
242-
})
243254

244-
const actions = Object.keys(models).reduce(
245-
(o, modelName) => ({ ...o, [modelName]: getActions(modelName) }),
246-
{}
247-
)
255+
actions[n] = getActions(name)
256+
})
248257

249258
Global.withDevTools =
250259
typeof window !== 'undefined' &&
@@ -255,12 +264,23 @@ function Model<M extends Models, MT extends ModelType, E>(
255264
}
256265
return {
257266
actions,
258-
getActions,
259-
getInitialState,
260-
getState,
261-
subscribe,
262-
unsubscribe,
263-
useStore
267+
getActions: (name: string) => getActions(prefix + name),
268+
getInitialState: async <T extends { modelName: string | string[] }>(
269+
context?: T,
270+
config?: { isServer?: boolean }
271+
) => getInitialState(context, { ...config, prefix }),
272+
getState: (name: string) => getState(prefix + name),
273+
subscribe: (
274+
name: string,
275+
actions: keyof MT['actions'] | Array<keyof MT['actions']>,
276+
callback: () => void
277+
) => subscribe(prefix + name, actions as string | string[], callback),
278+
unsubscribe: (
279+
name: string,
280+
actionName: keyof MT['actions'] | Array<keyof MT['actions']>
281+
) => unsubscribe(prefix + name, actionName as string | string[]),
282+
useStore: (name: string, selector?: Function) =>
283+
useStore(prefix + name, selector)
264284
} as APIs<M>
265285
}
266286
}

0 commit comments

Comments
 (0)