繁体   English   中英

尝试预加载小部件时避免重建

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM