Understanding ValueNotifier and ValueListenableBuilder in Flutter

Kashif Ahmed Siddiqui
4 min readNov 30, 2024

--

Flutter provides various tools for state management, ranging from simple solutions like setState to advanced ones like Provider, Riverpod, and Bloc. However, for lightweight and reactive state management, ValueNotifier and ValueListenableBuilder are efficient and easy-to-use options.

In this article, we’ll explore ValueNotifier and ValueListenableBuilder, understand their roles, and learn how they can simplify state management in Flutter apps.

1. What is ValueNotifier?

ValueNotifier is a special type of ChangeNotifier in Flutter. It allows you to hold a single piece of data and notify listeners whenever the value changes.

Key Features

  • Lightweight and simple.
  • Efficient for managing a single value.
  • Automatically notifies listeners when the value is updated.

How to Use ValueNotifier?

Here’s a simple example to demonstrate ValueNotifier:

ValueNotifier<int> counter = ValueNotifier<int>(0);

void incrementCounter() {
counter.value++;
}

In the example above:

  • counter holds the current value.
  • Updating counter.value triggers notifications to all listeners.

2. What is ValueListenableBuilder?

ValueListenableBuilder is a widget that listens to a ValueNotifier or any ValueListenable. It rebuilds its child whenever the ValueNotifier’s value changes.

Key Features

  • Reactive: Automatically rebuilds UI when the value changes.
  • Declarative: Fits well with Flutter’s reactive programming model.
  • Simple to use with ValueNotifier.

3. Using ValueNotifier with ValueListenableBuilder

To see how these two work together, let’s build a simple counter app:

Step 1: Define a ValueNotifier

Create a ValueNotifier to hold the counter value:

ValueNotifier<int> counter = ValueNotifier<int>(0);

Step 2: Create a UI with ValueListenableBuilder

Use ValueListenableBuilder to reactively display the counter value:

class CounterApp extends StatelessWidget {
final ValueNotifier<int> counter = ValueNotifier<int>(0);

void incrementCounter() {
counter.value++;
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('ValueNotifier Example')),
body: Center(
child: ValueListenableBuilder<int>(
valueListenable: counter,
builder: (context, value, child) {
return Text(
'Counter Value: $value',
style: TextStyle(fontSize: 24),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: incrementCounter,
child: Icon(Icons.add),
),
);
}
}

4. How Does It Work?

  1. The ValueNotifier (counter) holds the value and notifies listeners when updated.
  2. ValueListenableBuilder listens to the ValueNotifier.
  3. When counter.value changes, the ValueListenableBuilder rebuilds the Text widget.

5. Practical Use Cases

a) Dynamic Theme Switching

Use ValueNotifier to toggle between light and dark themes:

ValueNotifier<bool> isDarkTheme = ValueNotifier<bool>(false);

class ThemeSwitcherApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<bool>(
valueListenable: isDarkTheme,
builder: (context, isDark, child) {
return MaterialApp(
theme: isDark ? ThemeData.dark() : ThemeData.light(),
home: Scaffold(
appBar: AppBar(title: Text('Theme Switcher')),
body: Center(
child: ElevatedButton(
onPressed: () {
isDarkTheme.value = !isDarkTheme.value;
},
child: Text('Toggle Theme'),
),
),
),
);
},
);
}
}

b) Search Box Filtering

Filter a list of items in real time using ValueNotifier:

ValueNotifier<String> searchQuery = ValueNotifier<String>('');

class SearchApp extends StatelessWidget {
final List<String> items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Search Example')),
body: Column(
children: [
TextField(
onChanged: (value) {
searchQuery.value = value;
},
decoration: InputDecoration(labelText: 'Search'),
),
Expanded(
child: ValueListenableBuilder<String>(
valueListenable: searchQuery,
builder: (context, query, child) {
final filteredItems = items
.where((item) => item.toLowerCase().contains(query.toLowerCase()))
.toList();
return ListView.builder(
itemCount: filteredItems.length,
itemBuilder: (context, index) {
return ListTile(title: Text(filteredItems[index]));
},
);
},
),
),
],
),
);
}
}

6. Advantages of ValueNotifier and ValueListenableBuilder

  • Simplicity: No need for complex state management solutions.
  • Performance: Updates only the widgets listening to the notifier.
  • Integration: Works seamlessly with Flutter’s reactive widget tree.

7. When Not to Use ValueNotifier?

While ValueNotifier is great for simple use cases, it has limitations:

  • Not suitable for managing large or complex states.
  • Lacks advanced features like dependency injection and scalability.
  • Use more robust state management solutions (e.g., Provider, Riverpod) for complex apps.

8. Conclusion

ValueNotifier and ValueListenableBuilder are powerful tools for lightweight state management in Flutter. They’re simple, efficient, and integrate seamlessly with Flutter’s widget tree, making them perfect for managing a single value or a small piece of state.

By mastering these tools, you can build reactive Flutter apps with minimal overhead. So the next time you need lightweight state management, give ValueNotifier and ValueListenableBuilder a try!

Do you use ValueNotifier in your Flutter apps? Share your thoughts and experiences in the comments below!

— — — — — — — — — Click here to [Buy Me a Coffee!] — — — — — — — — —

--

--

Kashif Ahmed Siddiqui
Kashif Ahmed Siddiqui

Written by Kashif Ahmed Siddiqui

Experienced Flutter developer creating high-performance, cross-platform apps with Dart. Focused on UI/UX and optimized mobile solutions for iOS and Android.