Skip to content

Instantly share code, notes, and snippets.

@mjackson
Created May 15, 2020 23:08
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjackson/9908b122070b176989fedd3a55114272 to your computer and use it in GitHub Desktop.
Save mjackson/9908b122070b176989fedd3a55114272 to your computer and use it in GitHub Desktop.
import React from 'react';
let DataContext = React.createContext();
// A higher-order component for pairing preload function + component ...
function withData(preloadData, Component, autoPreloadOnRender = true) {
let needsPreload = !!autoPreloadOnRender;
let promise;
let value;
let error;
function preload() {
needsPreload = false;
if (promise == null) {
promise = preloadData();
promise.then(
v => {
promise = null;
value = v;
},
e => {
promise = null;
error = e;
}
);
}
return promise;
}
function Data(props) {
if (needsPreload) {
// Go ahead and kickoff preloading here if nobody did it yet.
preload();
}
return (
<DataContext.Provider value={{ promise, value, error }}>
<Component {...props} />
</DataContext.Provider>
);
}
Data.preload = preload;
return Data;
}
// ... and a hook to retrieve the result of the fetch or trigger suspense.
function useData() {
let { promise, value, error } = React.useContext(DataContext);
if (error) {
throw error;
}
if (promise) {
throw promise; // trigger suspense
}
return value;
}
// Use it:
let UserProfile = withData(
() => fetchUser('mjackson'),
() => {
let user = useData();
return <p>Hello, {user.name}</p>;
}
);
function fetchUser(name) {
return new Promise(accept => {
accept({ name });
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment