'Flutter: How to receive new Data and update Widget without rebuildung
I'm currently facing an annoying I think design problem made by myself and flutter :D
In my widgets I work with FutureBuilder. When the Widget gets created, it fetches initial the data - everything's fine. Now I got a WebSocket connection which sends me updated data. I pass this data to my widget and now I am facing the problem that either I change the data and the Widget does not reload or I additionally use setState and the widget will update itself and again fetches new data because it's rebuild and futurebuilder comes into play again. That's not efficient at all. How can I prevent this behavior.
I think about, that my Structure is maybe not right for this flutter behavior and therefore I maybe have to load the data initially outside the widget, pass em in via constructor and set a listener inside my Widget for the WebSocket notification and then call setState... right?
Here an short example that does rebuild and therefore again fetches data by itself -> so not my desired solution:
class _ExampleState extends State<Example> {
Stream wsData;
_ExampleState() {
wsData.listen((event) {
setState(() {
//update data
});
});
}
_getData() {
// Call network manager and fetch data
return {'fetchedData': 'data'};
}
@override
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: _getData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data != null) {
Text('data arrived: ' + snapshot.data.toString());
} else {
return CircularProgressIndicator();
}
}),
);
}
}
Solution 1:[1]
My solution: In my use case it just wouldn't work with Streambuilder. The data that were passed into the Widget after new data came from the stream were the same somehow.. Now I am using FutureBuilder to fetch the data initial and pass a Stream to my Widget. The Widget listens to changes on the Stream and updates itself..
Also, like mentioned from @Rémi Rousselet, I start the fetch process in the initState method and assign it to a local future variable, instead of triggering the fetch directly with FutureBuilder.
Solution 2:[2]
If you have a data source which constantly updates itself, you can use a StreamBuilder instead of FutureBuilder. StreamBuilder listens to the data source and rebuilds the widget after every update it gets from it.
Solution 3:[3]
Recently I also faced this problem, where I was passing data from another class with setState. The data was updated initially using initState then I was changing that particular data using a local variable, but when new data arrived from the parent class this was not updating.
later I found didUpdateWidget
method
@override
void didUpdateWidget(covariant ExampleClass oldWidget) {
print("didUpdateWidget: ${widget.value}");
selectedIndex = widget.value.toInt().toString(); //local variable
list.clear(); // list with data
_buildList(); // list will rebuild with new data
super.didUpdateWidget(oldWidget);
}
basically using this override method in the stateful class we can do something whenever there is a change in the widget.
Now I can update the data using local and parent variables.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | CAoT |
Solution 2 | Cankat Örüm |
Solution 3 | Sanjay Chakrapani |