Skip to content

Instantly share code, notes, and snippets.

@jacob-ebey
Last active December 31, 2022 00:46
Show Gist options
  • Save jacob-ebey/cd9c1e385a86e6fe28aaa4c73fad74a8 to your computer and use it in GitHub Desktop.
Save jacob-ebey/cd9c1e385a86e6fe28aaa4c73fad74a8 to your computer and use it in GitHub Desktop.
A very naive implementation of React's use() hook
// A very naive implementation of React's use() hook you can copy and paste into your app today
// to use with solutions such as remix's experimental `defer()` feature.
function use<T>(useable: Promise<T> | T) {
if (typeof useable != "object" || !useable || !("then" in useable)) {
return useable;
}
let promise = useable as Promise<T> & { _data?: T; _error?: unknown };
if ("_data" in promise) {
return promise._data!;
}
if ("_error" in promise) {
throw promise._error;
}
throw promise.then(
(data) => {
promise._data = data;
},
(error: unknown) => {
promise._error = error;
}
);
}
import { defer } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { Suspense } from "react";
import { use } from "~/react-use";
function delay<T = unknown>(value: T, ms: number) {
return new Promise<T>((resolve) => setTimeout(() => resolve(value), ms));
}
export function loader() {
return defer({
first: delay("first", 1000),
second: delay("second", 2000),
});
}
function Message({ message }: { message: Promise<string> | string }) {
return <p>{use(message)}</p>;
}
export default function Index() {
const { first, second } = useLoaderData<typeof loader>();
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Welcome to Remix</h1>
<Suspense fallback={<p>loading first...</p>}>
<Message message={first} />
</Suspense>
<Suspense fallback={<p>loading second...</p>}>
<Message message={second} />
</Suspense>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment