Я знаю, что могу использовать this.setState()
на родительском экране Stateful Widget, содержащем ListView.builder
, чтобы ListView перестроил свой список.
Проблема в том, что я использую другой дочерний виджет с состоянием для создания каждого из элемент ListView. В документации Flutter сказано, что сборка дерева останавливается всякий раз, когда он встречает один и тот же виджет. Это приводит к тому, что содержимое ListView не перестраивается.
Как я могу заставить ListView «аннулировать» все его дочерние элементы и принудительно перестроить весь контент без указания таких вещей, как ключи (глобальные ключи / локальные ключи)?
РЕДАКТИРОВАТЬ: упрощенный код.
class PostList extends extends StatefulWidget {
final UserModel user;
PostList({ this.user }): super();
@override
_PostListState createState() => _PostListState();
}
class _PostListState extends State<PostList> {
UserModel _user;
List<PostModel> _posts;
final _repository = Repository();
@override
void initState() {
_user = widget.user;
_repository.fetchPosts(userId: user.id)
.then((response) => this.setState(() => _posts = response)
.catchError((onError) => debugPrint(onError);
}
addNewRandomPost() {
final newPost = PostModel(text: DateTime.now().millisecondsSinceEpoch.toString());
this.setState(() => _posts = [newPost]..addAll(_posts ?? []));
}
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: "Post list"),
body: ListView.builder(
itemCount: (_posts?.length ?? 0) + 1,
itemBuilder: (context, index) {
if (index == 0)
return RaisedButton(child: Text("Add new random post"), onPressed: addNewRandomPost);
else if(_posts == null)
return Center(child: CircularProgressIndicator());
else
return PostCard(post: _posts[index - 1]);
}
)
}
}
class PostCard extends StatefulWidget {
final PostModel post;
PostCard ({ this.post }): super();
@override
_PostCardState createState() => _PostCardState();
}
class _PostCardState extends State<PostCard> {
PostModel _post;
@override
void initState() {
_post = widget.post;
}
@override
Widget build(BuildContext context) => Card(child:
Padding(padding: EdgeInsets.all(10), child: Text(_post.text));
}
Очевидно, что для виджета PostCard
есть больше кода и цели, которые я намеренно сделал его виджетом с сохранением состояния, а не без сохранения состояния. Но я просто упростил это здесь, чтобы показать, что даже с этим простым кодом, при каждом нажатии «Добавить новый случайный пост»:
- , когда изначально нет поста, список превращается из простого отображения круглого индикатора в правильно отображать новое сообщение.
- , но если там уже есть новое сообщение (
_posts
не равно нулю), если я добавляю новое сообщение в начале списка, существующая открытка, которая уже создана, не меняется Он добавляет только новый виджет почтовой открытки внизу списка, показывающий последнее сообщение в списке, которое по иронии судьбы было первыми данными, которые передаются последним. Таким образом, на всех почтовых карточках отображаются одни и те же данные, хотя содержание сообщений фактически отличается одно от другого.
Что я ожидаю после пяти нажатий кнопки:
[ Add new random post ]
1580789378
1580789373
1580789363
1580789349
1580789332
Что я получу:
[ Add new random post ]
1580789332
1580789332
1580789332
1580789332
1580789332