react-suspense-router
v1.0.0-alpha.12
Published
React Router for React Suspense and Render-as-You-Fetch
Downloads
28
Maintainers
Readme
react-suspense-router
React Router for React Suspense and Render-as-You-Fetch
Introduction
The new Render-as-You-Fetch pattern is mind-blowing.
This is an experimental library that combines react-router and some other libraries. You can get the benefit of Render-as-You-Fetch out of the box.
Install
yarn add react-suspense-router
Usage
App.tsx
import React, { Suspense } from 'react';
import { BrowserRouter } from 'react-suspense-router';
import Nav from './Nav';
import MyRoutes from './MyRoutes';
const App: React.FC = () => (
<BrowserRouter timeout={1000}>
<Nav />
<Suspense fallback={<div>Loading...</div>}>
<MyRoutes />
</Suspense>
</BrowserRouter>
);
export default App;
Nav.tsx
import React from 'react';
import { Link, useLocationPending } from 'react-suspense-router';
const Nav: React.FC = () => {
const isPending = useLocationPending();
return (
<div>
<div style={{ position: 'absolute', top: 0 }}>{isPending && 'Pending...'}</div>
<ul style={{ marginTop: 20 }}>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/user/1">User 1</Link>
</li>
<li>
<Link to="/user/2">User 2</Link>
</li>
</ul>
</div>
);
};
export default Nav;
Routes.tsx
import React from 'react';
import { Route, Routes, FetchDataLazy } from 'react-suspense-router';
const Index = React.lazy(() => import('./pages/Index'));
const User = React.lazy(() => import('./pages/User'));
const fetchUserData = FetchDataLazy(() => import('./pages/User.data'));
const MyRoutes: React.FC = () => (
<Routes>
<Route exact path="/">
<Index />
</Route>
<Route path="/user/:uid" fetchData={fetchUserData}>
<User />
</Route>
</Routes>
);
export default MyRoutes;
pages/Index.tsx
import React from 'react';
const Index: React.FC = () => (
<div>
<h1>Index</h1>
<p>Hello World</p>
</div>
);
export default Index;
pages/User.tsx
import React from 'react';
import { useParams, useRouteData } from 'react-suspense-router';
import { UserData } from './User.data';
const FirstName: React.FC = React.memo(() => {
const userData = useRouteData() as UserData;
return (
<div>
<h2>First Name</h2>
<div>{userData.data.first_name}, random={Math.random()}</div>
</div>
);
});
const User: React.FC = () => {
const { uid } = useParams();
return (
<div>
<h1>User</h1>
<div>uid: {uid}, random={Math.random()}</div>
<FirstName />
</div>
);
};
export default User;
pages/User.data.ts
import { Match } from 'react-suspense-router';
export type UserData = {
data: {
id: number;
email: string;
first_name: string;
last_name: string;
avatar: string;
};
};
const fetchUserData = async (match: Match) => {
const userId = match.params.uid;
const response = await fetch(`https://reqres.in/api/users/${userId}`);
const data = await response.json();
return data as UserData;
};
export default fetchUserData;
API
Routes
Routes for Suspense Render-as-You-Fetch
Its usage is the same with react-router,
except that Route accepts fetchData
prop.
Specify a function created by FetchData or FetchDataLazy.
Examples
import { Routes, Route } from 'react-suspense-router';
const MyRoutes = () => (
<Routes>
<Route path="/" element={<Index />} />
<Route path="/double/:number" element={<Double />} fetchData={fetchDouble} />
</Routes>
);
useRoutes
useRoutes for Suspense Render-as-You-Fetch
Its usage is the same with react-router,
except that Route accepts fetchData
prop.
Specify a function created by FetchData or FetchDataLazy.
FetchData
FetchData
This will wrap an async function and create fetchData
that canbe passed to fetchData
prop in .
Examples
import { FetchData, Route } from 'react-suspense-router';
const fetchDouble = FetchData(async (match) => {
await sleep(1000);
return { result: match.params.number * 2 };
});
<Route path="..." element={...} fetchData={fetchDouble} />
FetchDataLazy
FetchDataLazy
This is lazy loading version of FetchData. It will be used like React.lazy, but for route data.
Examples
import { FetchDataLazy, Route } from 'react-suspense-router';
const fetchUserData = FetchDataLazy(() => import('./pages/User.data'));
<Route path="..." element={...} fetchData={fetchUserData} />
useRouteData
useRouteData hook
This will return route data in components inside a route. It utilizes proxy-based tracking by React Tracked.
Examples
import { useRouteData } from 'react-suspense-fetch';
const FirstName = () => {
const userData = useRouteData();
return <div>userData.firstName</div>
};
useRouteDataSelector
useRouteDataSelector hook
This will return route data in components inside a route. It takes a selector function. Use this if proxy-based tracking doesn't work.
Examples
import { useRouteDataSelector } from 'react-suspense-fetch';
const selectFirstName = data => data.firstName;
const FirstName = () => {
const firstName = useRouteDataSelector(selectFirstName);
return <div>firstName</div>
};
Examples
The examples folder contains working examples. You can run one of them with
PORT=8080 yarn run examples:01_minimal
and open http://localhost:8080 in your web browser.