Skip to content

Instantly share code, notes, and snippets.

@Rafe
Created January 12, 2021 13:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rafe/c8bf4007cbd2d09c24efed8059aa3ee0 to your computer and use it in GitHub Desktop.
Save Rafe/c8bf4007cbd2d09c24efed8059aa3ee0 to your computer and use it in GitHub Desktop.
React Suspense and Error Boundary
<ErrorBoundary>
<ProfileDetails resource={resource}/>
</ErrorBoundary>
// Create dynamic loading component that trigger Suspense while loading.
const LazyComponent = React.lazy(() => import('./Component));
<Suspense fallback={<h1>Loading component</h1>}>
<LazyComponent>
</Suspense>
function ProfilePage({ resource }) {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails resource={resource} />
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline resource={resource} />
</Suspense>
</Suspense>
);
}
const Unitialized = -1;
const Pending = 0;
const Resolved = 1;
const Rejected = 2;
function lazy(ctor) {
// hold component state in closure
const payload = {
_status: Unitialized,
_result: ctor
}
return {
$$typeof: REACT_LAZY_TYPE,
_payload: payload,
_init: lazyInitializer
}
}
function lazyInitalizer(payload) {
// import when first initialize
if (payload._status === Uninitialized) {
const thenable = payload._result();
// Transition to the Pending state.
payload._status = Pending,
payload._result = thenable
thenable.then(
// save result to payload
moduleObject => {
if (payload._status === Pending) {
// Transition to the Resolved state.
payload._status = Resolved
payload._result = moduleObject.default
}
},
error => {
if (payload._status === Pending) {
// Transition to the Rejected state.
payload._status = Rejected;
payload._result = error;
}
},
);
} else if (payload._status === Resolved) {
// return result when resolved.
return payload._result;
} else {
// throw Promise or Error when status is Pending or Rejected.
throw payload._result;
}
}
const Unitialized = -1;
const Pending = 0;
const Resolved = 1;
const Rejected = 2;
function suspenseFetch(url) {
const payload = {
_status: Unitialized,
_result: () => fetch(url)
}
return () => {
if (payload._status === Uninitialized) {
const promise = payload._result()
payload._status = Pending
payload._result = promise
promise.then((res) => {
if (payload._status === Pending) {
payload._status = Resolved
payload._result = res
}
}, (err) => {
if (payload._status === Pending) {
payload._status = Rejected
payload._result = err
}
})
} else if (payload._status === Resolved) {
return payload._result
} else {
throw payload._result
}
}
}
// in app
const fetchUser = suspenseFetch(`/users/1`)
const User = () => {
const user = fetchUser()
return <div>{user.name}</div>
}
const App = () => (
<Suspense fallback={<h1>Loading user...</h1>}>
<User>
</Suspense>
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment