Differences between ChangeNotifier, StatefulWidget, and ValueNotifier in Flutter for state management

Created At: 2024-05-15 15:56:59 Updated At: 2024-05-16 16:01:35

ChangeNotifier:

  • A base class for managing state that can be listened to by widgets.
  • Holds any type of data (primitive, objects, etc.).
  • Provides the notifyListeners() method to notify listeners (widgets) when the state changes.
  • Offers more control over what triggers notifications.
  • Suitable for managing complex state with multiple properties.

import 'package:flutter/material.dart';

import 'package:provider/provider.dart';

void main() {

  runApp(MyApp());

}

class Counter extends ChangeNotifier {

  int _count = 0;

  int get count => _count;

  void increment() {

    _count++;

    notifyListeners();

  }

 

  void decrement() {

    _count--;

    notifyListeners();

  }

}

 

class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return ChangeNotifierProvider(

      create: (_) => Counter(),

      child: MaterialApp(

        home: CounterScreen(),

      ),

    );

  }

}

 

class CounterScreen extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    final counter = Provider.of(context);

 

    return Scaffold(

      appBar: AppBar(title: Text('ChangeNotifier Example')),

      body: Center(

        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,

          children: [

            Text('Count: ${counter.count}', style: TextStyle(fontSize: 24)),

            Row(

              mainAxisAlignment: MainAxisAlignment.center,

              children: [

                IconButton(

                  icon: Icon(Icons.remove),

                  onPressed: counter.decrement,

                ),

                IconButton(

                  icon: Icon(Icons.add),

                  onPressed: counter.increment,

                ),

              ],

            ),

          ],

        ),

      ),

    );

  }

}

ValueNotifier:

  • A subclass of ChangeNotifier specifically designed for a single value.
  • Holds a single value of a specific type (T).
  • Automatically notifies listeners whenever the value changes.
  • More concise for simple state with just one value.

import 'package:flutter/material.dart';

void main() {

  runApp(MyApp());

}

class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      home: CounterScreen(),

    );

  }

}

 

class CounterScreen extends StatelessWidget {

  final ValueNotifier _counter = ValueNotifier(0);

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(title: Text('ValueNotifier Example')),

      body: Center(

        child: ValueListenableBuilder(

          valueListenable: _counter,

          builder: (context, count, _) {

            return Column(

              mainAxisAlignment: MainAxisAlignment.center,

              children: [

                Text('Count: $count', style: TextStyle(fontSize: 24)),

                Row(

                  mainAxisAlignment: MainAxisAlignment.center,

                  children: [

                    IconButton(

                      icon: Icon(Icons.remove),

                      onPressed: () => _counter.value--,

                    ),

                    IconButton(

                      icon: Icon(Icons.add),

                      onPressed: () => _counter.value++,

                    ),

                  ],

                ),

              ],

            );

          },

        ),

      ),

    );

  }

}

StatefulWidget:

  • A core widget type in Flutter that allows managing internal state.
  • Uses the setState() method to update its state and trigger a rebuild of the widget and its sub-tree.
  • Ideal for managing state that's tightly coupled to a specific widget's behavior.

import 'package:flutter/material.dart';

void main() {

  runApp(MyApp());

}

class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      home: CounterScreen(),

    );

  }

}

class CounterScreen extends StatefulWidget {

  @override

  _CounterScreenState createState() => _CounterScreenState();

}

 

class _CounterScreenState extends State {

  int _count = 0;

  void _increment() {

    setState(() {

      _count++;

    });

  }

 

  void _decrement() {

    setState(() {

      _count--;

    });

  }

 

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(title: Text('StatefulWidget Example')),

      body: Center(

        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,

          children: [

            Text('Count: $_count', style: TextStyle(fontSize: 24)),

            Row(

              mainAxisAlignment: MainAxisAlignment.center,

              children: [

                IconButton(

                  icon: Icon(Icons.remove),

                  onPressed: _decrement,

                ),

                IconButton(

                  icon: Icon(Icons.add),

                  onPressed: _increment,

                ),

              ],

            ),

          ],

        ),

      ),

    );

  }

}

When to Use ChangeNotifier vs. ValueNotifier:

  • Use ChangeNotifier when:
    • You need to manage multiple state properties.
    • You want granular control over when notifications are triggered (e.g., after a specific logic is executed).
    • You're dealing with complex state updates that might involve object mutations or calculations.
  • Use ValueNotifier when:
    • You only need to manage a single state value.
    • You prefer a simpler approach with automatic notifications on value changes.
    • Your state updates are straightforward and don't require custom notification logic.

Additional Considerations:

  • StateNotifier (Flutter Hooks): A newer approach introduced in Flutter hooks that provides a mechanism for managing state with notifiers. It offers a more concise syntax and avoids the need for explicit widget classes. Consider using StateNotifier for simpler state management with ChangeNotifier-like functionality.
  • Provider (State Management Package): A popular package for managing application-level state across widgets. It integrates well with ChangeNotifier or ValueNotifier to provide a centralized state management solution.

In essence:

  • ChangeNotifier: Flexible for complex state with more control.
  • ValueNotifier: Simple for single values with automatic notifications.
  • StatefulWidget: Localized state tightly coupled to a widget's behavior.

Choose the approach that best suits your state management needs based on complexity, control, and desired notification behavior.

Comment

  • r
    ra2886380@gmail.com

    2024-09-12 03:13:34

    Has anyone ever tested REAL performance difference between using Provider/ChangeNotifer with 1 values, vs ValueNotifier on a single value? I am curious, and a beginner so it's not obvious to be how to test such a thing.

    Author response:

    I may try to create one

Add Reviews