Giter Site home page Giter Site logo

Comments (18)

brianegan avatar brianegan commented on July 20, 2024

You need to use a StoreConnector Widget + the set distinct to true.

You can read more about it from the docs:

Every time the store changes, the Widget will be rebuilt. As a performance optimization, the Widget can be rebuilt only when the ViewModel changes. In order for this to work correctly, you must implement == and hashCode for the ViewModel, and set the distinct option to true when creating your StoreConnector.

And see an example here:

https://github.com/brianegan/flutter_architecture_samples/blob/master/redux/lib/containers/stats.dart

from flutter_redux.

barilki avatar barilki commented on July 20, 2024

@brianegan I've been implement it and still the pages get rebuilt each time.

from flutter_redux.

barilki avatar barilki commented on July 20, 2024

Every time I dispatch an action from the socket service, all my pages are rebuilt. i'm using distinct and == operator inside view model.

from flutter_redux.

brianegan avatar brianegan commented on July 20, 2024

Could you share the code that isn't working, or at least a small reproducible sample? I've shared a working example above. Is something similar not working?

Distinct + == are tested, but there could still be a bug. Impossible for me to help without seeing some code.

https://github.com/brianegan/flutter_redux/blob/master/test/flutter_redux_test.dart#L626

from flutter_redux.

barilki avatar barilki commented on July 20, 2024

For example:

setting page with setting view model

class NotificationsPageVM {
NotificationsPageVM({
this.notifyList,
this.notifyListFromServer,
this.allInstruments,
this.removeFromNotif,
this.getAlertsList,
this.notifications,
});

final List? notifyList;
final List? allInstruments;
final List<GetAlertsRespDto?>? notifyListFromServer;

final List? notifications;

final void Function(String id)? removeFromNotif;
final void Function()? getAlertsList;

static NotificationsPageVM fromStore(Store store) {
return NotificationsPageVM(
notifyList: store.state.notificationState.activeNotification,
allInstruments: store.state.symbolState.allSymbols,
notifyListFromServer: store.state.notificationState.activeNotificationList,
removeFromNotif: NotificationSelector.getRemoveFromNotificationsFunction(store),
getAlertsList: NotificationSelector.getAlertsList(store),
notifications: NotificationSelector.getNotificationsList(store),
);
}

@OverRide
bool operator ==(Object other) =>
identical(this, other) ||
other is NotificationsPageVM &&
runtimeType == other.runtimeType &&
notifyList == other.notifyList &&
notifyListFromServer == other.notifyListFromServer &&
allInstruments == other.allInstruments &&
removeFromNotif == other.removeFromNotif &&
getAlertsList == other.getAlertsList;

@OverRide
int get hashCode => notifyList.hashCode ^ notifyListFromServer.hashCode ^ allInstruments.hashCode ^ removeFromNotif.hashCode ^ getAlertsList.hashCode;
}

this is the small part of instrument page (Storeconnector)
@OverRide
Widget build(BuildContext context) {
return MainLayout(
key: Key('[NotificationsPage][MainLayout]'),
buildPhoneLayout: (BuildContext context, bool isSmallPhone) {
return StoreConnector<AppState, NotificationsPageVM>(
distinct: true,
converter: NotificationsPageVM.fromStore,
builder: (BuildContext context, NotificationsPageVM vm) {
....
}

in the main i dispatch event inside timer every second
Timer.periodic(
Duration(milliseconds: SocketConsts.INSTRUMENTS_TIMER_DELAY_IN_MILLISECONDS),
(_) {
widget.store.dispatch(UpdateSymbolsWithSocketDataAction(
symbols: symbols,
));
},
);

As a result, the setting page and other pages are always rebuilt.

from flutter_redux.

brianegan avatar brianegan commented on July 20, 2024

Thanks. Do you have tests that verify the == method on the NotificationsPageVM is working as expected?

I could see a couple of issues here.

  1. By default, Dart does not compare List objects by content, but by identity. Therefore, if you're creating a new notifyList, allInstruments, notifyListFromServer or notifications list inside your reducer, the == method will assume these are two different objects. Many folks use the collection package's ListEquality class to compare the content of two lists.
  2. Dart also compares Function objects only by identity. It looks like your callback functions are created by a selctor, so I assume that's working as intended, but it'd still be good to verify with a test case.

First, I'd start by trying the following test to make sure the == method is working as expected. If the following test works, please let me know and we can dig deeper. However, this feels like something is going on with the == method, since that's all the distinct option does: compare the old ViewModel to the new ViewModel using the == operator.

test('NotificationsPageVM == works as expected', () {
  final store = createStore(); // Example function, should be replaced by how you're building your store
  final viewModel = NotificationsPageVM.fromStore(store);

  store.dispatch(UpdateSymbolsWithSocketDataAction(symbols: symbols));

  final newViewModel = NotificationsPageVM.fromStore(store);

  expect(viewModel.notifyList, equals(newViewModel.notifyList));
  expect(viewModel.allInstruments, equals(newViewModel.allInstruments));
  expect(viewModel.notifyListFromServer, equals(newViewModel.notifyListFromServer));
  expect(viewModel.notifications, equals(newViewModel.notifications));
  expect(viewModel.removeFromNotif, equals(newViewModel.removeFromNotif));
  expect(viewModel.getAlertsList, equals(newViewModel.getAlertsList));
  expect(viewModel, equals(newViewModel));
});

from flutter_redux.

brianegan avatar brianegan commented on July 20, 2024

Looking at your code for a little longer, is the symbols List dispatched by the Timer.periodic( always a new List? If so, I'd imagine that might be the root of the problem.

from flutter_redux.

barilki avatar barilki commented on July 20, 2024

class NotificationsPageVM{
NotificationsPageVM({
this.notifyList,
this.notifyListFromServer,
this.allInstruments,
this.removeFromNotif,
this.getAlertsList,
this.notifications,
});

final List? notifyList;
final List? allInstruments;
final List<GetAlertsRespDto?>? notifyListFromServer;

final List? notifications;

final void Function(String id)? removeFromNotif;
final void Function()? getAlertsList;

static NotificationsPageVM fromStore(Store store) {
return NotificationsPageVM(
notifyList: store.state.notificationState.activeNotification,
allInstruments: store.state.symbolState.allSymbols,
notifyListFromServer: store.state.notificationState.activeNotificationList,
removeFromNotif: NotificationSelector.getRemoveFromNotificationsFunction(store),
getAlertsList: NotificationSelector.getAlertsList(store),
notifications: NotificationSelector.getNotificationsList(store),
);
}

@OverRide
bool operator ==(Object other) {
if (identical(this, other)) return true;

return other is NotificationsPageVM &&
    listEquals(other.notifyList, notifyList) &&
    listEquals(other.notifyListFromServer, notifyListFromServer) &&
    listEquals(other.allInstruments, allInstruments) &&
    listEquals(other.notifications, notifications) &&
    other.removeFromNotif == removeFromNotif &&
    other.getAlertsList == getAlertsList;

}

@OverRide
int get hashCode {
return notifyList.hashCode ^
notifyListFromServer.hashCode ^
allInstruments.hashCode ^
notifications.hashCode ^
removeFromNotif.hashCode ^
getAlertsList.hashCode;
}
}

Still the same, notification page are always rebuilt

from flutter_redux.

brianegan avatar brianegan commented on July 20, 2024

from flutter_redux.

barilki avatar barilki commented on July 20, 2024

Yes test case passed

from flutter_redux.

barilki avatar barilki commented on July 20, 2024

Your assistance would greatly be appreciated. I need it urgently, thanks.

from flutter_redux.

brianegan avatar brianegan commented on July 20, 2024

from flutter_redux.

barilki avatar barilki commented on July 20, 2024
  1. widget isn't rebuild outside the builder, only inside store connector builder.
  2. == method return true.
  3. bool _whereDistinct(ViewModel vm) {
    if (widget.distinct) ==> always true
    {
    return vm != _latestValue; ==> always false
    }
    return true;
    }
  4. I'm not quite understanding

from flutter_redux.

brianegan avatar brianegan commented on July 20, 2024

from flutter_redux.

barilki avatar barilki commented on July 20, 2024

I/flutter ( 9789): _whereDistinct: false
I/flutter ( 9789): _whereDistinct: true
I/flutter ( 9789): _handleChange: true
I/flutter ( 9789): _whereDistinct: false
I/flutter ( 9789): _whereDistinct: false
I/flutter ( 9789): builder: Notification Page VM

this is what it get.

from flutter_redux.

brianegan avatar brianegan commented on July 20, 2024

Thanks. This is what I'd expect if the Stream is working as expected. If two view models are equal using the == method, _whereDistinct correctly returns false and the Stream does not continue / the widget is not rebuilt.

However, from the pasted log, you can see that in some cases, your == method shows that two view models are not equal, so _whereDistinct returns true. This will cause the widget to rebuild, since it detects a new viewmodel has been emitted.

Please examine your == method when it returns false to figure out the root cause of the problem. In order to prevent the widget from rebuilding, _whereDistinct must return false.

from flutter_redux.

barilki avatar barilki commented on July 20, 2024

allInstruments return false inside == operator

from flutter_redux.

brianegan avatar brianegan commented on July 20, 2024

In that case, you've found the root of the issue! The allInstruments instance variable content changes.

If the list content changes, the two view models are no longer equal, and flutter_redux will rebuild the widget tree using the builder function, passing in new view model.

To prevent a whole page from rebuilding, the best thing to do would be to remove the allInstruments variable from your view model, and wrap only the specific part of the page that needs to rebuild when allInstruments changes with a StoreConnector widget that extracts that info.

from flutter_redux.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.