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

ActionWhat Happens?
User presses BackPage navigates back, and form data is lost.
User presses ForwardPage restores, but form fields are empty.
User refreshes the pageEntire 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?

ScenarioWhat 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. 🚀