Explore how to implement stores using MobX in Flutter for efficient state management, focusing on creating and managing a task list.
In this section, we will delve into the implementation of stores using MobX in Flutter, focusing on creating a task management application. MobX is a powerful state management library that leverages reactive programming principles to make state management intuitive and scalable. By the end of this article, you will have a comprehensive understanding of how to implement and utilize stores in MobX to manage application state effectively.
MobX stores are central repositories where the state of your application resides. They are responsible for holding the state and defining the logic to manipulate it. In MobX, stores are typically implemented as classes that contain observables, actions, and computed properties. Observables represent the reactive state, actions define the logic to modify the state, and computed properties derive new state from existing observables.
Before we create our store, we need a model to represent the tasks in our application. The Task
model will encapsulate the properties of a task, such as its title, description, and completion status.
Create a new file models/task.dart
and define the Task
class as follows:
class Task {
String id;
String title;
String description;
bool isCompleted;
Task({
required this.id,
required this.title,
required this.description,
this.isCompleted = false,
});
}
This simple class provides a blueprint for our tasks, with an id
, title
, description
, and a boolean isCompleted
to track whether the task is done.
With the task model in place, we can now create a MobX store to manage a list of tasks. The store will handle adding, removing, and toggling the completion status of tasks.
Create a new file stores/task_store.dart
. Start by importing the necessary packages and setting up the code generation part:
import 'package:mobx/mobx.dart';
import '../models/task.dart';
part 'task_store.g.dart';
class TaskStore = _TaskStore with _$TaskStore;
The part 'task_store.g.dart';
directive is crucial for MobX code generation, which we’ll discuss further.
Define the _TaskStore
class with observables and actions:
abstract class _TaskStore with Store {
@observable
ObservableList<Task> taskList = ObservableList<Task>();
@action
void addTask(Task task) {
taskList.add(task);
}
@action
void removeTask(String id) {
taskList.removeWhere((task) => task.id == id);
}
@action
void toggleTaskStatus(String id) {
final index = taskList.indexWhere((task) => task.id == id);
if (index != -1) {
taskList[index].isCompleted = !taskList[index].isCompleted;
}
}
}
ObservableList<Task>
is used to store the list of tasks. This makes the list reactive, meaning any changes to it will automatically update any UI components observing it.addTask
, removeTask
, and toggleTaskStatus
are marked with the @action
decorator, indicating that they modify the state.Computed properties in MobX allow you to derive new state from existing observables. In our task store, we can create computed properties to filter tasks based on their completion status.
Add the following computed properties to your _TaskStore
class:
@computed
List<Task> get completedTasks =>
taskList.where((task) => task.isCompleted).toList();
@computed
List<Task> get pendingTasks =>
taskList.where((task) => !task.isCompleted).toList();
taskList
to return only tasks that are marked as completed.taskList
to return tasks that are not yet completed.MobX uses code generation to create the necessary boilerplate code for observables and actions. To generate the .g.dart
files, run the following command in your terminal:
flutter pub run build_runner build
This command will generate the task_store.g.dart
file, which contains the code required for MobX to function correctly.
@observable
and actions with @action
.Let’s consider a practical example of how you might integrate this store into a Flutter application. Imagine a simple task management app where users can add, remove, and toggle tasks.
To use the TaskStore
in your Flutter application, you’ll typically provide it using a state management solution like Provider
or directly within your widget tree.
Here’s a basic example of how you might use the TaskStore
in a Flutter widget:
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'stores/task_store.dart';
class TaskListPage extends StatelessWidget {
final TaskStore taskStore = TaskStore();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Task List')),
body: Observer(
builder: (_) => ListView.builder(
itemCount: taskStore.taskList.length,
itemBuilder: (context, index) {
final task = taskStore.taskList[index];
return ListTile(
title: Text(task.title),
subtitle: Text(task.description),
trailing: Checkbox(
value: task.isCompleted,
onChanged: (value) {
taskStore.toggleTaskStatus(task.id);
},
),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add a new task
taskStore.addTask(Task(
id: DateTime.now().toString(),
title: 'New Task',
description: 'Task Description',
));
},
child: Icon(Icons.add),
),
);
}
}
Observer
widget listens for changes in the taskStore
and rebuilds the UI accordingly.Implementing stores with MobX in Flutter offers a powerful way to manage application state. By leveraging observables, actions, and computed properties, you can create responsive and scalable applications. As you continue to explore MobX, consider experimenting with more complex state management scenarios and integrating MobX with other libraries to enhance your application’s capabilities.