Clearing Riverpod provider caches efficiently on logout
Keep one provider whose value changes on logout, have every other provider watch it during initialisation, and forgetting to clear something stops being possible.
- Published
This article is also published elsewhere. https://iganin.hatenablog.com/entry/2021/09/02/233939
Originally written in Japanese. This is a translation of the same piece.
TL;DR
- Create a provider whose value changes on logout, and watch that provider in every other provider’s initialisation
Environment
[✓] Flutter (Channel stable, 2.2.3, on macOS 11.3.1 20E241 darwin-x64, locale ja-JP)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] IntelliJ IDEA Ultimate Edition (version 2021.1.2)
[✓] VS Code (version 1.59.1)
hooks_riverpod: 0.14.0+4
Motivation
For security reasons, you want local data gone at logout.
Suppose a user logs out and signs back in with a different account, and data from the previous account is still there. Seeing another account’s data on screen is obviously unwanted — but worse, that data can ride along on a POST or similar request and end up mixed into the backend’s data.
So at logout you want the local database cache and any in-memory cache cleared. Below I think through an efficient way to clear Riverpod provider caches.
Clearing the Riverpod cache
The naive approach that comes to mind is to add a clear method to each ChangeNotifierProvider or
StateNotifierProvider, reset the data, and put the initial value back for things like StateNotifier.
But writing that method over and over is tedious, and it looks like exactly the sort of thing where adding a
property later means forgetting to update the clear method.
One alternative is to create a provider whose value is rewritten at logout, and to watch that provider when each provider initialises.
final logoutProvider = StateProvider<DateTime?>((ref) => null);
final sampleProvider = StateProvider<String?>((ref) {
ref.watch(logoutProvider);
return null;
});
For simplicity I made the provider hold the logout timestamp as its value. There are plenty of other
options — the signed-in user’s information, for instance. With this in place, the moment a new value lands
in logoutProvider’s state, sampleProvider re-initialises and its current value is discarded.
What I like about this approach is that it re-runs the initialisation without needing any special handling.
If your initialisation fetches data from a database, the initial value depends on what is in that database —
but if you clear the database at logout and then change logoutProvider’s value, you no longer have to
think about the database contents at all, which is convenient.
The thing to watch when designing the overall flow is to clear the database and in-memory cache before
changing logoutProvider’s value. If a provider’s initialisation reads from the database or memory,
re-creating the provider would just pull the old data back out again — not what you want.
Closing
Handling local data at logout tends to be more of a chore than it looks. I hope this helps a little.