仅重建FutureBuilder小部件



我正在从一些API获取一个随机值,并且我有一个条件。如果条件为真,我将返回一个小部件,否则我想更改随机值,并再次从API获取另一个随机值。我只需要重建FutureBuilder小部件,但我不知道如何做到这一点,我在使用setState(即setState() or markNeedsBuild() called during build.(时出错这是我迄今为止的代码:

FutureBuilder<List<dynamic>>(
future: API.get_pets(randomly_select_URL()),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<dynamic>? pet_data = snapshot.data;
if (dropDownIsSelected == true) {
var number_of_parameters = snapshot.data!.length;
var random_pet = random.nextInt(number_of_parameters);
var category =
pet_data![random_pet].category.toString();
var photoURL =
pet_data![random_pet].photoUrls.toString();
if (notEqualsIgnoreCase(category, "Kitty") ||
notEqualsIgnoreCase(category, "Puppy") ||
notEqualsIgnoreCase(category, "Fish") ||
notEqualsIgnoreCase(category, "Hedgehog") ||
notEqualsIgnoreCase(category, "Bunny") ||
photoURL.length == 0) {
print("NOT IN CATEGORY");
random_pet = random.nextInt(number_of_parameters);
}
else {
return Random_Card();
}

}

我不确定这是否是您所需要的,但我看到了两个潜在的错误。

  1. FutureBuilder应与StatefulWidget一起使用,其中Future是在initState中初始化的属性
  2. 你收到的错误告诉你:;你让我进行重建,尽管我甚至还没有完成渲染这个帧,这就是awkard"。通过设计,Flutter框架引入了这些场景

这比说的容易,所以,下面是我要尝试的(我没有测试这个(:

// Warning: pseudocode ahead!
class MyWidget extends StatefulWidget {
MyWidget({Key? key}) : super(key: key);
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Future<int>? myFuture;
@override
void initState() {
super.initState();
myFuture = // your API call
}
void requestAgain() {
setState(() {
myFuture = // another API call
});
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: myFuture,
builder: (context, snapshot) {
var output = "";
if (snapshot.connectionState == ConnectionState.waiting) output = "loading...";
if (snapshot.hasData) {
output = "Now we have: ${snapshot.data}";
if (someCondition) {
// !
WidgetsBinding.instance.addPostFrameCallback((_){
requestAgain();
});
}
}
if (snapshot.hasError) output = "Woops, something went wrong";
},
);
}
}

正如您所看到的,当someCondition为真时,我们将在Flutter完成渲染当前帧后附加您的API调用;不过,这是一个棘手的解决方案,可能是也可能不是理想的解决方案。

我强烈建议使用Riverpod来处理这个问题(请参阅FutureProvider(。

在Statefull或Stateless小部件中,混合StatefullBuilder和FutureBuilder以仅重置StatefullBuilder内容。

下面是一个使用StatelessWidget的工作示例:

class MyWidget extends StatelessWidget {
Future myFuture() async {
print("reloading");
await Future.delayed(Duration(seconds: 1));
return true;
}
@override
Widget build(BuildContext context) {
return StatefulBuilder(builder: (context, subState) {
return Column(children: [
FutureBuilder(
future: myFuture(),
builder: (context, snapShot) {
return Text('hasData:${snapShot.hasData} | at: ${DateTime.now()}');
}),
InkWell(
onTap: () {
subState(() {});
},
child: Text("Call Future"))
]);
});
}
}

只需在Future函数的顶部使用Future.delayed(Durationzero(,所有事情都会很好地进行

Future<void> testFunction(){
Future.delayed(Duration.zero);
//then type your future code here
}

或者如果你正在使用警报对话框或其他任何东西,你必须在代码的顶部使用延迟持续时间

相关内容

最新更新