在 FutureBuilder 中设置提供者值
Setting provider value in FutureBuilder
我有一个小部件可以向 api 发出请求,其中 returns 是一张地图。我想做的不是每次加载小部件时都发出相同的请求并将列表保存到 appState.myList
。但。当我在 FutureBuilder
中执行 appState.myList = snapshot.data;
时,出现以下错误:
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');
}
}
}
我知道 myList
调用了 notifyListeners()
,这就是导致错误的原因。希望我做对了。如果是这样,我如何设置 appState.myList
并在应用程序中使用而不出现上述错误?
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();
}
}
出现该异常是因为您正在同步修改其后代的小部件。
这很糟糕,因为它可能导致小部件树不一致。一些小部件。可能是使用突变前的值构建的小部件,而其他人可能正在使用突变后的值。
解决方法是消除不一致。使用ChangeNotifierProvider
,通常有2种情况:
对您的 ChangeNotifier
执行的突变始终在与创建您的 ChangeNotifier
相同的 build 中完成。
在这种情况下,您可以直接从 ChangeNotifier
:
的构造函数中调用
class MyNotifier with ChangeNotifier {
MyNotifier() {
// TODO: start some request
}
}
执行的更改可能会发生 "lazily"(通常在更改页面之后)。
在那种情况下,您应该将您的突变包装在 addPostFrameCallback
或 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();
}
}
我在使用provider的时候遇到了和你类似的问题。我的解决办法是在获取数据的时候加上WidgetsBinding.instance.addPostFrameCallback()
只需从代码中删除 notifyListeners();
。我遇到了这个错误,这就是我解决问题的方法。
我有一个小部件可以向 api 发出请求,其中 returns 是一张地图。我想做的不是每次加载小部件时都发出相同的请求并将列表保存到 appState.myList
。但。当我在 FutureBuilder
中执行 appState.myList = snapshot.data;
时,出现以下错误:
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');
}
}
}
我知道 myList
调用了 notifyListeners()
,这就是导致错误的原因。希望我做对了。如果是这样,我如何设置 appState.myList
并在应用程序中使用而不出现上述错误?
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();
}
}
出现该异常是因为您正在同步修改其后代的小部件。
这很糟糕,因为它可能导致小部件树不一致。一些小部件。可能是使用突变前的值构建的小部件,而其他人可能正在使用突变后的值。
解决方法是消除不一致。使用ChangeNotifierProvider
,通常有2种情况:
对您的
ChangeNotifier
执行的突变始终在与创建您的ChangeNotifier
相同的 build 中完成。在这种情况下,您可以直接从
的构造函数中调用ChangeNotifier
:class MyNotifier with ChangeNotifier { MyNotifier() { // TODO: start some request } }
执行的更改可能会发生 "lazily"(通常在更改页面之后)。
在那种情况下,您应该将您的突变包装在
中addPostFrameCallback
或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(); } }
我在使用provider的时候遇到了和你类似的问题。我的解决办法是在获取数据的时候加上WidgetsBinding.instance.addPostFrameCallback()
只需从代码中删除 notifyListeners();
。我遇到了这个错误,这就是我解决问题的方法。