Effortless Flutter Model Classes with Freezed

Hadiuzzaman
4 min readJul 16, 2023

--

Greetings, fellow developers! In this article, we’re embarking on a journey to streamline Flutter app development using cutting-edge technology. We’ll dive into the world of Freezed, a powerful tool that allows us to create extensive lines of Flutter code without the need for tedious manual coding. By harnessing the magic of Freezed, we can supercharge our productivity and free up valuable development time.

One of the most time-consuming tasks in Dart programming is defining models. Each model or class typically demands a substantial amount of boilerplate code, including:

  1. Constructor Definition: Manually defining constructors for your classes can be a repetitive and error-prone process.
  2. Constructor Property Setup: Setting properties within constructors can lead to a lot of repetitive code that clutters your files.
  3. Method Overrides: To create robust and well-behaved classes, you often need to override methods like toString, operator, and hashCode.
  4. Clone Functionality: Implementing a copyWith() method is essential to clone objects easily, but it's yet another task on your to-do list.
  5. JSON Handling: When working with JSON data, the manual creation of serialization and deserialization code becomes a significant development bottleneck.

Let’s now examine a person.dart file to illustrate these challenges and explore how Freezed can come to our rescue:

class Person {
const Person({
required this.firstName,
required this.lastName,
required this.age,
});

final String firstName;
final String lastName;
final int age;

factory Person.fromJson(Map<String, dynamic> json) {
return Person(
firstName: json['firstName'] as String,
lastName: json['lastName'] as String,
age: json['age'] as int);
}

@override
String toString() {
return 'Person('
'firstName: $firstName, '
'lastName: $lastName, '
'age: $age';
}

@override
bool operator ==(Object other) {
return other is Person &&
other.runtimeType == runtimeType &&
other.firstName == firstName &&
other.lastName == lastName &&
other.age == age;
}

@override
int get hashCode {
return Object.hash(runtimeType, firstName, lastName, age);
}
}

Isn’t it just exhausting to write extensive code repeatedly for various models? Well, here’s the cool part — you no longer have to bear that burden. With the help of the freezed package, you can craft just a few lines of code, and the machine will take care of the rest. To clarify, it won't actually write 'freezed,' but rather 'build_runner.' To get started with these packages, let's head over to your pubspec.yaml file and add the necessary dependencies and dev-dependencies as shown below."

This version maintains a conversational tone while providing clear instructions for adding dependencies to the pubspec.yaml file, making it more user-friendly for developers.

dependencies:
freezed_annotation: ^2.4.1

dev_dependencies:
build_runner: ^2.4.6
freezed: ^2.4.1
json_serializable: ^6.7.1

Creating a freezed class is a breeze with the assistance of freezed_annotation (by using @freezed). Thanks to build_runner, the heavy lifting of code generation is taken care of. Additionally, json_serializable steps in to simplify all JSON-related tasks, including fromJson() and toJson(). Is it a daunting task? Absolutely not. Let's transform our previous person.dart model into a sleek @freezed class.

This revised paragraph maintains a concise and informative tone while highlighting the roles of freezed_annotation, build_runner, and json_serializable in code generation, making it approachable for developers looking to streamline their model classes.

import 'package:freezed_annotation/freezed_annotation.dart';

part 'person.freezed.dart';
part 'person.g.dart';

@freezed
class Person with _$Person {
factory Person(
{required String firstName,
required String lastName,
required int age}) = _Person;

factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
}

Just that much? Yes, it’s that straightforward! By writing this minimal code, you’ll get everything done — from fromJson, toString, hashCode, to operator methods. Now, let's embark on our journey to explore the wonders of the freezed class!

In our example, ‘Person’ is the name of our model, and we introduce _$Person (the freezed generated mixin) using the with keyword. Notice how, instead of a typical constructor, we employ a factory constructor here. The fascinating part is that, in a regular class, you'd write member variables separately, but in a freezed class, there's no need for that. The parameters of the factory constructor automatically become member variables. If you're not familiar with how factory constructors work, a quick Google search should provide some valuable insights.

Now, let’s delve into the Person.fromJson(..) method. Remember when we added the json_serializable package to the pubspec.yaml file earlier? Well, freezed takes advantage of it to automatically generate the code for fromJson() and toJson() methods. All we need to do is define the method, just like this-

factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);

Our journey is almost complete. Have you considered where the machine-generated code, which we’re about to create, will be saved? To ensure that, we must now specify the path for saving this auto-generated code. This should be done right above the @freezed annotation.

part 'person.freezed.dart';

If we utilize methods like fromJson() and toJson() within our model, it's essential to specify the path for these methods as well.

part 'person.g.dart';

How much more to go? Just one line left! Copy and paste the following command into your terminal to let the machine do the code writing for you.

flutter packages pub run build_runner watch --delete-conflicting-outputs

Vyas has done the heavy lifting with a bunch of machine-generated code. If you’re in doubt, feel free to inspect the person.frozen.dart and person.g.dart files. This is how the freezed package empowers us to offload the task of writing hundreds of lines of code to the machine.

Certainly! The freezed package offers a wide array of features and capabilities. For detailed information, please visit the documentation or the official website for a comprehensive overview of what the package has to offer.

https://pub.dev/packages/freezed

--

--

Hadiuzzaman
Hadiuzzaman

Written by Hadiuzzaman

Mobile Engineer | Flutter Expert | SwiftUI Enthusiast | Passionate about crafting exceptional cross-platform experiences. 🚀📱

No responses yet