Provider 加 FutureBuilder 在 Stateless Widget 的困惑
Provider plus FutureBuilder in Stateless Widget Confusion
因此,我看到了使用 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();
}
}
);
}
}
我只是不确定这样做是否正确。
您也可以在 statefulwidget 中使用相同的方式。在 initstate 中加载 http 数据不是一个好方法。
还有一件事,使用 statefulwidget 或 statelesswidget 完全取决于您想要实现的输出。所以,你使用的方式,是完美的。
如果您正在调用需要显示的未来,您应该使用有状态小部件并在 initState
或类似方式中获取未来。 documentation 不鼓励在 build
期间这样做,这是有充分理由的。
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.
如文档所述,如果在 build
中获取未来时重建 GamesGrid
,将再次调用您的未来方法,这应该是不良行为。 每隔 次 Flutter 想要构建那个小部件,就会再次调用该函数。如果这是理想的行为,您可能在其他地方使用了反模式。尽管如果这个小部件位于小部件树的顶部,它可能并没有真正的区别。尽管如此,它还是令人气馁。
你的代码对我来说似乎有点奇怪,它可能会被重构得更清晰更好,但如果你只是想在 initState
之后快速切换到获得未来的正确方法转换为 StatefulWidget
,您还需要访问 initState
中的提供商 gamesData
值,这可以通过 完成。然后,您将 Future
存储在一个变量中,并将该变量传递给您的 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();
}
}
);
}
}
我只是不确定这样做是否正确。
您也可以在 statefulwidget 中使用相同的方式。在 initstate 中加载 http 数据不是一个好方法。 还有一件事,使用 statefulwidget 或 statelesswidget 完全取决于您想要实现的输出。所以,你使用的方式,是完美的。
如果您正在调用需要显示的未来,您应该使用有状态小部件并在 initState
或类似方式中获取未来。 documentation 不鼓励在 build
期间这样做,这是有充分理由的。
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.
如文档所述,如果在 build
中获取未来时重建 GamesGrid
,将再次调用您的未来方法,这应该是不良行为。 每隔 次 Flutter 想要构建那个小部件,就会再次调用该函数。如果这是理想的行为,您可能在其他地方使用了反模式。尽管如果这个小部件位于小部件树的顶部,它可能并没有真正的区别。尽管如此,它还是令人气馁。
你的代码对我来说似乎有点奇怪,它可能会被重构得更清晰更好,但如果你只是想在 initState
之后快速切换到获得未来的正确方法转换为 StatefulWidget
,您还需要访问 initState
中的提供商 gamesData
值,这可以通过 Future
存储在一个变量中,并将该变量传递给您的 FutureBuilder
.
您应该能够从使用问题中提到的这种模式的示例中找出答案。如果没有,我可以举个例子。