提供程序未重建ListView [英] Provider is not rebuilding ListView
问题描述
我正在使用提供程序进行应用程序的状态管理,但遇到了问题,提供程序无法通过ListView在需要结果的位置进行重建
I'm using provider for state management for my app, and I'm running into a problem, provider doesn't rebuild by ListView where I want the results
这是我的feed.dart
Here is my feed.dart
class Feed extends StatefulWidget {
@override
_FeedState createState() => _FeedState();
}
class _FeedState extends State<Feed> {
@override
void initState() {
PostNotifier postNotifier =
Provider.of<PostNotifier>(context, listen: false);
getGlobalPosts(postNotifier);
super.initState();
}
@override
Widget build(BuildContext context) {
AuthNotifier authNotifier =
Provider.of<AuthNotifier>(context, listen: false);
PostNotifier notifier = Provider.of<PostNotifier>(context);
return Scaffold(
body: Padding(
padding: EdgeInsets.only(left: 10, right: 10, top: 80),
child: Column(
children: <Widget>[
Expanded(
child: (notifier.postList.isEmpty) ? Center(child: CircularProgressIndicator(),) :
ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
return PostTile(
userName: notifier.postList[index].userName,
userDp: notifier.postList[index].userDp,
imgSrc: notifier.postList[index].imageUrl,
);
},
physics: ScrollPhysics(),
itemCount: notifier.postList.length,
),
),
],
),
),
);
}
}
class PostTile extends StatelessWidget {
final String imgSrc;
final String userName;
final String userDp;
PostTile(
{@required this.userName, @required this.userDp, @required this.imgSrc});
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: <Widget>[
CircleAvatar(
backgroundImage: NetworkImage(
"https://cdn0.iconfinder.com/data/icons/users-android-l-lollipop-icon-pack/24/user-128.png")
),
FlatButton(
child: Text(userName),
),
Expanded(
child: Container(),
),
RaisedButton(
child: Text(
'Follow',
style: TextStyle(color: Colors.white),
),
color: Colors.blue,
onPressed: () {},
)
],
),
),
SizedBox(
height: 20,
),
Image.network(imgSrc),
SizedBox(
height: 20,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
LikeButton(),
LikeButton(
likeBuilder: (bool isLiked) {
return Icon(
Icons.bookmark,
color: isLiked ? Colors.deepPurpleAccent : Colors.grey,
size: 30,
);
},
)
],
),
)
],
);
}
}
和我的getGlobalPosts函数-我也从firebase和用户信息中获取帖子
and my getGlobalPosts function - I get my posts from firebase and the user info too
getGlobalPosts(PostNotifier postNotifier) async {
QuerySnapshot snapshot = await Firestore.instance.collection('Posts').getDocuments();
FirebaseUser firebaseUser = await FirebaseAuth
.instance.currentUser()
.catchError((e) => print(e));
List<Post> _postList = [];
snapshot.documents.forEach((document) async {
if (firebaseUser.email != document.data["email"]) {
Post post = Post.fromMap(document.data);
//TODO: Use this to get user
await post.user.get().then((value) {
post.userName = value.data['displayName'];
post.userDp = value.data['profilePicture'];
print(post.userDp);
}).whenComplete(() {
_postList.add(post);
// print(_postList[0].userName);
print('Success');
});
} else {
print('Failed');
}
});
postNotifier.postList = _postList;
}
PostNotifier-
PostNotifier -
class PostNotifier with ChangeNotifier {
List<Post> _postList = [];
Post _currentPost;
List<Post> get postList => _postList;
Post get currentPost => _currentPost;
set postList(List<Post> postList) {
_postList = postList;
notifyListeners();
}
set currentPost(Post post) {
_currentPost = post;
notifyListeners();
}
}
我正在接收数据,但是直到我热加载后我的列表视图才会显示,仅显示CircularProgress指示器
I'm receiving the data but my listview doesn't show up until I hot reload, Only CircularProgress indicator is shown
推荐答案
通过阅读提供商文档
A typical situation where this happens is when starting an http request, where the future is stored inside the notifier:
initState() {
super.initState();
context.read<MyNotifier>().fetchSomething();
}
This is not allowed, because the modification is immediate.
Which means that some widgets may build before the mutation, while other widgets will build after the mutation. This could cause inconsistencies in your UI and is therefore not allowed.
也许Future在调用build方法之前就完成了一点,所以建议(不是最佳实践,但它是可行的)是使用微任务在框架结尾处完成Future.
Perhaps the Future completes a bit before the build method is called, so the recomendation (not the best practice, but it works) is to use a microtask to complete the future at the end of the frame
Future.microtask(() => getGlobalPosts(postNotifier););
更新
尝试使用 Future.forEach 使用Iterable.forEach不能保证它一直等到forEach内部动作结束(在forEach内部使用 async/await
来执行future,但是在forEach方法外部却不能保证它等待)知道这是未来,您不能使用 await snapshot.documents.forEach(...)
,因为该方法的类型为void)
Try using Future.forEach instead of only forEach, using Iterable.forEach doesn't guarantee that it awaits until the forEach inner actions end (inside the forEach you use async/await
to perform a future but outside the forEach method doesn't know it is a future and you cannot use await snapshot.documents.forEach(...)
because the method is of type void)
getGlobalPosts(PostNotifier postNotifier) async {
QuerySnapshot snapshot = await Firestore.instance.collection('Posts').getDocuments();
FirebaseUser firebaseUser = await FirebaseAuth
.instance.currentUser()
.catchError((e) => print(e));
List<Post> _postList = [];
//now you can await to the forEach to end before moving on to the next line
await Future.forEach(snapshot.documents, (document) async {
if (firebaseUser.email != document.data["email"]) {
Post post = Post.fromMap(document.data);
var user = await post.user.get();
post.userName = user .data['displayName'];
post.userDp = user .data['profilePicture'];
print(post.userDp);
_postList.add(post);
print('Success');
} else print('Failed')
});
//all of the iterations of the forEach should have ended by now and _postList should have all the posts added
postNotifier.postList = _postList;
}
这篇关于提供程序未重建ListView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!