Reputation: 35864
So, I've seen examples of using the initState
function to load data (http) into a provider for a stateful widget. But if the widget is stateless, I'm not sure what the best approach is. What I've done is the following:
class GamesGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
final gamesData = Provider.of<GamesProvider>(context);
return FutureBuilder<void>(
future: gamesData.fetchGamesFromBgg(),
builder: (ctx, AsyncSnapshot<void> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
final games = gamesData.items;
return GridView.builder(
padding: const EdgeInsets.all(10.0),
itemCount: games.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3 / 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10),
itemBuilder: (context, idx) => ChangeNotifierProvider.value(
value: games[idx],
child: GameItem()
)
);
} else {
return CircularProgressIndicator();
}
}
);
}
}
I'm just not sure that this is the right way to go about it.
Upvotes: 2
Views: 2075
Reputation: 17123
If you're calling a future that needs to be displayed, you should be using a stateful widget and obtaining the future in initState
or similar. Doing it during build
is discouraged by the documentation and for good reason.
The future must have been obtained earlier, e.g. during State.initState, State.didUpdateWidget, or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.build method call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted.
As the documentation states, if GamesGrid
is rebuilt when obtaining the future in build
, your future method will be called again, which should be undesirable behavior. Every time Flutter wants to build that widget, that function is going to be called again. If this is desirable behavior, you likely are using an antipattern somewhere else. Though if this widget is way at the top of your widget tree, it may not really make a difference. It's discouraged nonetheless.
Your code seems a bit odd to me and it can likely be refactored to be much more clear and better, but if you just want to quickly switch to the proper approach of obtaining the future in initState
after converting to a StatefulWidget
, you'll also need to access your provider gamesData
value in initState
, which can be accomplished with this SO answer. You then store the Future
in a variable and pass that variable to your FutureBuilder
.
You should hopefully be able to figure it out from the examples using this pattern that you mentioned in your question. If not, I can whip up an example.
Upvotes: 2
Reputation: 302
You can use same way in statefulwidget also. Loading http data in initstate is not a good way. One more thing, using statefulwidget or statelesswidget is totally depends up on the output that you want to achieve. So, way you are using, is perfect.
Upvotes: -1