jio_provider 1.0.2 copy "jio_provider: ^1.0.2" to clipboard
jio_provider: ^1.0.2 copied to clipboard

Simple light weight provider inherited widget, basic, multi, eager and lazy jio providers.

example/lib/main.dart

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

void main() {
  debugPrintRebuildDirtyWidgets = false; // πŸ‘ˆ enables rebuild logging
  // runApp(BasicJioProvider(notifier: ExpenseViewModel(), child: const MyApp()));

  runApp(
    MultiJioProvider(
      providers: [
        // βœ… Lazy β€” created only when used <-- created only when first used (with LAZY loading)
        // βœ… App startup is faster πŸš€  βœ… Memory usage is lower πŸ’Ύ
        //----------------New version-------------------
        // LazyJioUniversalProvider<ExpenseViewModel>(() async {
        //   await Future.delayed(const Duration(seconds: 2));
        //   return ExpenseViewModel();
        // }),
        // LazyJioUniversalProvider<CounterViewModel>(() async {
        //   await Future.delayed(const Duration(seconds: 2));
        //   return CounterViewModel();
        // }),
        //----------------Old version-------------------
        LazyJioProvider<ExpenseViewModel>(
          () => ExpenseViewModel(),
          autoDispose: false,
        ),
        // πŸ‘ˆ Keeps state alive even after screen pop
        LazyJioProvider<CounterViewModel>(() => CounterViewModel()),
        //-----------------------------------------------
        // βœ… Eager β€” created immediately
        EagerJioProvider<TodoViewModel>(notifier: TodoViewModel()),
      ],
      child: const MyApp(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DashboardView(),
    );
  }
}

//=====================COUNTER==================
class CounterViewModel extends JioNotifier {
  bool _option = false;
  int _count = 0;

  // Private constructor
  CounterViewModel._();

  // Public accessor
  // Factory constructor
  factory CounterViewModel() => _instance;

  // Single static instance
  static final CounterViewModel _instance = CounterViewModel._();

  bool get option => _option;

  int get count => _count;

  void changeOption() {
    _option = !_option;
    notifyListeners();
  }

  void increment() {
    _count++;
    notifyListeners();
  }

  @override
  void dispose() {
    debugPrint('πŸ—‘οΈ CounterViewModel disposed');
    super.dispose();
  }
}

class CounterView extends StatelessWidget {
  static int _buildCount = 0;

  const CounterView({super.key});

  @override
  Widget build(BuildContext context) {
    _buildCount++;
    debugPrint('πŸ” Counter built $_buildCount times');
    // final counter = JioProvider.of<CounterViewModel>(context); // OK | OK for small app
    // rebuilds on change : use it in separate widget
    final counter = context.watch<CounterViewModel>();

    return Scaffold(
      appBar: AppBar(title: Text(counter.option ? 'OPTION1' : 'OPTION2')),
      body: Column(
        children: [
          Center(
            child: Row(
              children: [
                ElevatedButton(
                  onPressed: () =>
                      context.read<CounterViewModel>().changeOption(),
                  child: Text('OPTIONS'),
                ),
              ],
            ),
          ),
          Center(
            child: Text(
              'Count: ${counter.count}',
              style: const TextStyle(fontSize: 28),
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: context.read<CounterViewModel>().increment, // no rebuild
        child: const Icon(Icons.add),
      ),
    );
  }
}

//=====================TO DO==================
class TodoViewModel extends JioNotifier {
  final List<String> _todos = [];

  List<String> get todos => List.unmodifiable(_todos);

  void addTodo() {
    _todos.add("Task ${_todos.length + 1}");
    notifyListeners(); // πŸ”₯ Triggers rebuild for watchers
  }

  int get count => _todos.length;
}

class TodoView extends StatelessWidget {
  static int _buildCount = 0;

  const TodoView({super.key});

  @override
  Widget build(BuildContext context) {
    _buildCount++;
    debugPrint('πŸ” TodoList built $_buildCount times');
    // βœ… This part WATCHES the ViewModel β†’ rebuilds when todos change
    final todos = context.watch<TodoViewModel>().todos;

    return Scaffold(
      appBar: AppBar(
        title: const Text('Todo Demo'),
        actions: [
          // ❌ This part READS only β†’ does NOT rebuild when state changes
          Padding(
            padding: const EdgeInsets.all(16),
            child: Center(
              child: Text(
                "Total: ${context.read<TodoViewModel>().count}",
                style: const TextStyle(fontSize: 16),
              ),
            ),
          ),
        ],
      ),
      body: ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) => ListTile(title: Text(todos[index])),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // βœ… Use READ because we don't want to rebuild this FAB widget
          context.read<TodoViewModel>().addTodo();
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

//=====================EXPENSE==================
class ExpenseViewModel extends JioNotifier {
  final List<String> _txn = [];

  List<String> get txs => _txn;

  int get total => _txn.length;

  void addTxn(int limit) {
    for (var i = 0; i < limit; i++) {
      _txn.add('Txn: $i | Balance: β‚Ή${total + i}');
    }
    notifyListeners();
  }
}

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

  @override
  Widget build(BuildContext context) {
    debugPrint("🧱 Dashboard rebuilt");

    // final expense = context.jioWatch<ExpenseViewModel>(); // πŸ‘ˆ BIG MISTAKE!

    return Scaffold(
      appBar: AppBar(title: Text("Dashboard")),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: [
          _HeaderSection(userName: "Jiocoders"), // ❌ Static β†’ no watch
          Divider(),
          _BalanceCard(), // βœ… Dynamic β†’ watch
          Divider(),
          _RecentTransactions(), // βœ… Dynamic β†’ watch
          Divider(),
          _FooterSection(), // ❌ Static β†’ no watch
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          context.read<ExpenseViewModel>().addTxn(10);
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

class _HeaderSection extends StatelessWidget {
  const _HeaderSection({required this.userName});

  final String userName;

  @override
  Widget build(BuildContext context) {
    return RebuildLogger(label: 'Header', child: Text("Welcome $userName"));
  }
}

class _BalanceCard extends StatelessWidget {
  const _BalanceCard();

  @override
  Widget build(BuildContext context) {
    final total = context.watch<ExpenseViewModel>().total;
    return RebuildLogger(
      label: 'Balance',
      child: Text("Total Balance: β‚Ή$total"),
    );
  }
}

class _RecentTransactions extends StatelessWidget {
  const _RecentTransactions();

  @override
  Widget build(BuildContext context) {
    final txs = context.watch<ExpenseViewModel>().txs;
    return RebuildLogger(
      label: 'Txn',
      child: Expanded(
        child: ListView.builder(
          itemCount: txs.length,
          itemBuilder: (context, index) => Center(child: Text(txs[index])),
        ),
      ),
    );
  }
}

class _FooterSection extends StatelessWidget {
  const _FooterSection();

  @override
  Widget build(BuildContext context) {
    return RebuildLogger(label: 'Footer', child: Text("All rights reserved"));
  }
}

/// =====================REBUILD LOGGER==================
/// A debug-only widget to track rebuilds of any widget.
///
/// Usage:
/// ```dart
/// RebuildLogger(
///   label: "BalanceCard",
///   child: BalanceCard(),
/// )
/// ```
class RebuildLogger extends StatelessWidget {
  final String label;
  final Widget child;

  const RebuildLogger({super.key, required this.label, required this.child});

  @override
  Widget build(BuildContext context) {
    // πŸ”Ž This print runs every time the widget rebuilds
    debugPrint("πŸ” Widget Rebuilt: $label");

    return child;
  }
}

/// =====================REBUILD LOGGER END==================
1
likes
160
points
289
downloads
screenshot

Publisher

unverified uploader

Weekly Downloads

Simple light weight provider inherited widget, basic, multi, eager and lazy jio providers.

Repository (GitHub)
View/report issues
Contributing

Topics

#state-management #jio-provider #multi-jio-provider #eager-jio-provider #lazy-jio-provider

Documentation

Documentation
API reference

Funding

Consider supporting this project:

jiocoders.com

License

MIT (license)

Dependencies

flutter

More

Packages that depend on jio_provider