Skip to content

Commit

Permalink
fix: Fixed lazy usage with Suspense and Error Boundary together (#521)
Browse files Browse the repository at this point in the history
* Fixed lazy usage with Suspense and Error Boundary together

* Typo

* v1.0.0-fork

* accidental push

* Condition was reversed

* Fixed Suspense with full dynamic import after fulfilled promise

* Added unit test

* cached promise

* added tests for multiple elements of same async component

* renamed unit test

* added retryable error boundary

* reworked tests

* Retrying working for lazy and loadable

* linter should run on pre-commit... :/

* upped max bundle size

* fix: Fixed suspense tests and fixed un-throwable pending promises when using suspense

* refactor: removed unnecessary wait in test

* test: fixed test regarding nested suspense

* test: fixed fucked up assertion

* fix: fixed weird corner case on error boundary not being reached

* feat: removed proxy

* fix: removed unnecessary code

* fix: fixed unnecesssary stack of callbacks
  • Loading branch information
kamikazePT committed Sep 5, 2020
1 parent 10507da commit 42fbdd0
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 85 deletions.
5 changes: 5 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ module.exports = {
['@babel/preset-env', { loose: true, targets: getTargets() }],
],
plugins: ['@babel/plugin-proposal-class-properties'],
env: {
test: {
plugins: ['@babel/plugin-proposal-function-bind'],
},
},
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@babel/core": "^7.7.7",
"@babel/node": "^7.7.7",
"@babel/plugin-proposal-class-properties": "^7.7.4",
"@babel/plugin-proposal-function-bind": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.7.6",
"@babel/preset-env": "^7.7.7",
"@babel/preset-react": "^7.7.4",
Expand Down
87 changes: 51 additions & 36 deletions packages/component/src/createLoadable.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { invariant } from './util'
import Context from './Context'
import { LOADABLE_SHARED } from './shared'

const STATUS_PENDING = 'PENDING'
const STATUS_RESOLVED = 'RESOLVED'
const STATUS_REJECTED = 'REJECTED'

function resolveConstructor(ctor) {
if (typeof ctor === 'function') {
return { requireAsync: ctor }
Expand Down Expand Up @@ -75,8 +79,6 @@ function createLoadable({
cacheKey: getCacheKey(props),
}

this.promise = null

invariant(
!props.__chunkExtractor || ctor.requireSync,
'SSR requires `@loadable/babel-plugin`, please install it',
Expand Down Expand Up @@ -119,18 +121,22 @@ function createLoadable({
componentDidMount() {
this.mounted = true

if (this.state.loading) {
this.loadAsync()
} else if (!this.state.error) {
this.triggerOnLoad()
const cachedPromise = this.getCache()

if (cachedPromise && cachedPromise.status === STATUS_REJECTED) {
this.setCache()
this.setState({
error: undefined,
loading: true,
})
}
this.loadAsyncOnLifecycle()
}

componentDidUpdate(prevProps, prevState) {
// Component is reloaded if the cacheKey has changed
if (prevState.cacheKey !== this.state.cacheKey) {
this.promise = null
this.loadAsync()
this.loadAsyncOnLifecycle()
}
}

Expand Down Expand Up @@ -178,29 +184,45 @@ function createLoadable({
}

loadAsync() {
if (!this.promise) {
const { __chunkExtractor, forwardedRef, ...props } = this.props
this.promise = ctor
.requireAsync(props)
const { __chunkExtractor, forwardedRef, ...props } = this.props

let promise = this.getCache()

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

this.setCache(promise)

const cachedPromise = promise

promise = promise
.then(loadedModule => {
const result = resolve(loadedModule, this.props, Loadable)
if (options.suspense) {
this.setCache(result)
}
this.safeSetState(
{
result: resolve(loadedModule, this.props, Loadable),
loading: false,
},
() => this.triggerOnLoad(),
)
cachedPromise.status = STATUS_RESOLVED
return loadedModule
})
.catch(error => {
this.safeSetState({ error, loading: false })
cachedPromise.status = STATUS_REJECTED
throw error
})
}

return this.promise
return promise
}

loadAsyncOnLifecycle() {
this.loadAsync()
.then(loadedModule => {
const result = resolve(loadedModule, this.props, { Loadable })
this.safeSetState(
{
result,
loading: false,
},
() => this.triggerOnLoad(),
)
})
.catch(error => this.safeSetState({ error, loading: false }))
}

render() {
Expand All @@ -213,15 +235,10 @@ function createLoadable({
const { error, loading, result } = this.state

if (options.suspense) {
const cachedResult = this.getCache()
if (!cachedResult) throw this.loadAsync()
return render({
loading: false,
fallback: null,
result: cachedResult,
options,
props: { ...props, ref: forwardedRef },
})
const cachedPromise = this.getCache()
if (!cachedPromise || cachedPromise.status === STATUS_PENDING) {
throw this.loadAsync()
}
}

if (error) {
Expand All @@ -235,8 +252,6 @@ function createLoadable({
}

return render({
loading,
fallback,
result,
options,
props: { ...props, ref: forwardedRef },
Expand Down
4 changes: 2 additions & 2 deletions packages/component/src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export const { loadable, lazy } = createLoadable({
}
}
},
render({ result, loading, props }) {
if (!loading && props.children) {
render({ result, props }) {
if (props.children) {
return props.children(result)
}

Expand Down

0 comments on commit 42fbdd0

Please sign in to comment.