Flutter: Equatable & It’s usage in Bloc
In Dart or any language, We always find it difficult to compare objects and return results. If we do not implement it correctly then in the long term you will face a lot of problems, as this will provide the wrong output as data is not compared as expected, Let's see an example of how dart solve it?
First, we will see the problem which we will be trying to fix
void main() {
User user = User('jitsm555');
print(user == User('jitsm555')); // Output: false
}
class User {
final String name;
User(this.name);
}
As you can see above, both objects having the same values, but while comparing they returns false. This happens because both have different hashcode internally.
Solution!!!
import 'package:equatable/equatable.dart';
void main() {
User user = User('jitsm555');
print(user == User('jitsm555')); // Output: true
}
class User extends Equatable {
final String name;
User(this.name);
@override
List<Object?> get props => [name];
}
Object and data comparison is always hard to do, So here comes theEquatable
as it overrides ==
and hashCode
internally, which solves our purpose of data comparison and eventually will save a lot of boilerplate code.
If we are not using theEquatable
then we have to write our own code for object comparison like
class User {
final String name;
User(this.name);
@override
bool operator ==(Object other) => other is User &&
name == other.name;
@override
int get hashCode => name.hashCode;
}
So, coming to the usage of theEquatable
in Bloc, becomes important as it updates the state as per the object changes, so before jumping on it, I recommend you to read the blog on the Bloc Mystery | Part 1 first, as the below topic required some knowledge around it.
Dependency:
To use theEquatable
add the dependency in pubspec.yaml file
dependencies:
equatable: ^2.0.2
In
Bloc
, we have to extendEquatable
toStates and Events
classes to use this functionality. This helps us when it comes to stream as we need to decide state updation based on it.
Ex:
abstract class LoginState extends Equatable {}
LoginState
will not make duplicate calls and will not going to rebuild the widget if the same state occurs. Now, think we haven't used Equatable
it here, then how many times Widget will be rebuild.
Equatable
comes with props
property which have its own purpose in object comparison, I have seen developers been neglecting this, and later face a lot of time in debugging.
Let’s see props
usage in Equatable and what makes it special
Define State without props:
class LoginLoadSuccess extends LoginState {
final String name;
final List<User> users;
const LoginLoadSuccess([this.name, this.users = const []]);
}
Define State with props:
props
declared when we want State
to be compared against the values declared inside props
List
class LoginLoadSuccess extends LoginState {
final String name;
final List<User> users;
const LoginLoadSuccess([this.name, this.users = const []]); @override
List<Object> get props => [name, users]; }
props
property decides which objects we should consider for object comparison, Suppose if we remove the name from the props
then State
will only consider the users
field, avoiding the name
field for object comparison. That is why it's important to use it carefully, as one mistake can cost a lot of time.
Bloc Stream Usage:
As we extending State with Equatable
which makes a comparison of old state data with new state data.
For example, let's look at the below example here LoginState
will build a widget only once, which will avoid the second call as it is duplicated.
@override
Stream<LoginState> mapEventToState(MyEvent event) async* {
final List<User> users = [User(), User()];
yield LoginLoadSuccess(users);
yield LoginLoadSuccess(users);
/// Second call will be avoided, means widget will not rebuild
}