Bloc 8.0 Tutorial for Flutter: Getting Started

Learn how to build a Wordle clone app in Flutter using one of the most robust state management libraries: Bloc 8.0. By Alejandro Ulate Fallas.

5 (4) · 1 Review

Download materials
Save for later
Share

Hey, you! Did you hear? The new release 8.0 for Bloc has been out for some time now, and you’ll love it! One of the most notable changes is that it removes the deprecated mapEventToState API in favor of on<Event>, introduced in earlier versions. It also has a new way to work with concurrent events, and monitoring Blocs is now easier to do and predict.

In this tutorial, you’ll get to:

  • Refresh your knowledge about core concepts like Bloc and cubits.
  • Learn about the new event API in Bloc 8.0.
  • Understand the concurrency of events in a Bloc.
  • Track and debug your Blocs or cubits.

It’s time for you to take advantage of all these new changes by developing a Wordle-like app with Bloc 8.0. Are you ready?

Note: This tutorial assumes you have intermediate knowledge of stateful and stateless widgets, usage of previous versions of Bloc and provider. To learn more about them, check out Getting Started with the BLoC Pattern and Bloc’s documentation and tutorials or learn about State Management With Provider.

Getting Started

Download the starter project by clicking Download Materials at the top or bottom of the tutorial. Then, open the starter project in VS Code 1.66 or later. You can also use Android Studio, but you’ll have to adapt the instructions below as needed.

Use a recent version of Flutter, 2.10 or above. VS Code should show a notification prompting you to click it to get the dependencies for the project.

If VS Code doesn’t get the dependencies automatically, then download them by opening pubspec.yaml and clicking the get package icon in the top-right corner or by running the command flutter pub get from the terminal.

In this tutorial, you’ll develop an app called Plingo, a word-guessing game like Wordle. You have to guess a five-letter word within five attempts to win. There’s a new random word to guess each time you play. If the user guesses the word, they’ll start or increase a winning streak. If the user fails to guess correctly, then the streak resets. The game also stores statistics for:

  • Number of times you’ve played.
  • Percentage of games you’ve won.
  • Your current winning streak.
  • Your longest winning streak.

Here’s a quick rundown of how the project is set up:

  • main.dart: Standard main file required for Flutter projects.
  • domain.dart: Contains the game logic and corresponding class definitions.
  • data.dart: Contains the classes that interact with storage and allows for better data handling.
  • app: A folder with the app widget and also a helper file with colors defined by the brand guidelines.
  • monitoring: A folder with a helper class that helps you track your Blocs and cubits.
  • presentation: Contains different folders that build the game’s UI:
    • bloc has a bloc definition for handling game interactions and possible outcomes from it, like winning or losing.
    • cubit has a cubit definition for handling the stats displayed in an in-game dialog.
    • pages has all the pages.
    • widgets contains all the reusable widgets.
    • dialogs has all the game’s dialog.
  • bloc has a bloc definition for handling game interactions and possible outcomes from it, like winning or losing.
  • cubit has a cubit definition for handling the stats displayed in an in-game dialog.
  • pages has all the pages.
  • widgets contains all the reusable widgets.
  • dialogs has all the game’s dialog.

Build and run the starter project using the emulator of your preference or a mobile device. At this point, you’ll see the following:

Game board screen for Plingo

Empty stats dialog for Plingo

As you can tell, the most critical aspects of the game are missing. Plingo doesn’t display anything when you tap a key on the on-screen keyboard. Also, when you tap the stats icon in the top-right corner of the screen, all the stats show as negative numbers.

In summary, all the game logic is missing. You’ll work on implementing it in this tutorial by using Bloc 8.0.

Reviewing Key Terms

Plingo looks great right now. Even though it doesn’t provide interaction for players yet, the game does have a complete UI. This will give you a chance to review a couple of key terms that are crucial for understanding the plugin’s implementation of the BLoC pattern.

BLoC stands for Business Logic Component and is a design pattern created for state management in apps. The general idea of how BLoC interacts in your app is that the user — or a process — triggers an event. Then, a component takes the event and applies business logic to it — for example, by communicating with an external API — transforming the information into a new state. In turn, this state change triggers a change in the UI or another part of your app.

In the end, what Bloc attempts is to control when state changes can occur and enforce a single way to change states throughout an entire app.

bloc is a plugin that has a built-in implementation of BLoC. It has two different variants of these types of components: Blocs and Cubits. Using either option will help you separate presentation from business logic, making your code fast, predictable, easy to test and reusable.

A Bloc is the core definition of the design pattern above, and it relies on events to trigger state changes. Blocs are more complex to understand but provide better traceability and can handle advanced event transformations.

Look at this example implementation of Bloc for a counting app that you can find in the plugin’s documentation:

abstract class CounterEvent {}
class CounterIncrementPressed extends CounterEvent {}

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<CounterIncrementPressed>((event, emit) => emit(state + 1));
  }
}

A Cubit is a much simpler implementation of the pattern — it exposes functions to trigger state changes instead of event classes. Its simplicity makes it easier to understand and needs less code. Here’s how the counting app would look with a Cubit:

class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() => emit(state + 1);
}

OK, now you might be thinking about when to choose one over the other. A good rule of thumb is to start with a Cubit and refactor to a Bloc if you need more traceability or to handle event transformation.

Note: As you see, the word “bloc” can be used in different ways to refer to different things, like BLoC for the pattern, bloc for the plugin and Bloc for the implementation of the pattern inside the plugin. For the rest of this tutorial, Bloc refers to the class defined in the plugin. This should help you avoid confusion in the following sections.