diff --git a/__test__/SSR/index.spec.ts b/__test__/SSR/index.spec.ts new file mode 100644 index 0000000..d146056 --- /dev/null +++ b/__test__/SSR/index.spec.ts @@ -0,0 +1,29 @@ +/// +import '@testing-library/react/cleanup-after-each' +import { Model } from '../../src' +import { SSRCounter } from '..' + +describe('asyncState', () => { + test('return default initial state from asyncState', async () => { + const { getInitialState } = Model({ + WrappedSSRCounter: Model(SSRCounter), + SSRCounter + }) + const initialModels = await getInitialState(undefined, { isServer: true }) + // const state = getState('AsyncCounter') + expect(initialModels['SSRCounter'].count).toBe(1) + expect(initialModels['SSRCounter'].clientKey).toBe(undefined) + expect(initialModels['WrappedSSRCounter'].count).toBe(1) + expect(initialModels['WrappedSSRCounter'].clientKey).toBe(undefined) + + // Simulate Client Side + const { getState } = Model( + { WrappedSSRCounter: Model(SSRCounter), SSRCounter }, + initialModels + ) + expect(initialModels['SSRCounter'].count).toBe(1) + expect(initialModels['WrappedSSRCounter'].count).toBe(1) + expect(getState('SSRCounter').clientKey).toBe('unused') + expect(getState('WrappedSSRCounter').clientKey).toBe('unused') + }) +}) diff --git a/__test__/index.d.ts b/__test__/index.d.ts index a42490d..d165419 100644 --- a/__test__/index.d.ts +++ b/__test__/index.d.ts @@ -2,6 +2,11 @@ type CounterState = { count: number } +type SSRCounterState = { + count: number + clientKey: string +} + type ExtState = { name: string } diff --git a/__test__/index.ts b/__test__/index.ts index a260a0d..b982da5 100644 --- a/__test__/index.ts +++ b/__test__/index.ts @@ -113,6 +113,20 @@ export const AsyncCounter: ModelType = { state: { count: 0 } } +export const SSRCounter: ModelType = { + actions: { + increment: params => { + return state => { + state.count += params + } + } + }, + asyncState: async (context: { count?: number }) => ({ + count: context ? context.count || 1 : 1 + }), + state: { count: 0, clientKey: 'unused' } +} + export const AsyncNull: ModelType = { actions: { increment: params => { diff --git a/package.json b/package.json index cca7261..8e09448 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-model", - "version": "3.0.4", + "version": "3.1.0", "description": "The State management library for React", "main": "./dist/react-model.js", "umd:main": "./dist/react-model.umd.js", diff --git a/src/helper.ts b/src/helper.ts index 7105183..0c55c53 100644 --- a/src/helper.ts +++ b/src/helper.ts @@ -80,7 +80,11 @@ const timeout = (ms: number, data: T): Promise => }, ms) ) -const getInitialState = async (context?: T) => { +const getInitialState = async ( + context?: T, + config?: { isServer?: boolean } +) => { + const ServerState: { [name: string]: any } = { __FROM_SERVER__: true } await Promise.all( Object.keys(Global.State).map(async modelName => { if ( @@ -91,14 +95,18 @@ const getInitialState = async (context?: T) => { ) { const asyncGetter = Global.AsyncState[modelName] const asyncState = asyncGetter ? await asyncGetter(context) : {} - Global.State[modelName] = { - ...Global.State[modelName], - ...asyncState + if (config && config.isServer) { + ServerState[modelName] = asyncState + } else { + Global.State[modelName] = { + ...Global.State[modelName], + ...asyncState + } } } }) ) - return Global.State + return config && config.isServer ? ServerState : Global.State } const getCache = (modelName: string, actionName: string) => { diff --git a/src/index.d.ts b/src/index.d.ts index 7fbb3df..87f4417 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -142,7 +142,8 @@ interface APIs { ? M[K]['actions'] : unknown getInitialState: ( - context?: T | undefined + context?: T | undefined, + config?: { isServer: boolean } ) => Promise<{ [modelName: string]: any }> diff --git a/src/index.tsx b/src/index.tsx index 706c4bc..4bb85d7 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -76,7 +76,7 @@ function Model( useStore: errorFn([{}, {}]) } as any } - if (initialState) { + if (initialState && !initialState.__FROM_SERVER__) { Global.State = initialState || {} } extContext && (Global.Context['__global'] = extContext) @@ -89,7 +89,9 @@ function Model( return } if (!isAPI(model)) { - if (!Global.State[name]) { + if (initialState && initialState.__FROM_SERVER__) { + Global.State[name] = { ...model.state, ...initialState[name] } + } else if (!Global.State[name]) { Global.State[name] = model.state } if (model.middlewares) { @@ -102,6 +104,12 @@ function Model( if (!Global.State[name] || !initialState) { Global.State[name] = Global.State[model.__id] } + if (initialState && initialState.__FROM_SERVER__) { + Global.State[name] = { + ...Global.State[model.__id], + ...initialState[name] + } + } Global.Actions[name] = Global.Actions[model.__id] Global.AsyncState[name] = Global.AsyncState[model.__id] Global.Middlewares[name] = Global.Middlewares[model.__id]