在FutureBuilder中设置提供者的价值 [英] Setting provider value in FutureBuilder
问题描述
我有一个小部件,它向返回地图的api发出请求。我想做的是每次加载窗口小部件时都不会发出相同的请求,并将列表保存到 appState.myList
中。但。当我在 FutureBuilder
中执行 appState.myList = snapshot.data;
时,出现以下错误:
I have a widget that makes a request to an api which returns a map. What I would like to do is not make the same request every time the widget is loaded and save the list to appState.myList
. But. when I do this appState.myList = snapshot.data;
in the FutureBuilder
, I get the following error:
flutter: ══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
flutter: The following assertion was thrown while dispatching notifications for MySchedule:
flutter: setState() or markNeedsBuild() called during build.
flutter: This ChangeNotifierProvider<MySchedule> widget cannot be marked as needing to build because the
flutter: framework is already in the process of building widgets. A widget can be marked as needing to be
flutter: built during the build phase only if one of its ancestors is currently building. ...
sun.dart
文件:
class Sun extends StatelessWidget {
Widget build(BuildContext context) {
final appState = Provider.of<MySchedule>(context);
var db = PostDB();
Widget listBuild(appState) {
final list = appState.myList;
return ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return ListTile(title: Text(list[index].title));
},
);
}
Widget futureBuild(appState) {
return FutureBuilder(
future: db.getPosts(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
// appState.myList = snapshot.data;
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(title: Text(snapshot.data[index].title));
},
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Center(
child: CircularProgressIndicator(),
);
},
);
}
return Scaffold(
body: appState.myList != null
? listBuild(appState)
: futureBuild(appState));
}
}
postService.dart
文件:
class PostDB {
var isLoading = false;
Future<List<Postmodel>> getPosts() async {
isLoading = true;
final response =
await http.get("https://jsonplaceholder.typicode.com/posts");
if (response.statusCode == 200) {
isLoading = false;
return (json.decode(response.body) as List)
.map((data) => Postmodel.fromJson(data))
.toList();
} else {
throw Exception('Failed to load posts');
}
}
}
我了解< c $ c> myList 调用 notifyListeners()
,这就是导致错误的原因。希望我说对了。如果是这样,如何设置 appState.myList
并在应用中使用而不会出现上述错误?
I understand that the myList
calls notifyListeners()
and that's what causes the error. Hope I got that right. If so, how do I set appState.myList
and use in the app without getting the above error?
import 'package:flutter/foundation.dart';
import 'package:myflutter/models/post-model.dart';
class MySchedule with ChangeNotifier {
List<Postmodel> _myList;
List<Postmodel> get myList => _myList;
set myList(List<Postmodel> newValue) {
_myList = newValue;
notifyListeners();
}
}
推荐答案
这很不好,因为它可能导致小部件树不一致。一些小部件。
This is bad, as it could lead to an inconsistent widget tree. Some widget. may be built widgets using the value before mutation, while others may be using the mutated value.
解决方案是消除不一致之处。使用 ChangeNotifierProvider
,通常有两种情况:
The solution is to remove the inconsistency. Using ChangeNotifierProvider
, there are usually 2 scenarios:
-
执行的突变
ChangeNotifier
上的操作始终与创建ChangeNotifier
的操作在同一 build 中完成
The mutation performed on your
ChangeNotifier
is always done within the same build than the one that created yourChangeNotifier
.
在这种情况下,您可以直接从 ChangeNotifier
的构造函数进行调用:
In that case, you can just do the call directly from the constructor of your ChangeNotifier
:
class MyNotifier with ChangeNotifier {
MyNotifier() {
// TODO: start some request
}
}
执行的更改可能会发生,
The change performed can happen "lazily" (typically after changing page).
在这种情况下,您应该将突变包装在 addPostFrameCallback
或 Future.microtask
:
In that case, you should wrap your mutation in an addPostFrameCallback
or a Future.microtask
:
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
MyNotifier notifier;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final notifier = Provider.of<MyNotifier>(context);
if (this.notifier != notifier) {
this.notifier = notifier;
Future.microtask(() => notifier.doSomeHttpCall());
}
}
@override
Widget build(BuildContext context) {
return Container();
}
}
这篇关于在FutureBuilder中设置提供者的价值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!