Fluter setState()使循环始终被调用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fluter setState()使循环始终被调用相关的知识,希望对你有一定的参考价值。

我有一个这样的代码,简单的流程是我从一个对象列表创建一个循环来创建一些小部件。

class ScoringAttribute {
  int _id;
  bool _isdelete;
  double _scorehigh, _scorelow, _scorevalue;
  String _name, _scoretype, _description, _title;
}

class HomePageState extends State<HomePage> with TickerProviderStateMixin {
  List dataScoringAttributes;
  List<ScoringAttribute> listScoringAttributeObjects = new List<ScoringAttribute>();

  final String urlPresentation = ".../.resentations/getPresentations";
  final String urlScoringAttribute = ".../.scoringattributes/getScoringattributes";

  Future<String> getPresentationData() async {
    var responseScoringAttribute = await http.get(
      Uri.encodeFull(urlScoringAttribute),
      headers: {"Accept": "application/json"}
    );

    var scoringAttributeJson = json.decode(responseScoringAttribute.body);

    dataScoringAttributes = scoringAttributeJson['scoringattributes'];

    for(int i = 0; i < dataScoringAttributes.length; i++) {
      var scoringAttributeObject = new ScoringAttribute();

      scoringAttributeObject._id = dataScoringAttributes[i]["id"];
      scoringAttributeObject._description = dataScoringAttributes[i]["iddescription"];
      scoringAttributeObject._isdelete = dataScoringAttributes[i]["isdelete"];
      scoringAttributeObject._name = dataScoringAttributes[i]["name"];
      scoringAttributeObject._scorehigh = double.parse(dataScoringAttributes[i]["scorehigh"].toString());
      scoringAttributeObject._scorelow = double.parse(dataScoringAttributes[i]["scorelow"].toString());
      scoringAttributeObject._scoretype = dataScoringAttributes[i]["scoretype"];
      scoringAttributeObject._title = dataScoringAttributes[i]["title"];
      scoringAttributeObject._scorevalue = double.parse(dataScoringAttributes[i]["scorelow"].toString());

      listScoringAttributeObjects.add(scoringAttributeObject);
    }

    return "Success";
  }

  List<Widget> scoringAttributeList() {
    List<Widget> list = new List();
    for(int i = 0; i < listScoringAttributeObjects.length; i++) {
      if(listScoringAttributeObjects[i]._scoretype == "slider") {
        list.add(
          new Container(
            child: new Column(
              children: <Widget>[
                new Column(
                  children: <Widget>[
                    //THE SLIDER VALUE TEXT
                    new Text(
                      //CONVERT DOUBLE TYPE TO STRING WITHOUT DECIMAL POINTS
                      listScoringAttributeObjects[i]._scorevalue.toStringAsFixed(listScoringAttributeObjects[i]._scorevalue.truncateToDouble() == listScoringAttributeObjects[i]._scorevalue ? 0 : 0),
                      style: new TextStyle(
                        fontSize: 28.0,
                      ),
                    ),
                    //THE SLIDER
                    new Slider(
                      activeColor: Colors.blueAccent,
                      inactiveColor: const Color(0xFFb7d2e0),
                      min: double.parse(listScoringAttributeObjects[i]._scorelow.toString()),
                      max: double.parse(listScoringAttributeObjects[i]._scorehigh.toString()),
                      value: double.parse(listScoringAttributeObjects[i]._scorevalue.toString()),
                      onChanged: (double value) {
                        setState(() {
                          listScoringAttributeObjects[i]._scorevalue = double.parse(value.round().toString());
                        });
                      },
                    ),
                  ],
                ),
              ],
            ),
          ),
        );
      }
      else if(listScoringAttributeObjects[i]._scoretype == "text_field") {
        list.add(...);
      }
      else if(listScoringAttributeObjects[i]._scoretype == "stars") {
        list.add(...);
      }
      else if(listScoringAttributeObjects[i]._scoretype == "thumb") {
        list.add(new Container(...);
      }
    }

    return list;
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: FutureBuilder<String> (
        future: getPresentationData(),
        builder: (context, snapshot) {
          if(snapshot.hasData) {
            return new Column(
              children: <Widget>[
                new Column(
                  children: scoringAttributeList(),
                ),
              ],
            ),
          }
        },
      ),
    );
  }
}

有一些不同的小部件取决于类型,有4种类型,1种类型可能有超过1个小部件,所以我使循环依赖于来自DB的iIgot数据。

问题是我不知道为什么每次我在循环中使用setState()时,它总是再次处理循环,所以它将是一个无限循环来创建一个新的小部件,它将从头开始复制小部件(仅发生)当调用setState()时。

例如:列表中有4个数据,如果调用setState(),它将显示8个数据(显示前4个数据两次)

这是我如何将setState()放入List中的数据的示例

onChanged: (double value) {
    setState(() {
      listScoringAttributeObjects[i]._scorevalue = double.parse(value.round().toString());
    });
},

我认为问题是因为我将qazxsw poi放入List中的一些数据中。因此,当List状态更改时,它将重新呈现与List相关的任何内容。

这是真的吗?

如果是,是否有任何其他解决方案如何更改我的代码?如果不是,我的代码或我的逻辑中是否有任何错误?

谢谢。真的很期待这个解决方案,因为我真的陷入了这个,它已经是一周了:(

答案

简单地将你的setState()移动到状态变量。所以它只会获得一次getPresentationData()

triggered

重复的原因:我们可以在Slider dataChange上调用class HomePageState extends State<HomePage> with TickerProviderStateMixin { Future<String> _presentationFuture; initState() { _presentationFuture = getPresentationData() } //other contents @override Widget build(BuildContext context) { return new Scaffold( body: FutureBuilder<String> ( future: _presentationFuture, builder: (context, snapshot) { if(snapshot.hasData) { ,这将重新渲染setState,这将再次触发HomePageState调用(network

注意:如果要在滑块更改时触发网络,请在进行网络呼叫之前清除列表

getPresentationData()
另一答案

我不知道这与你的代码中的Future<String> getPresentationData() async { listScoringAttributeObjects = new List<ScoringAttribute>(); // clear data var responseScoringAttribute = await http.get( Uri.encodeFull(urlScoringAttribute), headers: {"Accept": "application/json"} ); 有什么关系。仅在使用滑块时调用它。

我认为问题是由list.add(...)引起的;在scoringAttributeList()中。执行build()时不应修改数据。

你应该假设setState()可以在任何时候重复调用。构建您的代码,以便在发生时不会导致问题。

以上是关于Fluter setState()使循环始终被调用的主要内容,如果未能解决你的问题,请参考以下文章

从 for 循环中的多个连续异步调用中调用多个“setState”挂钩

在循环中调用 setState 只会更新状态 1 次

React组件的3种状态和setState循环调用

在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState。 React 限制嵌套更新的数量以防止无限循环

React:在 setState 中设置数组对象

React Hook SetState 导致无限循环