“There is no terror in the bang, only in the anticipation of it.”
— Alfred Hitchcock
Hitchcock is a debugging tool for React Suspense. It wraps your calls to React.lazy(), provides a simple cache (based on react-cache) and let you pause, delay or invalidate your promises.
🚨 EXPERIMENTAL 🚨
Use this only for experimenting with the new React Concurrent Mode. Hitchcock is inefficient and unstable. Also, I have no idea what I'm doing.
Demos
- Movies: A clone of @karl clone of @dan_abramov demo
- Suspensify: A clone of the suspense demo from Jared Palmer's React Conf talk.
The code is in the examples folder.
Usage
Try it on CodeSandbox
Add the dependency:
$ yarn add hitchcock
Director
Import the Director component and add it somewhere in your app:
import { Director } from "hitchcock"; function YourApp() { return ( <Director> <YourStuff /> </Director> ); }
Lazy
Instead of using React.lazy import lazy from hitchcock:
import { lazy } from "hitchcock"; const HomePage = lazy(() => import("./components/HomePage")); // Hitchcock's lazy accepts a second parameter with the name of the component: const ArtistPage = lazy(() => import("./components/ArtistPage"), "ArtistPage"); // it's optional, but recommended, it isn't always easy to guess the name from the import
createResource
import { createResource } from "hitchcock"; const BeerResource = createResource( id => fetch(`https://api.punkapi.com/v2/beers/${id}`) .then(r => r.json()) .then(d => d[0]), id => `beer-${id}` ); function Beer({ beerId }) { const beer = BeerResource.read(beerId); return ( <> <h1>{beer.name}</h1> <p>{beer.description}</p> </> ); }
createResource has two parameters. The first one is a function that returns a promise. The second one is a function that returns an id, that id is used as the key in the cache and also is used as the name of the resource in the debugger.
It returns a resource with a read method that will suspend a component until the resource is ready (when the promise resolves).
Waterfalls
React docs warn about using Suspense as a way to start fetching data when a component renders. The recommended approach is to start fetching before rendering, for example, in an event handler. Hitchcock doesn't solve this problem, but it provides a preload method if you want to try:
import React, { Suspense } from "react"; import ReactDOM from "react-dom"; import { createResource, Director } from "hitchcock"; const BeerResource = createResource( id => fetch(`https://api.punkapi.com/v2/beers/${id}`) .then(r => r.json()) .then(d => d[0]), id => `beer-${id}` ); function App() { const [beerId, setBeerId] = React.useState(0); const deferredBeerId = React.useDeferredValue(beerId, { timeoutMs: 1000 }); const showBeer = deferredBeerId > 0; const handleChange = e => { const newBeerId = +e.target.value; BeerResource.preload(newBeerId); setBeerId(newBeerId); }; return ( <Director> Beer # <input type="number" value={beerId} onChange={handleChange} /> <Suspense fallback={<div>{`Loading beer #${beerId}...`}</div>}> {showBeer && <Beer beerId={deferredBeerId} />} </Suspense> </Director> ); } function Beer({ beerId }) { const beer = BeerResource.read(beerId); return ( <> <h1>{beer.name}</h1> <p>{beer.description}</p> </> ); } const container = document.getElementById("root"); ReactDOM.createRoot(container).render(<App />);
Contributing
$ git clone git@github.com:pomber/hitchcock.git
$ cd hitchcock
$ npx lerna bootstrapRun the examples:
$ yarn start:example movies $ yarn start:example suspensify
Publish new version:
$ yarn build:packages $ npx lerna publish
License
Released under MIT license.

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.