Question #90EasyFlutter Basics

What is equatable in flutter ?

#flutter

Answer

Overview

Equatable is a Dart package that simplifies value equality by automatically implementing

text
==
and
text
hashCode
based on object properties. It's essential for state management (BLoC, Riverpod) to correctly compare objects.


The Problem Without Equatable

Dart uses referential equality by default (compares memory addresses, not values).

dart
class User {
  final String name;
  final int age;

  User(this.name, this.age);
}

void main() {
  final user1 = User('Alice', 25);
  final user2 = User('Alice', 25);

  print(user1 == user2); // false ❌ (different instances)

  // Without overriding ==, BLoC can't detect identical states
  if (previousState == currentState) { /* Never enters! */ }
}

Solution: Equatable Package

Add to

text
pubspec.yaml
:

yaml
dependencies:
  equatable: ^2.0.5

Usage:

dart
import 'package:equatable/equatable.dart';

class User extends Equatable {
  final String name;
  final int age;

  const User(this.name, this.age);

  
  List<Object?> get props => [name, age]; // Define which fields matter
}

void main() {
  final user1 = User('Alice', 25);
  final user2 = User('Alice', 25);

  print(user1 == user2); // true ✅ (same values)
}

How It Works

Equatable overrides

text
==
and
text
hashCode
for you:

dart
// What Equatable does internally (simplified):

bool operator ==(Object other) {
  if (identical(this, other)) return true;
  return other is User &&
         other.name == name &&
         other.age == age;
}


int get hashCode => name.hashCode ^ age.hashCode;

With BLoC State Management

Equatable prevents unnecessary widget rebuilds.

dart
// ❌ Without Equatable
class CounterState {
  final int count;
  CounterState(this.count);
}

// BLoC emits new state
emit(CounterState(5));
emit(CounterState(5)); // ❌ Rebuilds widget even though count is same!

// ✅ With Equatable
class CounterState extends Equatable {
  final int count;
  const CounterState(this.count);

  
  List<Object?> get props => [count];
}

emit(CounterState(5));
emit(CounterState(5)); // ✅ No rebuild (Equatable detects same value)

Advanced Features

Ignore Specific Fields

dart
class User extends Equatable {
  final String id;
  final String name;
  final DateTime lastLogin; // Don't compare this

  const User(this.id, this.name, this.lastLogin);

  
  List<Object?> get props => [id, name]; // lastLogin not included
}

Nullable Fields

dart
class Profile extends Equatable {
  final String username;
  final String? bio; // Nullable

  const Profile(this.username, this.bio);

  
  List<Object?> get props => [username, bio]; // Handles nulls
}

Stringify (Debugging)

dart
class User extends Equatable {
  final String name;
  final int age;

  const User(this.name, this.age);

  
  List<Object?> get props => [name, age];

  
  bool get stringify => true; // Auto-generate toString()
}

print(User('Alice', 25)); // User(Alice, 25) ✅

With Collections

dart
class TaskList extends Equatable {
  final List<String> tasks;

  const TaskList(this.tasks);

  
  List<Object?> get props => [tasks];
}

final list1 = TaskList(['a', 'b']);
final list2 = TaskList(['a', 'b']);
print(list1 == list2); // true ✅ (deep equality)

Comparison Table

Without EquatableWith Equatable
Manual
text
==
override
Automatic via
text
props
Manual
text
hashCode
Auto-generated
Error-proneLess bugs
Verbose boilerplateConcise
BLoC over-rebuildsOptimized rebuilds

Best Practices

dart
// ✅ Use const constructors with Equatable
class User extends Equatable {
  final String name;
  const User(this.name); // const = compile-time constant

  
  List<Object?> get props => [name];
}

// ✅ Include all relevant fields in props

List<Object?> get props => [id, name, email]; // All important fields

// ❌ Don't include derived/computed fields
class User extends Equatable {
  final String firstName;
  final String lastName;
  String get fullName => '$firstName $lastName'; // Don't add to props

  
  List<Object?> get props => [firstName, lastName]; // Only stored fields
}

When to Use

  • BLoC states/events — Prevents duplicate state emissions
  • Riverpod providers — Correctly detects state changes
  • Data models — User, Product, etc. (value objects)
  • Testing — Compare expected vs actual results

Learn more: Equatable Package