使用导航栏(NavigationRail)与多个 Futures

huangapple go评论68阅读模式
英文:

Using NavigationRail with multiple Futures

问题

我正在尝试创建一个带有NavigationRail的屏幕,其中每个目标都显示从后端获取的不同数据的表格。

我尝试使用NavigationRail和三个Future来实现它,但每次从一个目标过渡到另一个目标时,我看到第二个目标上出现一个红色屏幕,并且然后过渡完成。我的日志显示以下错误:

构建FutureBuilder<List<dynamic>>时引发了以下TypeErrorImpl
预期值的类型为'D1',但却得到了'D2'之一。

相关错误产生的小部件是FutureBuilder<List<dynamic>>

您能否看一下我是否遗漏了什么?我尝试了相同的方法,使用carousel_slider小部件和三个Future,但没有遇到同样的问题。我猜我在某种程度上误用了NavigationRail。以下是基本代码:

  1. class DataScreen extends StatefulWidget {
  2. const DataScreen({super.key});
  3. @override
  4. State<DataScreen> createState() => _DataScreenState();
  5. }
  6. class _DataScreenState extends State<DataScreen> {
  7. late Future<List<D1>> data1;
  8. late Future<List<D2>> data2;
  9. late Future<List<D3>> data3;
  10. int _selectedIndex = 0;
  11. @override
  12. void initState() {
  13. super.initState();
  14. data1 = D1Service().getD1();
  15. data2 = D2Service().getD2();
  16. data3 = D3Service().getD3();
  17. }
  18. @override
  19. Widget build(BuildContext context) {
  20. return Scaffold(
  21. body: Row(
  22. children: <Widget>[
  23. NavigationRail(
  24. selectedIndex: _selectedIndex,
  25. groupAlignment: 0.0,
  26. onDestinationSelected: (int index) {
  27. setState(() {
  28. _selectedIndex = index;
  29. });
  30. },
  31. labelType: NavigationRailLabelType.all,
  32. leading: const SizedBox(),
  33. trailing: const SizedBox(),
  34. destinations: const <NavigationRailDestination>[
  35. NavigationRailDestination(
  36. icon: Icon(Icons.perm_identity),
  37. selectedIcon: Icon(Icons.person),
  38. label: Text('D1'),
  39. ),
  40. NavigationRailDestination(
  41. icon: Icon(Icons.groups_outlined),
  42. selectedIcon: Icon(Icons.groups),
  43. label: Text('D2'),
  44. ),
  45. NavigationRailDestination(
  46. icon: Icon(Icons.inventory_2_outlined),
  47. selectedIcon: Icon(Icons.inventory_2),
  48. label: Text('D3'),
  49. ),
  50. ],
  51. ),
  52. const VerticalDivider(thickness: 1, width: 1),
  53. const Spacer(),
  54. // 这是主要内容。
  55. Center(
  56. child: Container(
  57. child: _toTableAll(),
  58. ),
  59. ),
  60. const Spacer(),
  61. ],
  62. ),
  63. );
  64. }
  65. Widget _toTableAll() {
  66. if (_selectedIndex == 0) {
  67. return _toTable(data1);
  68. } else if (_selectedIndex == 1) {
  69. return _toTable(data2);
  70. }
  71. return _toTable(data3);
  72. }
  73. Widget _toTable<T>(Future<List<T>> item) {
  74. return FutureBuilder<List<T>>(
  75. future: item,
  76. builder: (context, snapshot) {
  77. if (snapshot.hasData) {
  78. return Container(
  79. constraints: const BoxConstraints(maxWidth: 800),
  80. child: MTable(snapshot.data!),
  81. );
  82. } else if (snapshot.hasError) {
  83. return Text('${snapshot.error}');
  84. } else {
  85. return const Center(
  86. child: CircularProgressIndicator(),
  87. );
  88. }
  89. },
  90. );
  91. }
  92. }
英文:

I am trying to make a screen with NavigationRail where each destination displays table with different data fetched from backend.

I tried implementing it with NavigationRail and three futures, but each time I transit from one destination to another, I see a red screen with error on a second and then transit completes. My logs show following error:

The following TypeErrorImpl was thrown building FutureBuilder<List<dynamic>>(state: _FutureBuilderState<List<dynamic>>#675cb):
Expected a value of type 'D1', but got one of type 'D2'

The relevant error-causing widget was
FutureBuilder<List<dynamic>>

Could you please see if I am missing something? I tried the same approach with three futures with carousel_slider widget and did not run into a same problem. I guess I am misusing NavigationRail somehow.
Here is base code:

  1. class DataScreen extends StatefulWidget {
  2. const DataScreen({super.key});
  3. @override
  4. State&lt;DataScreen&gt; createState() =&gt; _DataScreenState();
  5. }
  6. class _DataScreenState extends State&lt;DataScreen&gt; {
  7. late Future&lt;List&lt;D1&gt;&gt; data1;
  8. late Future&lt;List&lt;D2&gt;&gt; data2;
  9. late Future&lt;List&lt;D3&gt;&gt; data3;
  10. int _selectedIndex = 0;
  11. @override
  12. void initState() {
  13. super.initState();
  14. data1 = D1Service().getD1();
  15. data2 = D2Service().getD2();
  16. data3 = D3Service().getD3();
  17. }
  18. @override
  19. Widget build(BuildContext context) {
  20. return Scaffold(
  21. body: Row(
  22. children: &lt;Widget&gt;[
  23. NavigationRail(
  24. selectedIndex: _selectedIndex,
  25. groupAlignment: 0.0,
  26. onDestinationSelected: (int index) {
  27. setState(() {
  28. _selectedIndex = index;
  29. });
  30. },
  31. labelType: NavigationRailLabelType.all,
  32. leading: const SizedBox(),
  33. trailing: const SizedBox(),
  34. destinations: const &lt;NavigationRailDestination&gt;[
  35. NavigationRailDestination(
  36. icon: Icon(Icons.perm_identity),
  37. selectedIcon: Icon(Icons.person),
  38. label: Text(&#39;D1&#39;),
  39. ),
  40. NavigationRailDestination(
  41. icon: Icon(Icons.groups_outlined),
  42. selectedIcon: Icon(Icons.groups),
  43. label: Text(&#39;D2&#39;),
  44. ),
  45. NavigationRailDestination(
  46. icon: Icon(Icons.inventory_2_outlined),
  47. selectedIcon: Icon(Icons.inventory_2),
  48. label: Text(&#39;D3&#39;),
  49. ),
  50. ],
  51. ),
  52. const VerticalDivider(thickness: 1, width: 1),
  53. const Spacer(),
  54. // This is the main content.
  55. Center(
  56. child: Container(
  57. child: _toTableAll(),
  58. ),
  59. ),
  60. const Spacer(),
  61. ],
  62. ),
  63. );
  64. }
  65. Widget _toTableAll() {
  66. if (_selectedIndex == 0) {
  67. return _toTable(data1);
  68. } else if (_selectedIndex == 1) {
  69. return _toTable(data2);
  70. }
  71. return _toTable(data3);
  72. }
  73. Widget _toTable&lt;T&gt;(Future&lt;List&lt;T&gt;&gt; item) {
  74. return FutureBuilder&lt;List&lt;T&gt;&gt;(
  75. future: item,
  76. builder: (context, snapshot) {
  77. if (snapshot.hasData) {
  78. return Container(
  79. constraints: const BoxConstraints(maxWidth: 800),
  80. child: MTable(snapshot.data!),
  81. );
  82. } else if (snapshot.hasError) {
  83. return Text(&#39;${snapshot.error}&#39;);
  84. } else {
  85. return const Center(
  86. child: CircularProgressIndicator(),
  87. );
  88. }
  89. },
  90. );
  91. }
  92. }

答案1

得分: 1

使用snapshot.connectionState == ConnectionState.done替换snapshot.hasData解决了这个问题。

英文:

Changing snapshot.hasData with snapshot.connectionState == ConnectionState.done solved the problem

huangapple
  • 本文由 发表于 2023年2月8日 20:44:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/75385989.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定