As a Flutter developer, you might have encountered scenarios where you have to deal with mammoth amounts of boilerplate code when implementing data classes with numerous properties. Meet Freezed Flutter, a package that saves you from writing hundreds of error-prone lines of code and enables the seamless creation of data classes.
Freezed is a code generator for immutable classes, eliminating much of the boilerplate code you would otherwise have to write yourself. With the Freezed package, not only can you create data classes efficiently, but you can also leverage it to create a union or sealed classes.
The Freezed package offers a special command, the Freezed Flutter command, enabling freezed code generation, perfect for creating a Freezed class. What makes it stand out from a typical data class are its unique features: const factory constructors, an extra copyWith method, and in-built support for JSON serialization.
Now, let's dive deep into some of the Freezed concepts and understand how we can use them in a Flutter application.
A Freezed class brings together excellent elements in other data models from Dart classes like immutable classes, with default values and support for pattern matching on sealed classes.
Let's break this down a bit.
Immutable Classes: A Freezed class is immutable by nature. It's characterized by final string, final int age properties that can't be changed once the class instance is created. This ensures the data integrity of the Freezed class.
1 2abstract class Student with _$Student { 3 const factory Student({required String name, required int age}) = _Student; 4} 5
Sealed Classes: Sealed classes, often referred to as union classes, are incredibly powerful when you need to represent a variety of states in your app. With Freezed, you'll generally use them with Freezed BLoC.
Default Values: By leveraging factory constructors, you can assign default values to your properties.
While working with Freezed, you'll find Freezed annotation Flutter incredibly handy. This is all made possible with the help of the code generation package which generates code for your Freezed class.
1part 'student.freezed.dart'; 2 3part 'student.g.dart'; 4 5 6abstract class Student with _$Student { 7 const factory Student({required String name, required int age}) = _Student; 8 9 factory Student.fromJson(Map<String, dynamic> json) => 10 _$StudentFromJson(json); 11} 12
Once you have written your annotated class, the Freezed flutter command will generate code providing extra utilities and methods to operate on the Freezed class.
Freezed BLoC is a great way to manage state in your Flutter applications. With the combination of Freezed and BLoC pattern, you can easily represent multiple states, events, and reduce boilerplate code.
To serialize nested lists or layers of complex JSON, the Freezed package is a game-changer. It simplifies serialization by generating serialization logic for JSON data, eliminating time-consuming and error prone lines of code.
Before we delve into using Freezed, it is important to set up your environment. Start by adding the Freezed package and other required dependencies to your Flutter project.
1 dependencies: 2 freezed_annotation: ^2.4.1 3 4 dev_dependencies: 5 build_runner: ^2.4.6 6 freezed: ^2.4.3 7
Always remember to run the following command to get the packages: flutter pub get.
You can also use the commands to get these dependencies in your Flutter project.
1 flutter pub add freezed_annotation 2 flutter pub add --dev build_runner 3 flutter pub add --dev freezed 4 # if using freezed to generate fromJson/toJson, also add: 5 flutter pub add json_annotation 6 flutter pub add --dev json_serializable 7
For Dart project:
1 dart pub add freezed_annotation 2 dart pub add --dev build_runner 3 dart pub add --dev freezed 4 # if using freezed to generate fromJson/toJson, also add: 5 dart pub add json_annotation 6 dart pub add --dev json_serializable 7
The star of the Freezed package is the command flutter pub run build_runner build. This command triggers Freezed code generation, compiling your Freezed classes into Freezed model files, complete with additional utilities and functions.
Add the package dependencies to your project as mentioned above to your project and run flutter pub get command. At the root of your project disable invalid_annotation_target in the analysis_options.yaml file.
1 analyzer: 2 errors: 3 invalid_annotation_target: ignore 4
Create a new file called student.dart and make it part of freezed using part 'student.freezed.dart';.
1import 'package:freezed_annotation/freezed_annotation.dart'; 2 3part 'student.freezed.dart'; 4 5part 'student.g.dart'; 6 7 8abstract class Student with _$Student { 9 const factory Student({ required String name, required int age }) = _Student; 10 11 factory Student.fromJson(Map<String, dynamic> json) => 12 _$StudentFromJson(json); 13} 14
Noticed the _Student? It is a Freezed class that we generate using build_runner.
The Freezed Flutter command helps to generate code for the data class we created above. Running flutter pub run build_runner build will generate code and update the student.freezed.dart file.
1 flutter pub run build_runner build 2
When you do this, you may run into conflicting outputs. If that happens, run flutter pub run build_runner build --delete-conflicting-outputs.
By now, we have our Freezed class; let's create a BLoC for it:
1import 'package:freezed_annotation/freezed_annotation.dart'; 2 3part 'student_bloc.freezed.dart'; 4 5 6abstract class StudentEvent with _$StudentEvent { 7 const factory StudentEvent.add( 8 { required String name, required int age }) = AddEvent; 9} 10 11 12abstract class StudentState with _$StudentState { 13 const factory StudentState.empty() = Empty; 14 15 const factory StudentState.success(Student student) = Success; 16 17 const factory StudentState.error(String message) = Error; 18} 19
We have created StudentEvent and StudentState with different types using the sealed class feature of Freezed.
All done! You can now use Freezed to manage clean and scalable state in your Flutter applications.
Handling errors is crucial for any application, and Freezed provides an elegant way of doing it by using sealed classes. Let's examine handling errors in the context of Network Requests using Freezed.
In your sealed class, create an Error state:
1 2 abstract class NetworkState with _$NetworkState { 3 const factory NetworkState.success() = Success; 4 const factory NetworkState.error(String message) = Error; 5 } 6
The error state in the NetworkState data class holds a string message. We can map this message to different states of the network request.
As we wrap up, the Freezed Flutter package is an innovative and efficient tool for writing modular and clean code in Flutter. It dramatically decreases boilerplate code, supports custom utility methods and JSON serialization, and seamlessly assists in state management using the Freezed BLoC pattern.
Whether you are working on a small or large scale project, Freezed is likely going to become an indispensable part of your toolkit due to its emphasis on developer productivity, error prevention, and code quality.
Moreover, Freezed introduces helpful concepts such as immutable classes, sealed classes, and Factory constructors which, once you get used to, you may start using in your other Dart classes too.
Remember, understanding the purpose and utility of a package is the first step towards mastery. So keep exploring, keep questioning, and most importantly, keep coding! If you are curious about any other aspects of Flutter Freezed, feel free to drop a comment below.
Thank you for reading this step-by-step instruction on Freezed in Flutter. I wish you a joyful flutteringg!
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.