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
- Yarn
yarn add rest-hooks@7 @rest-hooks/react@6 @rest-hooks/redux@6 @rest-hooks/test@9 @rest-hooks/[email protected]
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.
@rest-hooks/react@7
Once the rest-hooks
package is upgraded, you can optionally upgrade @rest-hooks/react to 7.
- NPM
- Yarn
yarn add @rest-hooks/react@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.
@rest-hooks/react@7.1
New additions in 7.1
- LogoutManager listens for 401 to trigger logout
- useLive() combines useSuspense() with useSubscription()
- <AsyncBoundary/> combines Suspense with NetworkErrorBoundary
- Middleware API gets full controller
- Block dispatches after unmount (#2307)
@rest-hooks/ssr@0.7
Newly added guide and utilities specific for making NextJS integration easier.
- NPM
- Yarn
yarn add @rest-hooks/ssr @rest-hooks/redux redux
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 (
<AppCacheProvider>
<Component {...pageProps} />
</AppCacheProvider>
);
}
Demo
LogoutManager
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.
- React Web 16+
- React Web 18+
- React Native
- NextJS
import { CacheProvider, LogoutManager } from '@rest-hooks/react';
import ReactDOM from 'react-dom';
const managers = [new LogoutManager(), ...CacheProvider.defaultProps.managers];
ReactDOM.render(
<CacheProvider managers={managers}>
<App />
</CacheProvider>,
document.body,
);
import { CacheProvider, LogoutManager } from '@rest-hooks/react';
import ReactDOM from 'react-dom';
const managers = [new LogoutManager(), ...CacheProvider.defaultProps.managers];
ReactDOM.createRoot(document.body).render(
<CacheProvider managers={managers}>
<App />
</CacheProvider>,
);
import { CacheProvider, LogoutManager } from '@rest-hooks/react';
import { AppRegistry } from 'react-native';
const managers = [new LogoutManager(), ...CacheProvider.defaultProps.managers];
const Root = () => (
<CacheProvider managers={managers}>
<App />
</CacheProvider>
);
AppRegistry.registerComponent('MyApp', () => Root);
import { CacheProvider, LogoutManager } from '@rest-hooks/react';
import { AppCacheProvider } from '@rest-hooks/ssr/nextjs';
import type { AppProps } from 'next/app';
const managers = [new LogoutManager(), ...CacheProvider.defaultProps.managers];
export default function App({ Component, pageProps }: AppProps) {
return (
<AppCacheProvider managers={managers}>
<Component {...pageProps} />
</AppCacheProvider>
);
}
useLive
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().
AsyncBoundary
Suspense and NetworkErrorBoundary are often co-located. To simplify this common case we introduced AsyncBoundary
import { AsyncBoundary } from '@rest-hooks/react';
function App() {
return (
<AsyncBoundary>
<AnotherRoute />
<TodoDetail id={5} />
</AsyncBoundary>
);
}
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.