Skip to main content

flutter_route_refresh 1.0.0 copy "flutter_route_refresh: ^1.0.0" to clipboard
flutter_route_refresh: ^1.0.0 copied to clipboard

Mark data keys as stale via events and auto-refresh when the screen becomes visible again.

Flutter Route Refresh #

pub package License: MIT

Automatically refresh stale data when users navigate back to a screen.

Flutter Route Refresh solves a common problem in Flutter apps: keeping screen data fresh after navigation. When users navigate away and return, this package automatically refreshes only the data that changed — no manual refresh logic needed.


The Problem #

Screen A (Product List)  →  Screen B (Edit Product)  →  Back to Screen A
        ↓                                                      ↓
   Shows products                                    Still shows OLD data! 😞

Typically, you'd need to manually track state changes, pass callbacks, or use complex state management just to refresh data when returning to a screen.

The Solution #

Screen A (Product List)  →  Screen B (Edit Product)  →  Back to Screen A
        ↓                         ↓                           ↓
   Shows products          Posts "updateProducts"      Auto-refreshes! ✨
                               event

Flutter Route Refresh handles this automatically with a simple event-based system.


Features #

  • Automatic Refresh — Data refreshes automatically when returning to a screen
  • Event-Driven — Mark data as stale via events from anywhere in your app
  • Selective Updates — Only refresh the specific data that changed
  • Type-Safe — Generic types for events and keys prevent runtime errors
  • Lightweight — No external dependencies, minimal footprint
  • Easy Integration — Just add a mixin to your existing StatefulWidgets

Installation #

Add to your pubspec.yaml:

dependencies:
  flutter_route_refresh: ^1.0.0

Then run:

flutter pub get

Quick Start #

1. Initialize the Package #

In your main.dart, create a RouteObserver and initialize the package:

import 'package:flutter/material.dart';
import 'package:flutter_route_refresh/flutter_route_refresh.dart';

final RouteObserver<ModalRoute<void>> routeObserver = RouteObserver<ModalRoute<void>>();

void main() {
  FlutterRouteRefresh.init(routeObserver: routeObserver);
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: [routeObserver], // Don't forget this!
      home: const HomeScreen(),
    );
  }
}

2. Define Your Events and Keys #

Create enums for your events and refresh keys:

// Events that can trigger data refresh
enum AppEvent {
  productUpdated,
  cartModified,
  userProfileChanged,
}

// Keys identifying refreshable data
enum RefreshKey {
  productList,
  cartItems,
  userProfile,
}

3. Add the Mixin to Your Screen #

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen>
    with DirtyKeysRefresher<HomeScreen, AppEvent, RefreshKey> {

  List<Product> products = [];

  @override
  void initState() {
    super.initState();

    // Register refresh callbacks
    registerRefresher(RefreshKey.productList, _fetchProducts);

    // Initial load
    _fetchProducts();
  }

  Future<void> _fetchProducts() async {
    final data = await api.getProducts();
    setState(() => products = data);
  }

  // Map events to the keys that should refresh
  @override
  Map<AppEvent, List<RefreshKey>> get staleEventMap => {
    AppEvent.productUpdated: [RefreshKey.productList],
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Products')),
      body: ListView.builder(
        itemCount: products.length,
        itemBuilder: (context, index) => ProductTile(
          product: products[index],
          onTap: () => Navigator.push(
            context,
            MaterialPageRoute(
              builder: (_) => EditProductScreen(product: products[index]),
            ),
          ),
        ),
      ),
    );
  }
}

4. Post Events When Data Changes #

From any screen, post an event when data is modified:

class EditProductScreen extends StatelessWidget {
  final Product product;

  const EditProductScreen({super.key, required this.product});

  Future<void> _saveProduct(BuildContext context) async {
    await api.updateProduct(product);

    // Notify that product data changed
    GlobalMessenger.instance<AppEvent>().postMessage(AppEvent.productUpdated);

    Navigator.pop(context);
  }

  @override
  Widget build(BuildContext context) {
    // ... your edit form UI
  }
}

That's it! When the user saves and navigates back, the product list automatically refreshes.


API Reference #

FlutterRouteRefresh #

Initialize the package with your route observer.

// Initialize (call once at app startup)
FlutterRouteRefresh.init(routeObserver: yourRouteObserver);

// Check initialization status
bool ready = FlutterRouteRefresh.isInitialized;

// Access the route observer
RouteObserver observer = FlutterRouteRefresh.routeObserver;

DirtyKeysRefresher Mixin #

Add to any State class to enable automatic refresh.

Method Description
registerRefresher(key, callback) Register a refresh callback for a key
unregisterRefresher(key) Remove a registered callback
markStaleKey(key) Manually mark a key as stale
markStaleKeys(keys) Mark multiple keys as stale
unmarkStaleKey(key) Remove a key from the stale set
clearAllStale() Clear all stale keys
Property Description
staleEventMap Override to map events → keys to refresh

GlobalMessenger #

A lightweight event bus for posting events.

// Get the singleton instance for your event type
final messenger = GlobalMessenger.instance<AppEvent>();

// Post an event (notifies all listeners)
messenger.postMessage(AppEvent.productUpdated);

// Manual listener management (usually not needed)
messenger.addListener(AppEvent.productUpdated, myCallback);
messenger.removeListener(AppEvent.productUpdated, myCallback);

Advanced Usage #

Multiple Keys per Event #

Refresh multiple data sources when a single event occurs:

@override
Map<AppEvent, List<RefreshKey>> get staleEventMap => {
  AppEvent.orderPlaced: [
    RefreshKey.cartItems,      // Clear the cart
    RefreshKey.orderHistory,   // Update order list
    RefreshKey.userPoints,     // Update loyalty points
  ],
};

Multiple Events per Key #

The same data can be refreshed by different events:

@override
Map<AppEvent, List<RefreshKey>> get staleEventMap => {
  AppEvent.productUpdated: [RefreshKey.productList],
  AppEvent.productDeleted: [RefreshKey.productList],
  AppEvent.categoryChanged: [RefreshKey.productList],
};

Manual Stale Marking #

Mark data as stale without using events:

// Mark a single key
markStaleKey(RefreshKey.productList);

// Mark multiple keys
markStaleKeys([RefreshKey.productList, RefreshKey.cartItems]);

Architecture #

┌─────────────────────────────────────────────────────────────────┐
│                        Your App                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌──────────────┐    posts event    ┌──────────────────────┐   │
│   │  Screen B    │ ───────────────── │   GlobalMessenger    │   │
│   │  (Editor)    │                   │   (Event Bus)        │   │
│   └──────────────┘                   └──────────┬───────────┘   │
│                                                  │               │
│                                        notifies  │               │
│                                                  ▼               │
│   ┌──────────────┐    route change   ┌──────────────────────┐   │
│   │  Screen A    │ ◄──────────────── │   RouteObserver      │   │
│   │  (List)      │                   │   (Flutter)          │   │
│   │              │                   └──────────────────────┘   │
│   │  with        │                                              │
│   │  DirtyKeys   │ ─── checks stale keys ──┐                    │
│   │  Refresher   │                         │                    │
│   │              │ ◄── executes callbacks ─┘                    │
│   └──────────────┘                                              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Example Use Cases #

Scenario Event Refreshed Data
User edits profile profileUpdated User info, avatar
Item added to cart cartModified Cart count, cart items
New comment posted commentAdded Comments list
Order placed orderPlaced Cart, order history, points
Settings changed settingsChanged Theme, locale, preferences

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

0
likes
150
points
36
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Mark data keys as stale via events and auto-refresh when the screen becomes visible again.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flutter_route_refresh