Skip to content

Commit 04e3cbe

Browse files
feat(ssr): only return asyncState from server side (#146)
1 parent a217007 commit 04e3cbe

File tree

7 files changed

+74
-9
lines changed

7 files changed

+74
-9
lines changed

__test__/SSR/index.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/// <reference path="../index.d.ts" />
2+
import '@testing-library/react/cleanup-after-each'
3+
import { Model } from '../../src'
4+
import { SSRCounter } from '..'
5+
6+
describe('asyncState', () => {
7+
test('return default initial state from asyncState', async () => {
8+
const { getInitialState } = Model({
9+
WrappedSSRCounter: Model(SSRCounter),
10+
SSRCounter
11+
})
12+
const initialModels = await getInitialState(undefined, { isServer: true })
13+
// const state = getState('AsyncCounter')
14+
expect(initialModels['SSRCounter'].count).toBe(1)
15+
expect(initialModels['SSRCounter'].clientKey).toBe(undefined)
16+
expect(initialModels['WrappedSSRCounter'].count).toBe(1)
17+
expect(initialModels['WrappedSSRCounter'].clientKey).toBe(undefined)
18+
19+
// Simulate Client Side
20+
const { getState } = Model(
21+
{ WrappedSSRCounter: Model(SSRCounter), SSRCounter },
22+
initialModels
23+
)
24+
expect(initialModels['SSRCounter'].count).toBe(1)
25+
expect(initialModels['WrappedSSRCounter'].count).toBe(1)
26+
expect(getState('SSRCounter').clientKey).toBe('unused')
27+
expect(getState('WrappedSSRCounter').clientKey).toBe('unused')
28+
})
29+
})

__test__/index.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ type CounterState = {
22
count: number
33
}
44

5+
type SSRCounterState = {
6+
count: number
7+
clientKey: string
8+
}
9+
510
type ExtState = {
611
name: string
712
}

__test__/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,20 @@ export const AsyncCounter: ModelType<CounterState, CounterActionParams> = {
113113
state: { count: 0 }
114114
}
115115

116+
export const SSRCounter: ModelType<SSRCounterState, CounterActionParams> = {
117+
actions: {
118+
increment: params => {
119+
return state => {
120+
state.count += params
121+
}
122+
}
123+
},
124+
asyncState: async (context: { count?: number }) => ({
125+
count: context ? context.count || 1 : 1
126+
}),
127+
state: { count: 0, clientKey: 'unused' }
128+
}
129+
116130
export const AsyncNull: ModelType<CounterState, CounterActionParams> = {
117131
actions: {
118132
increment: params => {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-model",
3-
"version": "3.0.4",
3+
"version": "3.1.0",
44
"description": "The State management library for React",
55
"main": "./dist/react-model.js",
66
"umd:main": "./dist/react-model.umd.js",

src/helper.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,11 @@ const timeout = <T>(ms: number, data: T): Promise<T> =>
8080
}, ms)
8181
)
8282

83-
const getInitialState = async <T extends any>(context?: T) => {
83+
const getInitialState = async <T extends any>(
84+
context?: T,
85+
config?: { isServer?: boolean }
86+
) => {
87+
const ServerState: { [name: string]: any } = { __FROM_SERVER__: true }
8488
await Promise.all(
8589
Object.keys(Global.State).map(async modelName => {
8690
if (
@@ -91,14 +95,18 @@ const getInitialState = async <T extends any>(context?: T) => {
9195
) {
9296
const asyncGetter = Global.AsyncState[modelName]
9397
const asyncState = asyncGetter ? await asyncGetter(context) : {}
94-
Global.State[modelName] = {
95-
...Global.State[modelName],
96-
...asyncState
98+
if (config && config.isServer) {
99+
ServerState[modelName] = asyncState
100+
} else {
101+
Global.State[modelName] = {
102+
...Global.State[modelName],
103+
...asyncState
104+
}
97105
}
98106
}
99107
})
100108
)
101-
return Global.State
109+
return config && config.isServer ? ServerState : Global.State
102110
}
103111

104112
const getCache = (modelName: string, actionName: string) => {

src/index.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ interface APIs<M extends Models> {
142142
? M[K]['actions']
143143
: unknown
144144
getInitialState: <T extends any>(
145-
context?: T | undefined
145+
context?: T | undefined,
146+
config?: { isServer: boolean }
146147
) => Promise<{
147148
[modelName: string]: any
148149
}>

src/index.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function Model<M extends Models, MT extends ModelType, E>(
7676
useStore: errorFn([{}, {}])
7777
} as any
7878
}
79-
if (initialState) {
79+
if (initialState && !initialState.__FROM_SERVER__) {
8080
Global.State = initialState || {}
8181
}
8282
extContext && (Global.Context['__global'] = extContext)
@@ -89,7 +89,9 @@ function Model<M extends Models, MT extends ModelType, E>(
8989
return
9090
}
9191
if (!isAPI(model)) {
92-
if (!Global.State[name]) {
92+
if (initialState && initialState.__FROM_SERVER__) {
93+
Global.State[name] = { ...model.state, ...initialState[name] }
94+
} else if (!Global.State[name]) {
9395
Global.State[name] = model.state
9496
}
9597
if (model.middlewares) {
@@ -102,6 +104,12 @@ function Model<M extends Models, MT extends ModelType, E>(
102104
if (!Global.State[name] || !initialState) {
103105
Global.State[name] = Global.State[model.__id]
104106
}
107+
if (initialState && initialState.__FROM_SERVER__) {
108+
Global.State[name] = {
109+
...Global.State[model.__id],
110+
...initialState[name]
111+
}
112+
}
105113
Global.Actions[name] = Global.Actions[model.__id]
106114
Global.AsyncState[name] = Global.AsyncState[model.__id]
107115
Global.Middlewares[name] = Global.Middlewares[model.__id]

0 commit comments

Comments
 (0)