Skip to content

Commit

Permalink
fix: use stable promises for load/preload/React (gregberge#858)
Browse files Browse the repository at this point in the history
  • Loading branch information
theKashey authored Dec 12, 2021
1 parent 7a9af15 commit 3afbe79
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 31 deletions.
64 changes: 34 additions & 30 deletions src/createLoadable.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,37 @@ function createLoadable({
return Component
}

const cachedLoad = props => {
const cacheKey = getCacheKey(props)
let promise = cache[cacheKey]

if (!promise || promise.status === STATUS_REJECTED) {
promise = ctor.requireAsync(props)
promise.status = STATUS_PENDING

cache[cacheKey] = promise

promise.then(
() => {
promise.status = STATUS_RESOLVED
},
error => {
console.error(
'loadable-components: failed to asynchronously load component',
{
fileName: ctor.resolve(props),
chunkName: ctor.chunkName(props),
error: error ? error.message : error,
},
)
promise.status = STATUS_REJECTED
},
)
}

return promise
}

class InnerLoadable extends React.Component {
static getDerivedStateFromProps(props, state) {
const cacheKey = getCacheKey(props)
Expand Down Expand Up @@ -270,33 +301,7 @@ function createLoadable({
resolveAsync() {
const { __chunkExtractor, forwardedRef, ...props } = this.props

let promise = this.getCache()

if (!promise) {
promise = ctor.requireAsync(props)
promise.status = STATUS_PENDING

this.setCache(promise)

promise.then(
() => {
promise.status = STATUS_RESOLVED
},
error => {
console.error(
'loadable-components: failed to asynchronously load component',
{
fileName: ctor.resolve(this.props),
chunkName: ctor.chunkName(this.props),
error: error ? error.message : error,
},
)
promise.status = STATUS_REJECTED
},
)
}

return promise
return cachedLoad(props)
}

render() {
Expand Down Expand Up @@ -343,12 +348,11 @@ function createLoadable({

// In future, preload could use `<link rel="preload">`
Loadable.preload = props => {
cache[getCacheKey()] = ctor.requireAsync(props);
Loadable.load(props)
}

Loadable.load = props => {
cache[getCacheKey()] = ctor.requireAsync(props);
return cache[getCacheKey()];
return cachedLoad(props)
}

return Loadable
Expand Down
2 changes: 1 addition & 1 deletion src/loadable.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe('#loadable', () => {
const { container } = render(<Component />)
expect(container).toBeEmpty()
await wait(() => expect(container).toHaveTextContent('loaded'))
expect(load).toHaveBeenCalledTimes(2)
expect(load).toHaveBeenCalledTimes(1)
})

it('supports commonjs default export', async () => {
Expand Down

0 comments on commit 3afbe79

Please sign in to comment.