Skip to content

Commit 878e6bf

Browse files
committed
Upgrade React and update React.lazy support
1 parent 9815e9b commit 878e6bf

File tree

6 files changed

+102
-91
lines changed

6 files changed

+102
-91
lines changed

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
}
5151
},
5252
"peerDependencies": {
53-
"react": "^16.8.0"
53+
"react": "^16.8.0 || ^17.0.0"
5454
},
5555
"devDependencies": {
5656
"@ampproject/rollup-plugin-closure-compiler": "^0.26.0",
@@ -72,8 +72,8 @@
7272
"lint-staged": "^10.5.1",
7373
"npm-run-all": "^4.1.5",
7474
"prettier": "^2.1.2",
75-
"react": "^16.13.1",
76-
"react-dom": "^16.13.1",
75+
"react": "^17.0.1",
76+
"react-dom": "^17.0.1",
7777
"rollup": "^2.33.1",
7878
"rollup-plugin-babel": "^4.4.0",
7979
"rollup-plugin-replace": "^2.2.0",

src/__tests__/element.test.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,6 @@ describe('typeOf', () => {
2626
})
2727
).toBe(REACT_PORTAL_TYPE)
2828

29-
expect(
30-
typeOf({
31-
$$typeof: is.Element,
32-
type: is.ConcurrentMode
33-
})
34-
).toBe(REACT_CONCURRENT_MODE_TYPE)
35-
3629
expect(
3730
typeOf({
3831
$$typeof: is.Element,

src/__tests__/suspense.test.js

Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ describe('renderPrepass', () => {
5252

5353
const render$ = renderPrepass(<Outer />)
5454

55-
return render$.catch(error => {
55+
return render$.catch((error) => {
5656
expect(Inner).toHaveBeenCalledTimes(1)
5757
expect(error).toBe(exception)
5858
})
@@ -66,7 +66,7 @@ describe('renderPrepass', () => {
6666
return null
6767
}
6868

69-
const Wait = props => {
69+
const Wait = (props) => {
7070
const start = Date.now()
7171
while (Date.now() - start < 21) {}
7272
return props.children
@@ -149,7 +149,7 @@ describe('renderPrepass', () => {
149149
})
150150
.mockImplementationOnce(() => value)
151151

152-
const Inner = jest.fn(props => {
152+
const Inner = jest.fn((props) => {
153153
expect(props.value).toBe(value)
154154
// We expect useState to work across suspense
155155
expect(props.state).toBe('test')
@@ -191,7 +191,7 @@ describe('renderPrepass', () => {
191191
})
192192
.mockImplementation(() => 'test')
193193

194-
const Inner = jest.fn(props => {
194+
const Inner = jest.fn((props) => {
195195
expect(props.value).toBe('test')
196196
expect(props.state).toBe('test')
197197
})
@@ -232,7 +232,7 @@ describe('renderPrepass', () => {
232232
})
233233
.mockImplementation(() => 'test')
234234

235-
const Inner = jest.fn(props => {
235+
const Inner = jest.fn((props) => {
236236
expect(props.state).toBe('test')
237237
})
238238

@@ -263,7 +263,7 @@ describe('renderPrepass', () => {
263263
const Inner = jest.fn(() => null)
264264
const Outer = jest.fn(() => <Inner />)
265265

266-
const visitor = jest.fn(element => {
266+
const visitor = jest.fn((element) => {
267267
if (element.type === Inner) return Promise.resolve()
268268
})
269269

@@ -294,7 +294,7 @@ describe('renderPrepass', () => {
294294
})
295295
.mockImplementationOnce(() => value)
296296

297-
const Inner = jest.fn(props => expect(props.value).toBe(value))
297+
const Inner = jest.fn((props) => expect(props.value).toBe(value))
298298

299299
class Outer extends Component {
300300
render() {
@@ -389,12 +389,12 @@ describe('renderPrepass', () => {
389389
describe('lazy components', () => {
390390
it('supports resolving lazy components', () => {
391391
const value = {}
392-
const Inner = jest.fn(props => expect(props.value).toBe(value))
392+
const Inner = jest.fn((props) => expect(props.value).toBe(value))
393393
const loadInner = jest.fn().mockResolvedValueOnce(Inner)
394394

395395
const Outer = React.lazy(loadInner)
396396
// Initially React sets the lazy component's status to -1
397-
expect(Outer._status).toBe(-1 /* INITIAL */)
397+
expect(Outer._payload._status).toBe(-1 /* INITIAL */)
398398

399399
const render$ = renderPrepass(<Outer value={value} />)
400400

@@ -405,14 +405,14 @@ describe('renderPrepass', () => {
405405

406406
// The lazy component's state should be updated with some initial
407407
// progress
408-
expect(Outer._status).toBe(0 /* PENDING */)
408+
expect(Outer._payload._status).toBe(0 /* PENDING */)
409409

410410
return render$.then(() => {
411411
// Afterwards we can expect Inner to have loaded and rendered
412412
expect(Inner).toHaveBeenCalledTimes(1)
413413

414414
// The lazy component's state should reflect this
415-
expect(Outer._status).toBe(1 /* SUCCESSFUL */)
415+
expect(Outer._payload._status).toBe(1 /* SUCCESSFUL */)
416416
})
417417
})
418418

@@ -424,28 +424,11 @@ describe('renderPrepass', () => {
424424

425425
expect(Inner).not.toHaveBeenCalled()
426426
expect(loadInner).toHaveBeenCalledTimes(1)
427-
expect(Outer._status).toBe(0 /* PENDING */)
427+
expect(Outer._payload._status).toBe(0 /* PENDING */)
428428

429429
return render$.then(() => {
430430
expect(Inner).toHaveBeenCalledTimes(1)
431-
expect(Outer._status).toBe(1 /* SUCCESSFUL */)
432-
})
433-
})
434-
435-
it('supports skipping rejecting lazy components', () => {
436-
const Inner = jest.fn(() => null)
437-
const loadInner = jest.fn().mockRejectedValueOnce(new Error('test'))
438-
const Outer = React.lazy(loadInner)
439-
const render$ = renderPrepass(<Outer />)
440-
441-
expect(Inner).not.toHaveBeenCalled()
442-
expect(loadInner).toHaveBeenCalledTimes(1)
443-
expect(Outer._status).toBe(0 /* PENDING */)
444-
445-
return render$.then(() => {
446-
expect(Inner).toHaveBeenCalledTimes(0)
447-
// The lazy component's state should reflect the rejected promise
448-
expect(Outer._status).toBe(2 /* FAILED */)
431+
expect(Outer._payload._status).toBe(1 /* SUCCESSFUL */)
449432
})
450433
})
451434

@@ -455,10 +438,10 @@ describe('renderPrepass', () => {
455438
const render$ = renderPrepass(<Outer />)
456439

457440
expect(loadInner).toHaveBeenCalledTimes(1)
458-
expect(Outer._status).toBe(0 /* PENDING */)
441+
expect(Outer._payload._status).toBe(0 /* PENDING */)
459442

460443
return render$.then(() => {
461-
expect(Outer._status).toBe(2 /* FAILED */)
444+
expect(Outer._payload._status).toBe(2 /* FAILED */)
462445
})
463446
})
464447

@@ -467,8 +450,8 @@ describe('renderPrepass', () => {
467450
const loadInner = jest.fn().mockResolvedValueOnce(Inner)
468451
const Outer = React.lazy(loadInner)
469452

470-
Outer._status = 1 /* SUCCESSFUL */
471-
Outer._result = Inner /* SUCCESSFUL */
453+
Outer._payload._status = 1 /* SUCCESSFUL */
454+
Outer._payload._result = Inner /* SUCCESSFUL */
472455

473456
renderPrepass(<Outer />)
474457

src/render/lazyComponent.js

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
// @flow
22

33
import { createElement, type Node } from 'react'
4-
import type { LazyComponent, DefaultProps, LazyFrame, Frame } from '../types'
4+
import type {
5+
LazyComponent,
6+
LazyComponentPayload,
7+
DefaultProps,
8+
LazyFrame,
9+
Frame
10+
} from '../types'
511
import { getChildrenArray } from '../element'
612

713
import {
@@ -15,28 +21,38 @@ import {
1521
} from '../internals'
1622

1723
const resolve = (type: LazyComponent): Promise<void> => {
18-
type._status = 0 /* PENDING */
24+
const payload = (type._payload || type: any)
25+
if (payload._status === 0) {
26+
return payload._result
27+
} else if (payload._status === 1) {
28+
return Promise.resolve(payload._result)
29+
} else if (payload._status === 2) {
30+
return Promise.reject(payload._result)
31+
}
32+
33+
payload._status = 0 /* PENDING */
1934

20-
return type
21-
._ctor()
35+
return (payload._result = (payload._ctor || payload._result)()
2236
.then((Component) => {
37+
payload._result = Component
2338
if (typeof Component === 'function') {
24-
type._result = Component
25-
type._status = 1 /* SUCCESSFUL */
39+
payload._status = 1 /* SUCCESSFUL */
2640
} else if (
2741
Component !== null &&
2842
typeof Component === 'object' &&
2943
typeof Component.default === 'function'
3044
) {
31-
type._result = Component.default
32-
type._status = 1 /* SUCCESSFUL */
45+
payload._result = Component.default
46+
payload._status = 1 /* SUCCESSFUL */
3347
} else {
34-
type._status = 2 /* FAILED */
48+
payload._status = 2 /* FAILED */
3549
}
3650
})
37-
.catch(() => {
38-
type._status = 2 /* FAILED */
39-
})
51+
.catch((error) => {
52+
payload._status = 2 /* FAILED */
53+
payload._result = error
54+
return Promise.reject(error)
55+
}))
4056
}
4157

4258
const render = (
@@ -46,8 +62,9 @@ const render = (
4662
): Node => {
4763
// Component has previously been fetched successfully,
4864
// so create the element with passed props and return it
49-
if (type._status === 1) {
50-
return createElement(type._result, props)
65+
const payload = ((type._payload || type: any): LazyComponentPayload)
66+
if (payload._status === 1) {
67+
return createElement(payload._result, props)
5168
}
5269

5370
return null
@@ -59,7 +76,8 @@ export const mount = (
5976
queue: Frame[]
6077
): Node => {
6178
// If the component has not been fetched yet, suspend this component
62-
if (type._status !== 2 && type._status !== 1) {
79+
const payload = ((type._payload || type: any): LazyComponentPayload)
80+
if (payload._status <= 0) {
6381
queue.push({
6482
kind: 'frame.lazy',
6583
contextMap: getCurrentContextMap(),

src/types/element.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,46 @@ export type FragmentElement = {
7676
$$typeof: typeof REACT_ELEMENT_TYPE
7777
}
7878

79-
export type LazyComponent = {
79+
type LazyComponentUninitialized = {
80+
_status: -1,
81+
_result: () => Promise<any>
82+
}
83+
84+
type LazyComponentPending = {
85+
_status: 0,
86+
_result: Promise<any>
87+
}
88+
89+
type LazyComponentResolved = {
90+
_status: 1,
91+
_result: ComponentType<DefaultProps> & ComponentStatics
92+
}
93+
94+
type LazyComponentRejected = {
95+
_status: 2,
96+
_result: mixed
97+
}
98+
99+
export type LazyComponentPayload =
100+
| LazyComponentUninitialized
101+
| LazyComponentPending
102+
| LazyComponentResolved
103+
| LazyComponentRejected
104+
105+
type LazyComponentLegacy = {
80106
$$typeof: typeof REACT_LAZY_TYPE,
81107
_ctor: () => Promise<any>,
82108
_status: -1 | 0 | 1 | 2,
83-
_result: any
109+
_result: mixed
110+
}
111+
112+
type LazyComponentModern = {
113+
$$typeof: typeof REACT_LAZY_TYPE,
114+
_payload: LazyComponentPayload
84115
}
85116

117+
export type LazyComponent = LazyComponentLegacy | LazyComponentModern
118+
86119
/** <React.lazy(Comp)> */
87120
export type LazyElement = {
88121
$$typeof: typeof REACT_LAZY_TYPE,

0 commit comments

Comments
 (0)