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”挂钩
在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState。 React 限制嵌套更新的数量以防止无限循环