State Management in Flutter Framework Explained as React.js Developer

Tew Tawan.
CodeX
Published in
5 min readFeb 17, 2023

In Flutter, state management is typically managed at the widget level. A widget in Flutter is a user interface element, and it can have its own state. When the state of a widget changes, the framework rebuilds the widget tree to reflect the updated state. This is known as the “rebuild” or “redraw” cycle. Flutter provides several ways to manage state at the widget level, such as using StatefulWidget or using a state management library like Provider or Bloc library.

In contrast, React.js manages state at the component level. A component in React.js is similar to a widget in Flutter, in that it represents a user interface element. When the state of a component changes, React.js will re-render the component and its children, but not the entire component tree. This is known as the “render” cycle. React.js provides several ways to manage state at the component level, such as using the useState hook or using a state management library like Redux.

Key differences

One of the key differences between these frameworks is how they handle state changes. In Flutter, state changes are typically handled synchronously, which means that the UI will update immediately. In React.js, state changes are typically handled asynchronously, which means that the UI may not update immediately. This can result in a performance hit, but it also means that React.js can batch multiple state changes together for better performance.

Another key difference is how these frameworks handle re-rendering. In Flutter, the entire widget tree is rebuilt when the state of a widget changes. This can be expensive in terms of performance, especially if the widget tree is large. In React.js, only the affected components are re-rendered when their state changes, which can lead to better performance.

As a React developer, you may be familiar with the concept of state management. In React, state management is often handled by external libraries such as Redux or MobX. In Flutter, you have several options for state management, including using setState(), using a Provider package, or using the Bloc library.

SetState

In Flutter, the setState() method is used to update the state of a widget. When the state of a widget changes, Flutter automatically rebuilds the widget tree. This is similar to how React’s setState() method works.

To use setState() in Flutter, you’ll typically define a stateful widget that contains a state object. The state object is then updated using the setState() method, which triggers a rebuild of the widget tree.

Provider

Provider: Provider is a popular state management package for Flutter. It’s similar to React’s Context API, in that it provides a way to share state between different parts of your app.

With Provider, you can define a “provider” that holds a piece of state. This state can then be accessed by any widget in your app. When the state changes, Provider automatically updates all the widgets that depend on that state.

Bloc

Bloc is another state management package for Flutter. It’s similar to Redux in that it uses a unidirectional data flow to manage state.

With Bloc, you define “events” that represent changes in your app’s state. You also define “states” that represent the different possible states of your app. When an event is triggered, the Bloc updates the state of your app and notifies all the widgets that depend on that state.

Example

Here’s an example of state management in Flutter using the Provider package, with code examples that should be familiar to a React developer:

Let’s say you have a simple counter app with a button that increments the counter when pressed. In React, you might use the useState() hook to manage the state of the counter. In Flutter, you can use Provider to accomplish the same thing.

First, you’ll need to add the Provider package to your project by adding it to your pubspec.yaml file:

dependencies:
flutter:
sdk: flutter
provider: ^6.0.1 // add the Provider package here

Next, you’ll need to create a new class that holds the state of your app. This class will extend the ChangeNotifier class, which is provided by the Provider package:

import 'package:flutter/foundation.dart';

class Counter with ChangeNotifier {
int _count = 0;

int get count => _count;

void increment() {
_count++;
notifyListeners();
}
}

In this example, the Counter class holds the state of the app. It has a private _count variable that represents the current count, as well as a getter that exposes the current count to the rest of the app. It also has an increment() method that updates the count and calls notifyListeners() to notify any listeners that the state has changed.

Now you can use this Counter class to manage the state of your app. To do this, you’ll create a new Provider at the root of your widget tree:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Counter(),
child: MyApp(),
),
);
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter State Management Example',
home: CounterScreen(),
);
}
}

In this example, the ChangeNotifierProvider creates a new instance of the Counter class and makes it available to the rest of the app. The MyApp widget then provides the top-level MaterialApp widget, with CounterScreen as the home page.

Now you can use the Counter class to manage the state of your app. For example, you can create a new CounterScreen widget that displays the current count and a button that increments the count when pressed:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter Screen')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count:', style: TextStyle(fontSize: 24)),
Consumer<Counter>(
builder: (context, counter, child) {
return Text('${counter.count}', style: TextStyle(fontSize: 36));
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<Counter>(context, listen: false).increment();
},
child: Icon(Icons.add),
),
);
}
}

In this example, the CounterScreen widget uses the Consumer widget provided by the Provider package to display the current count. The FloatingActionButton uses Provider.of() to access the Counter object and call its increment() method.

Super!

Overall, state management in Flutter is similar to state management in React. However, there are some differences in how it’s implemented. By using setState(), Provider, or Bloc, you can manage the state of your Flutter app in a way that’s familiar and comfortable for React developers.

If you’re a React.js beginner or you’re about to transform yourself into a Cross-platform Mobile App developer. Follow me on LinkedIn. We’ll go all in this together!

--

--

Tew Tawan.
CodeX
Writer for

I'm a self-taught fullstack developer. I hope to help others by sharing my knowledge, learning processes and aspiring others.