I have a provider that does some work when it loads (one time). It adds a script tag for a map then when that script is loaded it initializes the map.
I want to the children to be able to use suspense. I'd like to return from that provider a promise which either throws if not resolved (for suspense) or it returns the map.
I can't figure out how to do this inside my component. Of note, I'm using nextJS so I have to make sure I'm on the client side too.
I made a code sandbox to simplify it:
function App() {
return (
<MyProvider>
<Suspense fallback={<h1>Loading</h1>}>
<Child />
</Suspense>
</MyProvider>
);
}
Child consumes the map and displays it, in this case it's just text:
const Child = () => {
const { data } = useContext(context);
const result = data.read();
return <div>Result: {result}</div>;
};
Here is the provider:
const MyProvider = ({ children }) => {
useEffect(() => {
// I do asynchronous work here which adds a script tag and when
// it is fully loaded initializes a map. How do I pass this promise
// down to children in a way that will work with suspense?
const data = wrapPromise(
new Promise(resolve => {
setTimeout(() => {
console.log("fetched data");
resolve({
name: "Ringo Starr"
});
}, 1000);
})
);
}, []);
return <context.Provider value={{ data }}>{children}</context.Provider>;
};
You want to create the promise once, and memoize it:
const data = useMemo(() => new Promise(resolve => {
setTimeout(resolve, 1000, { name: "Ringo Starr" });
}), []);