【问题标题】:How to use setState in FutureBuilder properly?如何在 FutureBuilder 中正确使用 setState?
【发布时间】:2021-02-18 14:23:23
【问题描述】:

我正在制作一个页面,其中包含一些相互交互的保管箱和一个 Futurebuilder 包装的 ListView。

当 Dropbox 更改并单击复选框时,我正在调用“setState”。 但是,由于复选框的 onChanged 中的 setState,Futurebuilder 不断被调用,并且 ListView 被重建。 因此,当像下面的视频一样单击复选框时,整个 Listview 都会闪烁。

我想保留 Listview 并仅更新复选框。 有谁能帮助我吗? 谢谢。

完整代码是

class _StatefulDialogWidgetState extends State<StatefulDialogWidget> {
  ....   

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // Dropdown's
        Dropdown(0, widget.ReceiveArgs, _lListOfDepthList),
        Dropdown(1, widget.ReceiveArgs, _lListOfDepthList),
        Dropdown(2, widget.ReceiveArgs, _lListOfDepthList),
        Dropdown(3, widget.ReceiveArgs, _lListOfDepthList),
        Dropdown(4, widget.ReceiveArgs, _lListOfDepthList),
        
        // Listview with FutureBuilder
        AptListview(),
      ],
    );
  }

列表查看代码

Widget AptListview() {
    return FutureBuilder<List<String>>(
        future: AptNameListView(widget.ReceiveArgs),
        builder: (context, snapshot) {
          if (_bLastDepth == false) {
            return Text("Select Address");
          } else {
            if (snapshot.hasData == false || snapshot.data.isEmpty == true) {
              return CircularProgressIndicator();
            } else {
              return Expanded(
                child: ListView.builder(
                  shrinkWrap: true,
                  itemCount: _AptNameList.length,
                  itemBuilder: (context, index) {
                    //return new Text("${_AptName[index]}");
                    return CheckboxListTile(
                      title: Text(_AptNameList[index]),
                      value: _isAptChecked[index],
                      onChanged: (value) {
                        setState(() {                   //  SetState in FutureBuilder
                          _isAptChecked[index] = value;                              
                        });
                      },
                    );
                  },
                ),
              );
            }
          }
        });
  }

下拉代码

Widget Dropdown(int nDepth, ArgumentClass ReceiveArgs,
      List<List<String>> ListOfDepthList) {
    String _Value = "";
    List<DropdownMenuItem<String>> _itemList = null;
    if (ListOfDepthList.length <= nDepth) {
      _Value = "";
      _itemList = null;
    } else {
      _Value = _SelectedAddressList[nDepth];
      _itemList = GetMainItem(ListOfDepthList[nDepth]);
    }
    return DropdownButton(
        value: _Value,
        items: _itemList,
        onChanged: (value) {
          if (value.compareTo(GlobalObject().startMessage) != 0) {
            setState(() {
              .....
              // setState in Dropdown
            });
          }
        });
  }

【问题讨论】:

    标签: flutter dart checkbox setstate flutter-futurebuilder


    【解决方案1】:

    请阅读FutureBuilder documentation。它指出:

    未来一定是更早获得的,例如中 State.initState、State.didUpdateWidget 或 State.didChangeDependencies。期间不得创建 构造时调用 State.build 或 StatelessWidget.build 方法 未来建造者。如果未来与 FutureBuilder,那么每次重建 FutureBuilder 的父级时, 异步任务将重新启动。

    如文档所述,在initState 中获取未来并将其存储在您的状态中。

    Future future;
    @override
    void initState() {
      future = AptNameListView(widget.ReceiveArgs);
      super.initState();
    }
    
    
    Widget AptListview() {
        return FutureBuilder<List<String>>(
            future: future,
            builder: (context, snapshot) {
              if (_bLastDepth == false) {
                return Text("Select Address");
              } else {
                if (snapshot.hasData == false || snapshot.data.isEmpty == true) {
                  return CircularProgressIndicator();
                } else {
                  return Expanded(
                    child: ListView.builder(
                      shrinkWrap: true,
                      itemCount: _AptNameList.length,
                      itemBuilder: (context, index) {
                        //return new Text("${_AptName[index]}");
                        return CheckboxListTile(
                          title: Text(_AptNameList[index]),
                          value: _isAptChecked[index],
                          onChanged: (value) {
                            setState(() {                   //  SetState in FutureBuilder
                              _isAptChecked[index] = value;                              
                            });
                          },
                        );
                      },
                    ),
                  );
                }
              }
            });
      }
    

    【讨论】:

    • 好吧...如果我这样做,FutureBuilder 中的 Listview 会在创建 Widget 时构建一次。我想根据其他 Dropbox 的变化来刷新 Listview。这里的窍门是 Listview 有 Checkbox,所以它需要在滴答声时调用 'setState'。
    【解决方案2】:

    我解决了这个问题

    1. 在 Dropbox 的 setState 中调用 future 函数
    2. 将 Futurebuilder 更改为 Listview。

    它阻止了在调用 SetState 时更新 futurebuilder 中的列表视图。

    【讨论】:

      猜你喜欢
      • 2019-10-31
      • 2020-09-30
      • 2021-08-15
      • 2019-01-31
      • 2019-12-12
      • 1970-01-01
      • 2020-08-27
      • 1970-01-01
      • 2020-08-07
      相关资源
      最近更新 更多