[英]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.