[英]Avoid rebuilding when trying to preload widgets
我正在嘗試構建一個類似於 tinder 的系統,其中有一堆卡片可供用戶刷卡,並且總是預加載接下來的幾張卡片。
為此,我有一個Stack
小部件,它構建了一系列卡片子小部件,並為它們提供要加載的內容的 id:
class PostCardStack extends StatefulWidget {
const PostCardStack({Key key, this.postIds, this.onCardDismissed})
: super(key: key);
final List<String> postIds;
final Function onCardDismissed;
@override
_PostCardStackState createState() => _PostCardStackState();
}
class _PostCardStackState extends State<PostCardStack> {
ValueNotifier<double> _notifier = ValueNotifier<double>(0.0);
_buildCardStack() {
List<Widget> cards = [];
for (String postId in widget.postIds) {
int idx = widget.postIds.indexOf(postId);
if (postId == widget.postIds.first) {
cards.add(CustomDismissible(
resizeDuration: null,
dismissThresholds: {CustomDismissDirection.horizontal: 0.2},
notifier: _notifier,
key: Key(postId),
onDismissed: (direction) {
_notifier.value = 0.0;
widget.onCardDismissed(postId);
},
child: SlidablePanel(
panel: AnimatedBuilder(
animation: _notifier,
child: PostCard(
postId: postId,
),
builder: (context, _) {
return Opacity(
opacity: 1 - _notifier.value,
child: PostCard(
postId: postId,
));
}),
)));
} else {
cards.add(AnimatedBuilder(
animation: _notifier,
child: PostCard(
postId: postId,
),
builder: (context, _) {
return Opacity(
opacity: lerpDouble(1 - (0.1 * idx), 1 - ((0.1 * idx) - 0.1),
_notifier.value),
child: Transform(
origin: null,
alignment: Alignment.bottomCenter,
transform: Matrix4.translationValues(
0.0,
lerpDouble(
-idx * 35, (-idx * 35 + 35), _notifier.value),
0.0)
..scale(
lerpDouble(1 - (0.1 * idx), 1 - ((0.1 * idx) - 0.1),
_notifier.value),
lerpDouble(1 - (0.1 * idx), 1 - ((0.1 * idx) - 0.1),
_notifier.value),
1),
child: PostCard(
postId: postId,
)));
}));
}
}
return cards.reversed.toList();
}
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomCenter, children: _buildCardStack());
}
}
在PostCard
小部件中,我使用postId
參數來獲取卡片信息並在它准備好時構建它。
class PostCard extends StatefulWidget {
const PostCard({Key key, this.postId}) : super(key: key);
final String postId;
@override
_PostCardState createState() => _PostCardState();
}
class _PostCardState extends State<PostCard> {
PostModel post;
@override
void initState() {
super.initState();
print("${widget.postId} mounted");
_fetchPost(widget.postId);
}
@override
void dispose() {
print("${widget.postId} disposed");
super.dispose();
}
_fetchPost(String postId) async {
PostModel fullPost = await blablaFirestore(postId);
setState(() {
post = fullPost;
});
}
@override
Widget build(BuildContext context) {
return Container(
height: 300,
child: Align(
alignment: Alignment.topCenter,
child: Text(post == null ? "Loading..." : post.text),
),
);
}
}
一切正常,除非堆棧組件中的 id 列表的任何元素發生更改,所有子卡都被重建,因此丟失了之前加載的 state 並且必須再次獲取數據。
如果 id 列表中只有一個元素發生變化,為什么每張卡片都在重建? 我在這里錯過了什么嗎? :)
編輯:在標記為重復的問題中,問題是具有副作用的構建方法。 我不相信這里是這種情況。 就我而言,問題是 PostCards 小部件的 state 沒有保留,即使它們使用完全相同的參數(postId)重建
干杯!
當setState
被調用時, build
function 被再次調用,並且所有PostCard
小部件將被重新創建,因為它們是在build
function 中創建的。
這就是說,如果PostCard
是一個Stateful
的小部件,那么 state 不應該被破壞(例如 initState 不會被調用)。 但是您可能會失去對它們的引用,這可能就是您的代碼沒有按預期運行的原因(很難從您的代碼中分辨出來)。
也許您應該將這段代碼稱為有Stateful
小部件的小部件並創建一個List<PostCard> postCards
變量來存儲您的卡片,這樣您就可以在initState
function 中初始化postCards
並且在您調用setState
時不會重新創建它們,從而保留參考。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.