Chapter 6A: Gracefully Handling Navigation with Riverpod in Flutter Web
Introduction
Navigation is more than just moving between screens; it involves handling state persistence, user intent, and browser behavior effectively. In Flutter Web, navigation is managed through go_router
, but without proper state management, users may lose critical data when switching screens, refreshing the page, or using the browser’s back and forward buttons.
This chapter explores how to: ✅ Ensure new screens fetch necessary data gracefully with Riverpod.
✅ Handle back/forward button navigation while maintaining UI state.
✅ Prevent data loss by using state management and local storage.
1️⃣ Fetching Data on New Screens Gracefully
When navigating between screens, the newly opened page often needs to fetch and display relevant data. Without proper state management, data fetching may result in duplicate API calls or loss of in-memory state.
🔹 Solution: Use FutureProvider
to Fetch Data Dynamically
Instead of re-fetching data on every navigation event, use FutureProvider
to cache and manage API calls efficiently.
Scenario: A User Profile Page Fetching Data on Navigation
Without Riverpod: API is called every time the user navigates to the profile page.
With Riverpod: API is called only when needed, and cached for performance.
✅ Example: Using FutureProvider
to Fetch User Data Efficiently
final userProfileProvider = FutureProvider.family<User, String>((ref, userId) async {
return fetchUserProfile(userId); // API call to fetch user data
});
On the Profile Page:
final userProfile = ref.watch(userProfileProvider(userId));
userProfile.when(
data: (user) => Text("Welcome, ${user.name}"),
loading: () => CircularProgressIndicator(),
error: (e, _) => Text("Error loading profile"),
);
✅ Ensures data is only fetched once and reused when navigating back.
2️⃣ Handling Browser Back & Forward Button Navigation
🔹 Scenario: A User Presses the Back Button While Filling a Form
By default, go_router
does not prevent users from accidentally navigating away, leading to potential data loss.
❌ Default Behavior Without State Management
Action | What Happens? |
User presses Back | Page navigates back, and form data is lost. |
User presses Forward | Page restores, but form fields are empty. |
User refreshes the page | Entire app reloads, and state is lost. |
To solve this, we can intercept navigation actions and persist form data.
3️⃣ Preventing Data Loss in Navigation
🔹 Solution 1: Warn the User Before Leaving a Page
Use go_router
's redirect
method to display a confirmation prompt before navigation.
GoRoute(
path: '/form',
builder: (context, state) => FormPage(),
redirect: (context, state) {
if (isFormDirty) { // Check if form has unsaved data
return '/confirm-exit';
}
return null; // Allow navigation
},
);
✅ Prevents accidental navigation by prompting the user.
🔹 Solution 2: Use Riverpod to Persist Form Data
Instead of relying on the UI state, use StateProvider
to retain form input.
final formDataProvider = StateProvider<Map<String, String>>((ref) => {});
On the Form Page:
final formData = ref.watch(formDataProvider);
TextField(
controller: TextEditingController(text: formData["name"] ?? ""),
onChanged: (value) {
ref.read(formDataProvider.notifier).state = {"name": value};
},
);
✅ Even if the user navigates back and returns later, the form data remains.
🔹 Solution 3: Store Data in Browser Local Storage
For persistent data retention even after a page refresh, use window.localStorage
.
import 'dart:html'; // Flutter Web Only
void saveFormData(String key, String value) {
window.localStorage[key] = value;
}
String? loadFormData(String key) {
return window.localStorage[key];
}
✅ Ensures data persists even after page refresh or browser restarts.
🚀 Final Answer: What Will Happen in Different Scenarios?
Scenario | What Happens? |
User presses Back (Default Behavior) | ❌ Page goes back, data is lost. |
User presses Back (Using Redirect) | ✅ Shows a warning before leaving. |
User reopens the form (Using Riverpod) | ✅ Data is restored automatically. |
User refreshes the page (Using Local Storage) | ✅ Data remains even after refresh. |
Conclusion
Handling navigation effectively in Flutter Web requires more than just switching between screens. Using Riverpod and go_router
, developers can persist UI state, intercept navigation events, and retain user data across page transitions.
By implementing these solutions, Flutter Web apps can offer a seamless, user-friendly experience, preventing accidental data loss and improving navigation performance. 🚀