Flutter - Using ValueListenableBuilder Widget Examples

This tutorial shows you how to use the ValueListenableBuilder widget in Flutter.

In an application, sometimes you may need to display a component whose content must always be updated when a value changes. Creating such a component or widget in Flutter can be done easily by using the ValueListenableBuilder widget. It's a widget whose content stays synced with a ValueListenable. Below are the usage examples.

Using ValueListenableBuilder

The constructor of ValueListenableBuilder can be seen below.

  ValueListenableBuilder({
    Key? key,
    required ValueListenable valueListenable,
    required Widget Function(BuildContext, T, Widget?) builder,
    Widget? child,
  })

The constructor has two required arguments. The first one is valueListenable, which is used to pass a ValueListenable to which the widget depends on. ValueListenable is an interface for subclasses of Listenable that expose a getter named value. The second one is builder, which is used to build a widget based on the current value.

The ValueListenable is an abstract class. That means you need to use a non-abstract class to create the instance. Flutter provides a class called ValueNotifier, which is an extension of ChangeNotifier that implements ValueListenable. It's suitable for cases where there is a single value.

For the builder argument, you have to pass a function that returns a Widget. The function has three parameters. The first parameter is the BuildContext of the ValueListenableBuilder widget. The second parameter is the current value whose type depends on the value type of the ValueListenable instance. The last parameter is the Widget passed as the child argument which can be useful if there's a widget subtree that doesn't depend on the value of the ValueListenable.

  class MyPageState extends State<MyPage> {
  
    final ValueNotifier<int> _counter = ValueNotifier<int>(0);
  
    @override
    Widget build(BuildContext context) {
      return SizedBox(
        width: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ValueListenableBuilder(
              valueListenable: _counter,
              builder: (BuildContext context, value, Widget? child) {
                return Column(
                  children: [
                    Text('COUNTER'),
                    Text('$value'),
                  ],
                );
              },
            ),
            OutlinedButton(
              onPressed: () {
                _counter.value += 1;
              },
              child: const Text('Increment'),
            ),
          ],
        ),
      );
    }
  }

In the example above, the widget subtree that displays the 'COUNTER' text doesn't depend on the value of the ValueListenable. However, it will be rebuilt every time the value changes. In the case above, to prevent unnecessary rebuilds, you can add a const when creating the 'COUNTER' text widget. But let's assume we have a more complex widget that doesn't have a const constructor. The unnecessary rebuilds can be prevented by passing the widget as the child argument of the ValueListenableBuilder. That makes the widget passed as the third argument of the builder function.

  ValueListenableBuilder(
    valueListenable: _counter,
    builder: (BuildContext context, value, Widget? child) {
      return Column(
        children: [
          child!,
          Text('$value'),
        ],
      );
    },
    child: const Text('COUNTER'),
  )

Summary

ValueListenableBuilder is a widget that allows its content to always stay synced with a ValueListenable. To use it, you need to pass a ValueListenable that the widget will listen to. To return a widget to be rendered, you have to pass a builder function that will be invoked when the value changes.

You can also read about.