因此,我看到了使用initState
函数将数据(http(加载到有状态小部件的提供程序中的示例。但是,如果小部件是无状态的,我不确定最好的方法是什么
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();
}
}
);
}
}
我只是不确定这是否是正确的做法。
如果您正在调用一个需要显示的future,那么您应该使用一个有状态的小部件,并在initState
或类似程序中获取future。文档不鼓励在build
期间执行此操作,并且有充分的理由。
未来必须更早获得,例如State.initState、State.didUpdateWidget或State.didChangeDependencies。在构造FutureBuilder。如果未来与FutureBuilder,那么每次重建FutureBuilders的父级时,异步任务将被重新启动。
正如文档所述,如果在build
中获取future时重建了GamesGrid
,则会再次调用future方法,这应该是不希望的行为每当Flutter想要构建该小部件时,就会再次调用该函数。如果这是理想的行为,那么您可能正在其他地方使用反模式。尽管如果这个小部件位于小部件树的顶部,它可能不会有什么不同。尽管如此,它还是被劝阻了。
你的代码对我来说有点奇怪,它可能会被重构得更清晰、更好,但如果你只是想在转换为StatefulWidget
后快速切换到在initState
中获得未来的正确方法,你还需要访问initState
中的提供者gamesData
值,这可以通过这个SO答案来实现。然后将Future
存储在一个变量中,并将该变量传递给FutureBuilder
。
你应该能够从你在问题中提到的使用这种模式的例子中弄清楚。如果没有,我可以举个例子。
您也可以在statefulwidget中使用相同的方法。在initstate中加载http数据不是一个好方法。还有一件事,使用statefulwidget或stateleswidget完全取决于您想要实现的输出。所以,你们使用的方式是完美的。