无状态小部件混乱中的Provider加FutureBuilder



因此,我看到了使用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完全取决于您想要实现的输出。所以,你们使用的方式是完美的。

最新更新