Flutter's Bloc (Business Logic Component) pattern is a crucial aspect of state management, particularly in larger applications like GrowERP, where maintaining a clean separation of concerns is vital. It allows developers to effectively manage the flow of data and application states, ensuring a more maintainable and scalable codebase.
At its heart, Bloc is about separating the user interface (UI), business processing (Blocs), and the back-end REST interface. This clear division means that each part of your application has a specific role, reducing complexity and making the code easier to understand, test, and modify. Ideally, there should be no direct dependencies between these three layers, allowing the code to be organized into distinct packages.
The interaction within a Bloc-managed system follows a predictable pattern:
Event Trigger: An event occurs at the user interface, such as a button press or a text input.
State Change to Loading: This event causes the Bloc state to change to 'loading', indicating that an operation is in progress, and typically triggers a back-end REST request.
UI Feedback: The screen monitors the Bloc state and displays a loading indicator to the user.
Backend Processing: The result of the back-end request is then received and processed by the Bloc.
Error Handling: If the back-end operation encounters an issue, the state changes to an 'error' state, and an error message is sent to the screen for display.
Success and Display: If the operation is successful, the Bloc state transitions to a 'success' state, making the processed data available for display on the user's screen.
This flow ensures that the UI is always responsive and provides clear feedback to the user about the application's status.
Within this architecture, each component plays a distinct role:
Widget Screens (UI): The screens are solely responsible for displaying information and sending events. They maintain a single interface to their associated Blocs and monitor the
loading,success, orerrorstatus of the data. When the data changes, the screens are notified via state changes (usingBlocListener) and rebuild their UI (usingBlocBuilderorBlocConsumer) to reflect the new state.Bloc (Business Logic): The primary function of the Bloc is to process events received from the screens. It obtains requested data from the back-end (via the REST client), manipulates the data if necessary, and then returns the resulting data and its status to the screens. When a screen requests data that requires a back-end call, the Bloc sends the request to the REST client and updates the screen's status to 'loading' until the data is received, at which point the status changes to 'success' or 'failure'.
REST Client: This layer handles communication with the back-end. It receives requests from the Blocs, forwards them as REST requests to the server, and then checks and decodes the return codes. It also decodes the received JSON data into Dart objects based on a provided data model. If the request is successful and JSON decoding is error-free, a success message is reported; otherwise, a failure is reported along with an error message.
In GrowERP, the Bloc implementation typically involves four distinct files for each Bloc:
A user screen file responsible for creating events and receiving state changes.
An event file to define the various event classes that can be dispatched to the Bloc.
A state file to define the different states that the Bloc can be in (e.g., loading, success, error).
A bloc file itself, containing the core logic for processing events and emitting new states.
An example of this structure within GrowERP can be seen in the categories maintenance feature. For larger systems, GrowERP also leverages Flutter's packages feature to separate functionalities. Common models and frequently used Blocs, such as those for authorization, users, companies, and products, are grouped within a growerp_core package due to their tight interdependencies. Other packages can then extend these core functionalities or define their own specialized models and Blocs.
BlocProviders:
BlocProviderwidgets are used to make Blocs available to descendant widgets in the widget tree at runtime. While they can be created when needed, GrowERP has explored defining allBlocProviderinstances at application startup. This approach, while seemingly potentially slow, is effective because providers are typically "lazy" and only created when first accessed, resulting in no noticeable performance degradation. This also supports the flexible workflow system where any screen can be called at any time, independent of the menu structure.Generic Blocs: For simplifying data retrieval, GrowERP has implemented a single generic
DataFetchBlocthat can be used for reading any data type. This Bloc has a singlereadevent and handles the loading, error, and success states, making it highly reusable across the application.BlocBuilder for Dynamic UI: The
BlocBuilderwidget is strategically used in GrowERP to encapsulate parts of the screen that need to update dynamically based on Bloc state changes. When the state indicates 'success', the data within theBlocBuilderis refreshed, ensuring the UI always reflects the latest information.
By applying these principles, GrowERP maintains a robust and modular architecture that supports its comprehensive ERP functionalities, making it a flexible and maintainable system.
If you found this article valuable, don’t keep it to yourself—spread the word! Share it with friends, family, and colleagues to inspire more people to build business applications.
Thanks for reading! Have comments? Email us at support@growerp.com
No posts

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.