Last active
April 17, 2021 20:14
-
-
Save aloisdeniel/cfc6d4c0bac34757395b6b02ca6e6c19 to your computer and use it in GitHub Desktop.
This example shows how, in a majority of cases, Streams cause unnecessary rebuilds in initial state.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:rxdart/rxdart.dart'; | |
// Global application configuration and navigation | |
void main() => runApp(MyApp()); | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) => MaterialApp(home: Home()); | |
} | |
class Home extends StatelessWidget { | |
Widget _button(BuildContext context, String title, WidgetBuilder builder) => RaisedButton( | |
child: Text(title), | |
onPressed: () => Navigator.push( | |
context, MaterialPageRoute(builder: builder))); | |
@override | |
Widget build(BuildContext context) { | |
return Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
_button(context, "Streams", (c) => StreamExample()), | |
_button(context, "Notifiers", (c) => NotifierExample()), | |
], | |
); | |
} | |
} | |
// Basic view that displays two properties | |
class ExampleView extends StatelessWidget { | |
final String title; | |
final String description; | |
ExampleView({@required String title, @required String description}) : this.title = title ?? "<EMPTY>", this.description = description ?? "<EMPTY>"; | |
@override | |
Widget build(BuildContext context) { | |
print("ExampleView built with title:'$title' and description: '$description'"); | |
return Scaffold( | |
appBar: AppBar(title: Text(this.title)), | |
body: Text(this.description), | |
); | |
} | |
} | |
// With Streams/RX | |
// ---- | |
// | |
// Two initial rebuilds while we know we have values. | |
// | |
// I/flutter (31663): ExampleView built with title:'<EMPTY>' and description: '<EMPTY>' | |
// I/flutter (31663): ExampleView built with title:'Stream's example' and description: 'This shows how Streams with empty inital data cause more rebuild than ValueListenable.' | |
class StreamModel { | |
final title = BehaviorSubject.seeded("Stream's example"); | |
final description = BehaviorSubject.seeded( | |
"This shows how Streams with empty inital data cause more rebuild than ValueListenable."); | |
Future<void> dispose() async { | |
Future.wait([ | |
this.title.close(), | |
this.description.close(), | |
]); | |
} | |
} | |
class StreamExample extends StatefulWidget { | |
@override | |
_StreamExampleState createState() => _StreamExampleState(); | |
} | |
class _StreamExampleState extends State<StreamExample> { | |
final model = StreamModel(); | |
@override | |
void dispose() { | |
super.dispose(); | |
model.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return StreamBuilder( | |
stream: model.title, | |
builder: (context, title) { | |
return StreamBuilder( | |
stream: model.description, | |
builder: (context, description) { | |
return ExampleView( | |
title: title.data, description: description.data); | |
}); | |
}); | |
} | |
} | |
// With Notifiers/ValueListenable | |
// ---- | |
// | |
// Only one build since ValueListenable always has a stored value. | |
// | |
// I/flutter (31663): ExampleView built with title:'Notifier's example' and description: 'This shows how Streams with empty inital data cause more rebuild than ValueListenable.' | |
class NotifierModel { | |
final title = ValueNotifier("Notifier's example"); | |
final description = ValueNotifier( | |
"This shows how Streams with empty inital data cause more rebuild than ValueListenable."); | |
void dispose() async { | |
this.title.dispose(); | |
this.description.dispose(); | |
} | |
} | |
class NotifierExample extends StatefulWidget { | |
@override | |
_NotifierExampleState createState() => _NotifierExampleState(); | |
} | |
class _NotifierExampleState extends State<NotifierExample> { | |
final model = NotifierModel(); | |
@override | |
void dispose() { | |
super.dispose(); | |
model.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return ValueListenableBuilder( | |
valueListenable: model.title, | |
builder: (context, title, _) { | |
return ValueListenableBuilder( | |
valueListenable: model.description, | |
builder: (context, description, _) { | |
return ExampleView( | |
title: title, description: description); | |
}); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment