react-suspense-fetch
Version:
A low-level library for React Suspense for Data Fetching
167 lines (126 loc) • 5.53 kB
Markdown
[](https://github.com/dai-shi/react-suspense-fetch/actions?query=workflow%3ACI)
[](https://www.npmjs.com/package/react-suspense-fetch)
[](https://bundlephobia.com/result?p=react-suspense-fetch)
[](https://discord.gg/MrQdmzd)
A low-level library for React Suspense for Data Fetching
React 18 comes with Suspense (sort of),
but Suspense for Data Fetching is left for data frameworks.
The goal of this library is to provide a thin API
to allow Suspense For Data Fetching without richer frameworks.
Project status: Waiting more feedbacks before finalizing the API.
## Install
```bash
npm install react-suspense-fetch
```
## Usage
```javascript
import React, { Suspense, useState, useTransition } from 'react';
import { createRoot } from 'react-dom/client';
import { createFetchStore } from 'react-suspense-fetch';
// 1️⃣
// Create a store with an async function.
// The async function can take one input argument.
// The input value becomes the "key" of cache.
// By default, keys are compared with strict equal `===`.
const store = createFetchStore(async (userId) => {
const res = await fetch(`https://reqres.in/api/users/${userId}?delay=3`);
const data = await res.json();
return data;
});
// 2️⃣
// Prefetch data for the initial data.
// We should prefetch data before getting the result.
// In this example, it's done at module level, which might not be ideal.
// Some initialization function would be a good place.
// We could do it in render function of a component close to root in the tree.
store.prefetch('1');
// 3️⃣
// When updating, wrap with startTransition to lower the priority.
const DisplayData = ({ result, update }) => {
const [isPending, startTransition] = useTransition();
const onClick = () => {
startTransition(() => {
update('2');
});
};
return (
<div>
<div>First Name: {result.data.first_name}</div>
<button type="button" onClick={onClick}>Refetch user 2</button>
{isPending && 'Pending...'}
</div>
);
};
// 4️⃣
// We should prefetch new data in an event handler.
const Main = () => {
const [id, setId] = useState('1');
const result = store.get(id);
const update = (nextId) => {
store.prefetch(nextId);
setId(nextId);
};
return <DisplayData result={result} update={update} />;
};
// 5️⃣
// Suspense boundary is required somewhere in the tree.
// We can have many Suspense components at different levels.
const App = () => (
<Suspense fallback={<span>Loading...</span>}>
<Main />
</Suspense>
);
createRoot(document.getElementById('app')).render(<App />);
```
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
fetch store
`prefetch` will start fetching.
`get` will return a result or throw a promise when a result is not ready.
`preset` will set a result without fetching.
`evict` will remove a result.
`abort` will cancel fetching.
There are three cache types:
* WeakMap: `input` has to be an object in this case
* Map: you need to call evict to remove from cache
* Map with areEqual: you can specify a custom comparator
Type: {prefetch: function (input: Input): void, get: function (input: Input, option: GetOptions): Result, preset: function (input: Input, result: Result): void, evict: function (input: Input): void, abort: function (input: Input): void}
* `prefetch` **function (input: Input): void**
* `get` **function (input: Input, option: GetOptions): Result**
* `preset` **function (input: Input, result: Result): void**
* `evict` **function (input: Input): void**
* `abort` **function (input: Input): void**
create fetch store
* `fetchFunc` **FetchFunc\<Result, Input>**
* `cacheType` **CacheType\<Input>?**
* `presets` **Iterable\<any>?**
```javascript
import { createFetchStore } from 'react-suspense-fetch';
const fetchFunc = async (userId) => (await fetch(`https://reqres.in/api/users/${userId}?delay=3`)).json();
const store = createFetchStore(fetchFunc);
store.prefetch('1');
```
The [examples](examples) folder contains working examples.
You can run one of them with
```bash
PORT=8080 npm run examples:01_minimal
```
and open <http://localhost:8080> in your web browser.
You can also try them in codesandbox.io:
[](https://codesandbox.io/s/github/dai-shi/react-suspense-fetch/tree/main/examples/01\_minimal)
[](https://codesandbox.io/s/github/dai-shi/react-suspense-fetch/tree/main/examples/02\_typescript)
[](https://codesandbox.io/s/github/dai-shi/react-suspense-fetch/tree/main/examples/03\_props)
[](https://codesandbox.io/s/github/dai-shi/react-suspense-fetch/tree/main/examples/04\_auth)
[](https://codesandbox.io/s/github/dai-shi/react-suspense-fetch/tree/main/examples/05\_todolist)
[](https://codesandbox.io/s/github/dai-shi/react-suspense-fetch/tree/main/examples/06\_reactlazy)
[](https://codesandbox.io/s/github/dai-shi/react-suspense-fetch/tree/main/examples/07\_wasm)
* [Diving Into React Suspense Render-as-You-Fetch for REST APIs](https://blog.axlight.com/posts/diving-into-react-suspense-render-as-you-fetch-for-rest-apis/)