Fix <Edit>, <ReferenceField> and <List> to better support offline mode#11161
Fix <Edit>, <ReferenceField> and <List> to better support offline mode#11161fzaninotto wants to merge 20 commits intomasterfrom
<Edit>, <ReferenceField> and <List> to better support offline mode#11161Conversation
<Edit>, <ReferenceField> and <List> to better support offline mode
| const getRecordRepresentation = useGetRecordRepresentation(reference); | ||
|
|
||
| if (error) { | ||
| if (error && referenceRecord == null) { |
There was a problem hiding this comment.
When the app is online and a cached referenceRecord exists, it can hide real API errors
// Potencial Fix
if (error && (referenceRecord == null || !referenceFieldContext.isPaused)) {There was a problem hiding this comment.
That's a good point but isPaused is not guaranteed to reflect the actual connectivity status all the time (it can take some time for the device to actually mark the connectivity status as offline in real-life conditions).
Besides, it can be argued that displaying the reference record is more useful to the user than displaying only the error, even if the data is not fresh.
Alternatively, we could also introduce a prop to let the user decide ultimately (just like we have a redirectOnError prop on <Edit> that can be set to false)...
@fzaninotto wdyt?
There was a problem hiding this comment.
We're using the stale-while-revalidate approach heavily in react-admin, the idea being that the SPA architecture allows apps to be more useful to the user. Besides, there is still the possibility to both show the stale data and an error notification by using queryOptions.onError . So I think we can go with if (error && referenceRecord == null) { here.
| @@ -0,0 +1,26 @@ | |||
| # ra-offline | |||
|
|
|||
There was a problem hiding this comment.
deserves a one line explanation of the demo puropse and usage
examples/ra-offline/package.json
Outdated
| "@tanstack/query-async-storage-persister": "^5.90.22", | ||
| "@tanstack/react-query": "^5.90.21", | ||
| "@tanstack/react-query-persist-client": "^5.90.22", | ||
| "ra-core": "^5.14.1", |
There was a problem hiding this comment.
not necessary (ra-ui-mui neither)
examples/ra-offline/src/Layout.tsx
Outdated
| export const Layout = ({ children }: { children: ReactNode }) => ( | ||
| <RALayout> | ||
| {children} | ||
| <CheckForApplicationUpdate /> |
There was a problem hiding this comment.
unnecessary. But we'd benefit from the react query dev tools
examples/ra-offline/src/PostList.tsx
Outdated
| @@ -0,0 +1,14 @@ | |||
| import { DataTable, List, ReferenceField } from "react-admin"; | |||
There was a problem hiding this comment.
no difference with a ListGuesser, we should remove it
| <title>My Awesome App</title> | ||
| <meta name="description" content="My Awesome App description" /> | ||
| <link rel="icon" href="/favicon.ico" /> | ||
| <link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png" sizes="180x180" /> |
There was a problem hiding this comment.
we can simplify by removing the favicons and loading css
examples/ra-offline/package.json
Outdated
| "react": "^19.0.0", | ||
| "react-admin": "^5.14.1", | ||
| "react-dom": "^19.0.0", | ||
| "react-router": "^7.1.3", |
There was a problem hiding this comment.
same, not sure it's required
examples/ra-offline/package.json
Outdated
| "eslint-plugin-react": "^7.37.4", | ||
| "eslint-plugin-react-hooks": "^5.2.0", | ||
| "globals": "^16.0.0", | ||
| "https-localhost": "^4.7.1", |
| languageName: node | ||
| linkType: hard | ||
|
|
||
| "@rollup/pluginutils@npm:^3.1.0": |
There was a problem hiding this comment.
some duplicates here, can we avoid them?
There was a problem hiding this comment.
Not they are not duplicates, the major version is different (5 vs 3).
We can't avoid the two versions as one is needed by astro and the other one by the vite pwa plugin.
I already ran yarn dedupe btw so they should not remain any duplicates.
examples/ra-offline/package.json
Outdated
| "dev": "vite", | ||
| "build": "vite build", | ||
| "preview": "vite preview", | ||
| "serve": "REINSTALL=true PORT=4433 serve dist", |
There was a problem hiding this comment.
make serve-offline fails
serve Should be install in devDependencies
There was a problem hiding this comment.
Actually I kept this command since it was added by @djhi and figured it was probably useful to force reinstalling the PWA on a real mobile device or something similar. But in the end, I did not use this command, force-reinstalling the PWA is easy enough to do with the desktop browser devtools (and on mobile device you can always remove and reinstall the app), so since it doesn't work I guess I'll simply remove it.
There was a problem hiding this comment.
Other than the requested changes, I tested both in development and production (make build-offline + make preview-offline): offline behavior works as expected, including cached navigation/edit flows and mutation replay when reconnecting. Looks good to me.
Good Job 💪
examples/ra-offline/index.html
Outdated
| <link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png" sizes="180x180" /> | ||
| <link rel="mask-icon" href="/maskable-icon-512x512.png" color="#FFFFFF" /> | ||
| <meta name="theme-color" content="#ffffff" /> | ||
| <title>ra-offline</title> |
Problem
Offline apps behave in a strange way, sometimes showing error pages even though they should not.
The offline mode of TanStack Query works fine in a standalone example, so the problems come from react-admin.
We lack a way to properly test offline mode, particularly in the context of a PWA.
Additional specific issues found:
<Edit>ignores theredirectOnErrorprop, making it hard to disable the redirection to the list in case of error (even if there's data in the cache)<ReferenceField>renders an error message even if the reference record is available in the cache<ListView>hides the pagination as soon as a fetch error occurs, preventing the user to go back to a page for which cached data are presentSolution
Build a demo (with Vite PWA plugin), track down the issues and fix them.
When offline, all calls to useQuery return an error... but they also return data.
In a nutshell, we must not only check for errors before deciding to show/return things but also that no data is available for offline support to work correctly
If we have a NetworkError and valid data, it means we're offline and that TanStack query returned stale data.
How To Test
make build-offlinemake preview-offline(the offline mode doesn't work in dev mode, that's a limitation of vite-pwa)
Use the DevTools to simulate Offline mode when needed.
The PWA should be able to fetch data from the cache, even when reloading the whole app while offline (thanks to the service worker and the TanStack query Persister).
Known issue: TanStack query discards the cached data if you reload the app 2 times. See related issue.
The PWA should allow to perform mutations while offline, and replay the mutations when back online.
Note: Since this demo is hooked up to JSONPlaceholder API, the changes are not persisted for real. But the mutation should be visible in the Network tab and not trigger errors.
Additional Checks
masterfor a bugfix or a documentation fix, ornextfor a feature