2
2
import React from 'react'
3
3
import PropTypes from 'prop-types'
4
4
import hoist from 'hoist-non-react-statics'
5
+ import { Context } from 'vm'
5
6
import req from './requireUniversalModule'
6
-
7
7
import type {
8
8
Config ,
9
9
ConfigFunc ,
@@ -19,6 +19,7 @@ import {
19
19
createDefaultRender ,
20
20
isServer
21
21
} from './utils'
22
+ import { __update } from './helpers'
22
23
23
24
export { CHUNK_NAMES , MODULE_IDS } from './requireUniversalModule'
24
25
export { default as ReportChunks } from './report-chunks'
@@ -48,7 +49,7 @@ export default function universal<Props: Props>(
48
49
...options
49
50
} = opts
50
51
51
- const render = userRender || createDefaultRender ( Loading , Err )
52
+ const renderFunc = userRender || createDefaultRender ( Loading , Err )
52
53
53
54
const isDynamic = hasBabelPlugin || testBabelPlugin
54
55
options . isDynamic = isDynamic
@@ -58,7 +59,7 @@ export default function universal<Props: Props>(
58
59
59
60
return class UniversalComponent extends React . Component < void , Props , * > {
60
61
/* eslint-disable react/sort-comp */
61
- _mounted : boolean
62
+ _initialized : boolean
62
63
_asyncOnly : boolean
63
64
64
65
state : State
@@ -112,103 +113,22 @@ export default function universal<Props: Props>(
112
113
report : PropTypes . func
113
114
}
114
115
115
- constructor ( props : Props , context : { } ) {
116
- super ( props , context )
117
- this . state = { error: null }
118
- }
119
-
120
- componentWillMount ( ) {
121
- this . _mounted = true
122
-
123
- const { addModule , requireSync , requireAsync , asyncOnly } = req (
124
- asyncModule ,
125
- options ,
126
- this . props
127
- )
128
-
129
- let mod
130
-
131
- try {
132
- mod = requireSync ( this . props , this . context )
133
- }
134
- catch ( error ) {
135
- return this . update ( { error } )
136
- }
137
-
138
- this . _asyncOnly = asyncOnly
139
- const chunkName = addModule ( this . props ) // record the module for SSR flushing :)
140
-
141
- if ( this . context . report ) {
142
- this . context . report ( chunkName )
143
- }
144
-
145
- if ( mod || isServer ) {
146
- this . handleBefore ( true , true , isServer )
147
- this . update ( { mod } , true , true , isServer )
148
- return
149
- }
150
-
151
- this . handleBefore ( true , false )
152
- this . requireAsync ( requireAsync , this . props , true )
153
- }
154
-
155
- componentWillUnmount ( ) {
156
- this . _mounted = false
157
- }
158
-
159
- componentWillReceiveProps ( nextProps : Props ) {
160
- if ( isDynamic || this . _asyncOnly ) {
161
- const { requireSync, requireAsync, shouldUpdate } = req (
162
- asyncModule ,
163
- options ,
164
- nextProps ,
165
- this . props
166
- )
167
-
168
- if ( shouldUpdate ( nextProps , this . props ) ) {
169
- let mod
170
-
171
- try {
172
- mod = requireSync ( nextProps , this . context )
173
- }
174
- catch ( error ) {
175
- return this . update ( { error } )
176
- }
177
-
178
- this . handleBefore ( false , ! ! mod )
179
-
180
- if ( ! mod ) {
181
- return this . requireAsync ( requireAsync , nextProps )
182
- }
183
-
184
- const state = { mod }
185
-
186
- if ( alwaysDelay ) {
187
- if ( loadingTransition ) this . update ( { mod : null } ) // display `loading` during componentWillReceiveProps
188
- setTimeout ( ( ) => this . update ( state , false , true ) , minDelay )
189
- return
190
- }
191
-
192
- this . update ( state , false , true )
193
- }
194
- else if ( isHMR ( ) ) {
195
- const mod = requireSync ( nextProps , this . context )
196
- this . setState ( { mod : ( ) => null } ) // HMR /w Redux and HOCs can be finicky, so we
197
- setTimeout ( ( ) => this . setState ( { mod } ) ) // toggle components to insure updates occur
198
- }
199
- }
200
- }
201
-
202
- requireAsync ( requireAsync : RequireAsync , props : Props , isMount ? : boolean ) {
203
- if ( this . state . mod && loadingTransition ) {
204
- this . update ( { mod : null } ) // display `loading` during componentWillReceiveProps
116
+ requireAsyncInner (
117
+ requireAsync : RequireAsync ,
118
+ props : Props ,
119
+ state : State ,
120
+ context : Context ,
121
+ isMount ? : boolean
122
+ ) {
123
+ if ( ! state . mod && loadingTransition ) {
124
+ this . update ( { mod : null , props } ) // display `loading` during componentWillReceiveProps
205
125
}
206
126
207
127
const time = new Date ( )
208
128
209
- requireAsync ( props , this . context )
129
+ requireAsync ( props , context )
210
130
. then ( ( mod : ?any ) => {
211
- const state = { mod }
131
+ const state = { mod, props , context }
212
132
213
133
const timeLapsed = new Date ( ) - time
214
134
if ( timeLapsed < minDelay ) {
@@ -218,7 +138,7 @@ export default function universal<Props: Props>(
218
138
219
139
this . update ( state , isMount )
220
140
} )
221
- . catch ( error => this . update ( { error } ) )
141
+ . catch ( error => this . update ( { error, props , context } ) )
222
142
}
223
143
224
144
update = (
@@ -227,7 +147,7 @@ export default function universal<Props: Props>(
227
147
isSync ? : boolean = false ,
228
148
isServer ? : boolean = false
229
149
) => {
230
- if ( ! this . _mounted ) return
150
+ if ( ! this . _initialized ) return
231
151
if ( ! state . error ) state . error = null
232
152
233
153
this . handleAfter ( state , isMount , isSync , isServer )
@@ -271,11 +191,124 @@ export default function universal<Props: Props>(
271
191
272
192
this . setState ( state )
273
193
}
194
+ // $FlowFixMe
195
+ init ( props , context ) {
196
+ const { addModule , requireSync , requireAsync , asyncOnly } = req (
197
+ asyncModule ,
198
+ options ,
199
+ props
200
+ )
201
+
202
+ let mod
203
+
204
+ try {
205
+ mod = requireSync ( props , context )
206
+ }
207
+ catch ( error ) {
208
+ return __update ( props , { error, props, context } , this . _initialized )
209
+ }
210
+
211
+ this . _asyncOnly = asyncOnly
212
+ const chunkName = addModule ( props ) // record the module for SSR flushing :)
213
+
214
+ if ( context . report ) {
215
+ context . report ( chunkName )
216
+ }
217
+
218
+ if ( mod || isServer ) {
219
+ this . handleBefore ( true , true , isServer )
220
+ return __update (
221
+ props ,
222
+ { asyncOnly, props, mod, context } ,
223
+ this . _initialized ,
224
+ true ,
225
+ true ,
226
+ isServer
227
+ )
228
+ }
229
+
230
+ this . handleBefore ( true , false )
231
+ this . requireAsyncInner (
232
+ requireAsync ,
233
+ props ,
234
+ { props, asyncOnly, mod, context } ,
235
+ context ,
236
+ true
237
+ )
238
+ return { mod , asyncOnly , context , props }
239
+ }
240
+
241
+ constructor ( props : Props , context : { } ) {
242
+ super ( props , context )
243
+ this . state = this . init ( this . props , this . context )
244
+ // $FlowFixMe
245
+ this . state . error = null
246
+ }
247
+
248
+ static getDerivedStateFromProps ( nextProps , currentState ) {
249
+ const { requireSync , shouldUpdate } = req (
250
+ asyncModule ,
251
+ options ,
252
+ nextProps ,
253
+ currentState . props
254
+ )
255
+ if ( isHMR ( ) && shouldUpdate ( currentState . props , nextProps ) ) {
256
+ const mod = requireSync ( nextProps , currentState . context )
257
+ return { ...currentState , mod }
258
+ }
259
+ return null
260
+ }
261
+
262
+ componentDidMount ( ) {
263
+ this . _initialized = true
264
+ }
265
+
266
+ componentDidUpdate ( prevProps : Props ) {
267
+ if ( isDynamic || this . _asyncOnly ) {
268
+ const { requireSync , requireAsync , shouldUpdate } = req (
269
+ asyncModule ,
270
+ options ,
271
+ this . props ,
272
+ prevProps
273
+ )
274
+
275
+ if ( shouldUpdate ( this . props , prevProps ) ) {
276
+ let mod
277
+
278
+ try {
279
+ mod = requireSync ( this . props , this . context )
280
+ }
281
+ catch ( error ) {
282
+ return this . update ( { error } )
283
+ }
284
+
285
+ this . handleBefore ( false , ! ! mod )
286
+
287
+ if ( ! mod ) {
288
+ return this . requireAsyncInner ( requireAsync , this . props , { mod } )
289
+ }
290
+
291
+ const state = { mod }
292
+
293
+ if ( alwaysDelay ) {
294
+ if ( loadingTransition ) this . update ( { mod : null } ) // display `loading` during componentWillReceiveProps
295
+ setTimeout ( ( ) => this . update ( state , false , true ) , minDelay )
296
+ return
297
+ }
298
+
299
+ this . update ( state , false , true )
300
+ }
301
+ }
302
+ }
303
+
304
+ componentWillUnmount ( ) {
305
+ this . _initialized = false
306
+ }
274
307
275
308
render ( ) {
276
309
const { isLoading , error : userError , ...props } = this . props
277
310
const { mod , error } = this . state
278
- return render ( props , mod , isLoading , userError || error )
311
+ return renderFunc ( props , mod , isLoading , userError || error )
279
312
}
280
313
}
281
314
}
0 commit comments