Release Notes
Notable changes in each release of @rhino-dev/rhino-react, newest first. The same package serves
React and React Native.
4.7.0
The hooks can be called straight from a React Native component, with no wrapper layer. Polling, dependent queries, file uploads, "load more" lists and prefix route groups previously needed app-side code around the hooks; they are now part of the hooks themselves.
const { data: trip } = useModelShow<Trip>('trips', tripId, {}, { refetchInterval: 5000 });
const stops = useModelInfinite<Stop>(
'stops',
{ filters: { trip_id: trip?.id }, perPage: 20 },
{ enabled: !!trip },
);
const items = stops.data?.pages.flatMap((page) => page.data) ?? [];
Added
| Addition | Where |
|---|---|
Trailing queryOptions on useModelIndex, useModelShow, useModelTrashed, useModelComputedAttributes, useModelAudit. enabled is AND-ed with the hook's own guard, and select flows into the return type. | TanStack Query Options |
Trailing mutationOptions on useModelStore, useModelUpdate, useModelDelete, useModelRestore, useModelForceDelete, useNestedOperations. The built-in invalidation runs before your onSuccess. | Mutation options |
FormData bodies on useModelStore / useModelUpdate. An update is a multipart POST with X-HTTP-Method-Override: PUT. | File Uploads |
useModelInfinite, which accumulates pages from the pagination headers. Every mutation that invalidates a model's lists invalidates its infinite lists too. | Infinite Scroll |
tenancy: 'none' and routeGroupInDataPath, for prefix route groups with or without an organization. | Tenancy and Data URLs |
configureApi({ timeout, withCredentials, nestedPath }) | configureApi |
buildModelUrl, modelKeys, fetchModelIndex, fetchModelShow, for code that runs outside React. The hooks are built on them. | Outside React |
LoginResult.token, STORAGE_KEYS | LoginResult, Keys Used Internally |
Fixed
- The token is in storage when
login()resolves. It used to be written after the next render, so a request made right afterawait login()went out without anAuthorizationheader. - React Native:
initStorage()restoresroute_group, so a group-aware session comes back in the group it signed into after an app restart. useNestedOperationsposts to/nested, the endpoint the Laravel, Rails and NestJS servers register by default. It used to post to/nested-operations, which a default server answers with 404.useOwner,useUserRoleanduseOrganizationExistsread the{ data: [...] }response envelope. Against a current serveruseOwner()returned the envelope itself andhasRole()was alwaysfalse.login()notifies hooks that are already mounted and stores the configured route group. Data hooks mounted before the login start fetching when it resolves, and a group set throughconfigureApi({ routeGroup })reachesuseRouteGroup().- The default 401 handler no longer throws on React Native when no
onUnauthorizedis configured.
Upgrading from 4.6
No code changes are required: with no new option passed, URLs, request bodies and query keys are the same as in 4.6, with the one exception of the nested-operations URL above. Every addition is an optional argument or a new export.
- A 401 also resets
AuthProviderand clearsuser. In 4.6 onlytokenwas removed from storage andisAuthenticatedstayedtrueuntil the provider remounted. If your app mirrored auth state in its own store to work around that, the mirror can go. On the web, signing in or out in one browser tab now updatesuseAuth()in the other tabs of the same origin. - A rejected login no longer calls
onUnauthorized. A 401 from the login endpoint is reported bylogin()({ success: false, status: 401 }) and leaves storage alone. useRegisterstarts a session. When the backend returns a token it is stored with the user and organization, andAuthProviderbecomes authenticated. Alogin()call after registering is no longer needed.useNestedOperationsposts to/nested. If you set the server's nestedpathtonested-operationsto match the old client, passconfigureApi({ nestedPath: 'nested-operations' }).
On React Native, bearer-token apps can drop any api.defaults mutation in favor of
configureApi({ withCredentials: false, timeout: 20_000 }). See
React Native — Getting Started.