Flutter is one of the youngest but also most promising open-source UI software development kit developed by Google, and I have been developing with it for the past six months for work. I'd like to share a few lessons I've learnt.
An easy one to overlook when swarming or developing as a team, this foundational advice has caught out rookies like myself and more experienced developers alike. Following proper naming convention makes Flutter code more readable, and effort should be invested as a team to maintain consistency in the codebase.
Libraries, directories, packages, source files, projects should be named in snake_case (lowercase_with_underscore)
Private variables should start with underscores
Constants, variables, parameters should be labeled in lowerCamelCase
Classes, types, extension names, enums should be in UpperCamelCase
Use meaningful names and avoid single character variables names
Widgets are an integral part of Flutter development, and where practically possible, widgets should be splitted into child widgets.
If the list of widgets becomes lengthy, you should use List.View.builder, which will improve app performance.
Use setState() judiciously in the widget tree as it rebuilds all widgets that fall underneath it. Hence when you split widget into smaller child widgets, setState() positioned well will only rebuild that part of the subtree where the UI needs to be updated.
Business Logic Components (BLoC) is a design pattern that allows for code reusability and a better developer experience when building for different platforms (web apps, mobile app, and more).
A BLoC can be thought of as the layer between data and UI. It receives events from an external source and emits a state in response to the received event.
Events are inputs to a bloc, they're usually triggered by user interactions such as button clicks or lifecycle events like page loads.
States are outputs to a bloc, they represent the application state. The UI components listen to state changes and "redraw" based on the current state at any point in time.
BLoC widgets help rebuild/notify UI components in response to any state changes. which consists of BLoCProvider, BLoCListener, BLoCConsumer and BLoCBuilder as provided by Google's flutter_bloc package.
BLoCProvider is a widget that provides an instance of the BLoC to its children. It uses dependency injection to deliver a single instance of a bloc to widgets within a subtree.
BlocProvider(
create: (BuildContext context) => BlocA(),
child: AChildWidget(),
)
BLoCBuilder is a widget that requires a bloc and a builder to construct the widget in response to new states. It will automatically look for a BLoCProvider and the current BuildContext.
BlocBuilder<BlocA, BlocAState>(
builder: (context, state) {
// return widget here based on BlocA's state
}
)
BLoCListener uses BlocWidgetListener and an optional bloc that invokes the listener to respond to changes in state. It is ideal when functionalities only occur once per state change, such as displaying a snack bar.
BlocListener<BlocA, BlocAState>(
listener: (context, state) {
// do things here based on BlocA's State
},
child: AChildWidget()
)
BLoCConsumer is a combination of both BLoCListener and BLoCBuilder. It exposes a listener and a builder to react to new state changes. It is good practice to only use BLoCConsumer when you need to rebuild the UI and execute other reactions to changes in the state of the bloc.
BlocConsumer<BlocA, BlocAState>(
listener: (context, state) {
// do things here based on BlocA's state
},
builder: (context, state){
// return widget here based on BlocA's state
}
)
I am still in the midst of understanding BLoC and how to apply SOLID engineering principles to codebase. I will update this post progressively as I learn and read more.