State management plays an important role in the flutter application. It helps us to synchronize the state of all the components throughout the application. The developer needs to know the state of the application at any point in time. We can achieve this by using many approaches like Provider, Redux, BLoC, and so on. In this article, we discuss more on BLoC.
What is BLoC?
BLoC stands for Business Logic Component. It was mentioned by Google at the Google I/O and became the de facto standard for many developers to develop enterprise-grade applications. It was created based on Streams and Reactive Programming. BLoC allows us to separate the business logic from the User Interface. Writing code in BLoC provides a more elegant and reusable way of managing the state in Flutter applications and also makes it easier to write and reuse tests. In simple terms, BLoC accepts a stream of events or the function is called, processes the data based on events or function called, and produces the output as stated. In the BLoC pattern, we have four main layers of application:
- Data Sources
UI — It holds all the components of the application that are visible to the user and with which the user can interact with. Since in Flutter all parts of the User Interface are Widgets, we can say that all of them belong to this layer.
BLoC — These are the classes that act as a layer between User Interface(UI) components and data. The BLoC listens to events passed from the UI and after receiving a response based on the event it emits an appropriate state.
Repository — It helps in fetching pieces of data from single or multiple data sources and processing it for the UI classes.
Data sources — These are classes that help by providing the required data for the application, from all the data sources, including the database, network, shared preferences, etc.
As we are aware of all the basic structures, we may next need to understand how these layers communicate with each other. The BLoC pattern depends on two main components — Event & State.
Events that are passed from UI, which contain information about a few specific actions that have got to be handled by the BLoC. States that show how the UI should react to the data changes. Every BLoC has its initial state, which is defined during the time of creation. For example, if we wanted to implement a Sign In screen, we would need to pass a Sign In Event with Sign In details when the user clicks on the appropriate Sign In button. After receiving a response, the BLoC should show the SuccessState when the Sign In has been completed successfully, or ErrorState when the user has entered the wrong or inappropriate details, or a different error has occurred
Importance of using the Business Logic
By separating the Business Logic from the UI and other layers we can replace just one layer of code without having to disturb the other. As we all know business logic maintains the rules for processing the data that is obtained from the data layer. So separating these in turn adds another level of security to your application. It also makes code maintenance easy and we can easily reuse the existing code. It’s very difficult to write automated unit tests against your business logic if this code is tightly coupled. So using the business logic layer helps us to do the unit testing easily.
BLoC is a man in the middle. All the business logic is handled inside the BLoC file. It tends to accept events, performs the logic, and outputs the states. A Bloc is a more advanced class that relies on events to trigger state changes as opposed to functions.
Cubit is a simpler version of the BLoC. It helps us to eliminate the need to write events by using functions. Cubit exposes direct functions, which may return appropriate states. Writing a Cubit rather than BLoC also reduces boilerplate code, making the code easier to read.
BlocBuilder is a Flutter widget that has a Bloc and a builder function. BlocBuilder is responsible for building the widget in response to changes in states. BlocBuilder is almost similar to StreamBuilder but is featured with the more simple API to scale down the quantity of boilerplate code needed. The builder function will potentially be called repeatedly and will have to be a pure function that returns a widget in response to the state.
BlocProvider is a Flutter widget that can provide a bloc to its children via BlocProvider.of<T>(context). To provide the single instance of a bloc that can be provided to multiple widgets within a subtree, blocProvider is used as a dependency injection (DI) widget.
Advantages of using the BLoC pattern
1. Separation of Concerns: The User Interface and the business logic are no longer tightly coupled this makes it easier to make changes to the user interface without or modifying the business logic. It helps us to keep the UI simple and independent.
2. Testing: It is easier to do the Business logic now because we do have to worry about how it fits with the user interface.
3. Reactive Programming: Since the BLoC makes use of streams it helps us take advantage of the operators like distinct, where, asyncMap, switchMap e.t.c. They help in writing clean and brief code.
Guidelines for writing a BLoC
Below are some guidelines that we need to follow when writing a BLoC.
1. Input and Output of the BLoC are simple Sinks and Streams
2. Dependencies must be independent of the Platform and injectable.
3. No platform branching is allowed
4. Implementation can be whatever you want as long as you follow the above rules.
Flutter has a lot of approaches for managing the state of an application so it is up to us to pick the right approach. As we can see, the BLoC pattern is more suitable for complex applications because it encourages the separation of layers and makes our code clean and testable.