Skip to main content

v7 - React Native, Web and SSR upgrades and more

· 5 min read
Nathaniel Tucker

Rest Hooks 7

For most people, upgrading to Rest Hooks 7 is as easy as upgrading the packages as long as you aren’t using previously (2 years ago) deprecated exports.

npm install --save rest-hooks@7 @rest-hooks/react@6 @rest-hooks/redux@6 @rest-hooks/test@9 @rest-hooks/[email protected]

The big difference here is all react-specific code has been moved into @rest-hooks/react, which is now a peer dependency of the other packages. The rest-hooks package re-exports everything from @rest-hooks/react.

Upgrade to Rest Hooks 7 guide


Once the rest-hooks package is upgraded, you can optionally upgrade @rest-hooks/react to 7.

npm install --save @rest-hooks/react@7

React Native

Because the React Native and Web interfaces are the same, we ship them in the same package and delivery appropriate specializations where appropriate.

The only breaking change is that useSuspense, useSubscription, useLive, useFetch are all react-native aware. This is unlikely to cause any issue, as screen focus will trigger fetches on stale data.


New additions in 7.1


Newly added guide and utilities specific for making NextJS integration easier.

npm install --save @rest-hooks/ssr @rest-hooks/redux redux
import { RestHooksDocument } from '@rest-hooks/ssr/nextjs';

export default RestHooksDocument;
import { AppCacheProvider } from '@rest-hooks/ssr/nextjs';
import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
return (
<Component {...pageProps} />


See full SSR guide for NextJS


Secure authentication expires at some point. Typically this results in APIs responding with a 401 status. To provide a batteries-included solution for this case, LogoutManager was introduced. It's fully configurable so be sure to check out the docs for more details.

import { CacheProvider, LogoutManager } from '@rest-hooks/react';
import ReactDOM from 'react-dom';

const managers = [new LogoutManager(), ...CacheProvider.defaultProps.managers];

<CacheProvider managers={managers}>
<App />

PR #2293


Often useSubscription() is used in the same components that useSuspense() is. To reduce verbosity we have introduced useLive() which simply calls both useSubscription() and useSuspense().

import { Entity, RestEndpoint } from '@rest-hooks/rest';
export class ExchangeRates extends Entity {
readonly currency: string = 'USD';
readonly rates: Record<string, string> = {};
pk(): string {
return this.currency;
export const getExchangeRates = new RestEndpoint({
urlPrefix: '',
path: '/exchange-rates',
searchParams: {} as { currency: string },
schema: { data: ExchangeRates },
pollFrequency: 15000,
import { useLive } from '@rest-hooks/react';
import { getExchangeRates } from './api/ExchangeRates';
function AssetPrice({ symbol }: Props) {
const { data: price } = useLive(getExchangeRates, {
currency: 'USD',
const displayPrice = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(1 / Number.parseFloat(price.rates[symbol]));
return (
{symbol} {displayPrice}
interface Props {
symbol: string;
render(<AssetPrice symbol="BTC" />);
Live Preview

PR #2287


Suspense and NetworkErrorBoundary are often co-located. To simplify this common case we introduced AsyncBoundary

import { AsyncBoundary } from '@rest-hooks/react';

function App() {
return (
<AnotherRoute />
<TodoDetail id={5} />

PR #2270

Manager.getMiddleware() API changes

Manager middleware has been designed to be compatible with redux. This means the original API had { dispatch, getState } as its arguments to the middleware.

Controller is a superset of this functionality, and its methods provide a more type-safe way of interacting with the flux lifecycle. Because of this we have moved to pass the whole controller, instead of just dispatch, and getState.

class Controller {
/*************** Action Dispatchers ***************/
fetch(endpoint, ...args) => ReturnType<E>;
invalidate(endpoint, ...args) => Promise<void>;
resetEntireStore: () => Promise<void>;
receive(endpoint, ...args, response) => Promise<void>;
receiveError(endpoint, ...args, error) => Promise<void>;
resolve(endpoint, { args, response, fetchedAt, error }) => Promise<void>;
subscribe(endpoint, ...args) => Promise<void>;
unsubscribe(endpoint, ...args) => Promise<void>;
/*************** Data Access ***************/
getResponse(endpoint, ...args, state)=> { data, expiryStatus, expiresAt };
getError(endpoint, ...args, state)=> ErrorTypes | undefined;
snapshot(state: State<unknown>, fetchedAt?: number): SnapshotInterface;
getState(): State<unknown>;

Of course existing Managers just using dispatch and/or getState will continue to work.

PR #2290