Hand in Hand with Flutter: Mastering State Management
与Flutter携手:掌握状态管理

State Management in Flutter: A Practical Problem-Solving

Bigpeak Chen

--

In this article, we will explore a practical case of Flutter app development, focusing mainly on state management, specifically on generating and displaying a series of unique identifiers (UUID) in a Flutter application. In the process of solving this problem, we will delve into the core concepts and usage of Riverpod.

Initial Concept

Our objective is to create a Flutter app that includes a button and a text list. When the user clicks the button, we generate a new UUID and add it to the list. To achieve this, we have chosen to use the Riverpod and UUID libraries.

First, we need to add these two libraries as dependencies in our Flutter project.

dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^1.0.0
uuid: ^3.0.4

Code Implementation

We first define two state providers in Riverpod, one for storing the text list, and the other for generating the UUID.

final textListProvider = StateProvider<List<String>>((ref) => ['Initial text']);
final uuidProvider = StateProvider<Uuid>((ref) => Uuid());

Then, we create a simple UI that includes a button and a text list. Each time the button is clicked, the app generates a new UUID and adds it to the text list.

class _MyAppState extends ConsumerState<MyApp> {
@override
Widget build(BuildContext context) {
final textList = ref.watch(textListProvider).state;
final uuid = ref.watch(uuidProvider).state; return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
final newUuid = uuid.v4();
ref.read(textListProvider).state = [...textList, "hello $newUuid"];
},
child: Icon(Icons.add),
),
body: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: textList.map((text) => Text(text)).toList(),
),
),
),
);
}
}

Encountered Problem

However, when we run this code, we find that clicking the button does not add a new UUID to the list on the screen. We printed the value of textList and found that after each button click, the value of textList does indeed change, but this change is not reflected in the UI.

This is because, in Flutter, UI updates are achieved by comparing the new and old Widget trees. When we click the button, the Riverpod state does change, but since our Widget tree has not changed, Flutter does not rebuild the Widget.

Problem Solving

To solve this problem, we need to ensure that our Widget tree also changes when the state changes.

We use Riverpod’s Consumer widget to monitor the state of textListProvider. Thus, each time the state of textListProvider changes, the Widget containing the Consumer will be rebuilt.

We also found that we should use ref.read(textListProvider.notifier) instead of ref.read(textListProvider).state to get the state when the state changes, as the former can get the latest value of the state.

Here is the corrected code:

class _MyAppState extends ConsumerState<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
final currentList = ref.read(textListProvider).state;
final newUuid = Uuid().v4();
ref.read(textListProvider.notifier).state = [...currentList, "hello $newUuid"];
},
child: const Icon(Icons.add),
),
body: Center(
child: Consumer(builder: (context, watch, _) {
final textList = watch(textListProvider).state;
return Column(
children: textList.map((text) => Text(text)).toList(),
);
}),
),
),
);
}
}

Lessons Learned

Through this process, I gained a deeper understanding of Flutter’s UI update mechanism and Riverpod’s state management. I learned that when the state changes, I need to ensure that the UI also changes correspondingly, otherwise, the UI will not update. I also learned about Riverpod’s state management mechanism and how to update the UI when the state changes.

In addition, I learned how to use the UUID library to generate unique identifiers in a Flutter application. These learnings will be very helpful for my future Flutter development work.

Core Concepts of Riverpod State Management

Riverpod is a powerful state management library. It provides a declarative way to manage states. It aims to solve some problems present in the Provider library, such as global state and type safety issues.

The main concepts of Riverpod include:

  • Provider: The Provideris a basic building block in Riverpod. It provides a value and exposes a listening API to the widgets.
  • StateProvider: A special kind of provider that can hold and expose a mutable state.
  • Consumer: A widget that can listen to a provider.
  • ref.watch: A function used to listen to a provider. It rebuilds the widget when the provider changes.
  • ref.read: A function used to read a provider without listening to it.

Conclusion

In this article, we have explored a practical problem-solving process in Flutter app development, focusing on state management with Riverpod. We have learned how to generate and display a series of unique identifiers (UUID) in a Flutter application, and how to solve the problem of UI not updating when the state changes.

Remember, practice is the best way to learn. By solving practical problems, we can better understand and master the concepts and usage of Riverpod and other state management libraries in Flutter. Happy Coding!

--

--

Bigpeak Chen

Tech enthusiast exploring Flutter, AI, and interdisciplinary applications. Sharing insights to empower developers. Join me for an exciting tech journey!