marcglasberg / async_redux

Flutter Package: A Redux version tailored for Flutter, which is easy to learn, to use, to test, and has no boilerplate. Allows for both sync and async reducers.
Other
234 stars 40 forks source link

List equality #120

Closed DaanDL closed 2 years ago

DaanDL commented 2 years ago

First let me thank you for this great project and very helpful docs you created!

The issue I'm having is that rebuilds of a certain widget get triggered wrongly. The culprit is that AsyncRedux thinks that both VM's are not equal (while in fact they are). To be more specific, the VM contains a list object, and the library thinks that both lists are not equal.

VM:

class MyViewModel extends Vm {
  final List<Preview> previews; // Just a list of objects where each element in it is exactly equal

  MyViewModel(
      {required this.previews})
      : super(equals: [previews]);
}

List item:

import 'package:equatable/equatable.dart';

class Preview extends Equatable {
  final int id;

  const Preview(this.id);

  @override
  List<Object?> get props => [id];
}

However when I don't use the equals functionality in my VM like this:

super(equals: [])

And instead opt to make use of the equatable package here:

 @override
  List<Object?> get props => [previews];

It works... So what's happening here with the built-in equals functionality as described in your docs?

marcglasberg commented 2 years ago

Your List<Preview> previews is a regular Dart list. Dart lists are compared by identity (the object reference), not equality (the list items). This means, if you have two lists with the same items, they are NOT considered to be the same list. That's the correct behavior.

AsyncRedux should not compare by equality (the items in the list), because that's very slow. It may not make a difference if you have only a few items, but a list can have millions of items, right? But comparing by identity this is always very fast.

You can force the view-model to be compared by equality, if you want. Just implement its equals() method, and then use a listEquals (https://api.flutter.dev/flutter/foundation/listEquals.html) to do the comparison by equality. I'd say that's probably what the Equatable package is doing? You'll have less builds that way, but it's going to be slow if the list has a lot of items.

Question: Is that list saved in your state? Or are you recreating it everytime? Please note, instead of mutable Dart lists, you can also use immutable lists (IList) from https://pub.dev/packages/fast_immutable_collections . Those immutable lists let you choose if you want to compare them by identity or equality.

I'll close this issue, but you can continue asking questions, until you understand everything. Thanks!