Comments (18)
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:
from flutter_redux.
@brianegan I've been implement it and still the pages get rebuilt each time.
from flutter_redux.
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.
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.
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.
Thanks. Do you have tests that verify the ==
method on the NotificationsPageVM
is working as expected?
I could see a couple of issues here.
- By default, Dart does not compare
List
objects by content, but by identity. Therefore, if you're creating a newnotifyList
,allInstruments
,notifyListFromServer
ornotifications
list inside your reducer, the==
method will assume these are two different objects. Many folks use thecollection
package'sListEquality
class to compare the content of two lists. - 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.
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.
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.
from flutter_redux.
Yes test case passed
from flutter_redux.
Your assistance would greatly be appreciated. I need it urgently, thanks.
from flutter_redux.
from flutter_redux.
- widget isn't rebuild outside the builder, only inside store connector builder.
- == method return true.
- bool _whereDistinct(ViewModel vm) {
if (widget.distinct) ==> always true
{
return vm != _latestValue; ==> always false
}
return true;
} - I'm not quite understanding
from flutter_redux.
from flutter_redux.
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.
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.
allInstruments return false inside == operator
from flutter_redux.
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)
- How to not accept change notifications when the Router is not at the top level, and then take the initiative to obtain the changes when the Router returns to the top level HOT 1
- onDidChange called twice HOT 8
- Is this package still actively maintained?
- `onWillChange` and `onDidChange` errors are swallowed HOT 4
- Warning related to `?` operator on Linux/Dev channel. HOT 2
- Import Store data type
- Widgets binding error after upgrading flutter version to 2.13.0-0.1.pre HOT 1
- onDidChange not working as expected HOT 3
- Build warning with Flutter 3.0 HOT 5
- flutter_redux depends on flutter_redux, version solving failed HOT 3
- onWillChange and onDidChange called twice after state update HOT 2
- Passing Store as an argument to MethodChannel and Background Isolate
- Question on how to use the reducer right way HOT 2
- [Question]: Any thoughts on difference between ignoreChange and distinct?
- Dispatching an action that does not alter state rerenders the widget, causing an infinite loop HOT 5
- How to watch redux store change inside useEffect? HOT 5
- [Question] is it expected that the store doesn't run until frames render? HOT 1
- After push a new page, and Dispatching an action, there is an infinite loop
- Is flutter redux actively maintained HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from flutter_redux.