Skip to content

Commit 97a21e8

Browse files
author
Anant Singh
committed
Add a resolving state to each instance of the component, so every instance renders once the module is resolved.
Fixes ctrlplusb#90
1 parent 09935a2 commit 97a21e8

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

src/__tests__/__snapshots__/asyncComponent.test.js.snap

+4
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@
22

33
exports[`asyncComponent in a browser environment when an error occurs resolving a component should render the ErrorComponent 1`] = `"<div>failed to resolve</div>"`;
44

5+
exports[`asyncComponent in a browser environment when multiple instances of component are present should render all instances of the component 1`] = `"<div><div>Component</div><div>Component</div></div>"`;
6+
7+
exports[`asyncComponent in a browser environment when multiple instances of component are present should render multiple ErrorComponent 1`] = `"<div><div>failed to resolve</div><div>failed to resolve</div></div>"`;
8+
59
exports[`asyncComponent in a server environment when an error occurs resolving a component should not render the ErrorComponent 1`] = `null`;

src/__tests__/asyncComponent.test.js

+34
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import asyncComponent from '../asyncComponent'
77

88
describe('asyncComponent', () => {
99
const errorResolveDelay = 20
10+
const promiseResolveDelay = 20
1011

1112
describe('in a browser environment', () => {
1213
describe('when an error occurs resolving a component', () => {
@@ -21,6 +22,39 @@ describe('asyncComponent', () => {
2122
expect(renderWrapper.html()).toMatchSnapshot()
2223
})
2324
})
25+
26+
describe('when multiple instances of component are present', () => {
27+
it('should render all instances of the component', async () => {
28+
const Bob = asyncComponent({
29+
resolve: () => Promise.resolve(() => <div>Component</div>),
30+
env: 'browser',
31+
})
32+
const renderWrapper = mount(
33+
<div>
34+
<Bob />
35+
<Bob />
36+
</div>,
37+
)
38+
await new Promise(resolve => setTimeout(resolve, promiseResolveDelay))
39+
expect(renderWrapper.html()).toMatchSnapshot()
40+
})
41+
42+
it('should render multiple ErrorComponent', async () => {
43+
const Bob = asyncComponent({
44+
resolve: () => Promise.reject(new Error('failed to resolve')),
45+
ErrorComponent: ({ error }) => <div>{error.message}</div>,
46+
env: 'browser',
47+
})
48+
const renderWrapper = mount(
49+
<div>
50+
<Bob />
51+
<Bob />
52+
</div>,
53+
)
54+
await new Promise(resolve => setTimeout(resolve, errorResolveDelay))
55+
expect(renderWrapper.html()).toMatchSnapshot()
56+
})
57+
})
2458
})
2559

2660
describe('in a server environment', () => {

src/asyncComponent.js

+11-5
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,7 @@ export default function asyncComponent(config) {
4242
}
4343

4444
const needToResolveOnBrowser = () =>
45-
state.module == null &&
46-
state.error == null &&
47-
!state.resolving &&
48-
typeof window !== 'undefined'
45+
state.module == null && state.error == null && typeof window !== 'undefined'
4946

5047
// Takes the given module and if it has a ".default" the ".default" will
5148
// be returned. i.e. handy when you could be dealing with es6 imports.
@@ -89,6 +86,13 @@ export default function asyncComponent(config) {
8986
}),
9087
}
9188

89+
constructor() {
90+
super()
91+
this.state = {
92+
resolving: state.resolving,
93+
}
94+
}
95+
9296
getChildContext() {
9397
return {
9498
asyncComponentsAncestor:
@@ -137,7 +141,9 @@ export default function asyncComponent(config) {
137141
}
138142

139143
componentDidMount() {
140-
if (needToResolveOnBrowser()) {
144+
const { resolving } = this.state
145+
146+
if (!resolving && needToResolveOnBrowser()) {
141147
this.resolveModule()
142148
}
143149
}

0 commit comments

Comments
 (0)