Optimize ListView.builder children rebuilds with Riverpod

huangapple go评论122阅读模式
英文:

Optimize ListView.builder children rebuilds with Riverpod

问题

我正在开发一个使用Riverpod作为状态管理解决方案的实时聊天应用,想知道是否有办法避免在每次小部件重建时重新构建所有ListView元素。以下是小部件本身的当前代码:

@override
Widget build(BuildContext context, WidgetRef ref) {
  final chatController = ref.watch(chatControllerProvider);

  return chatController.when(
    data: (messages) => Padding(
      padding: const EdgeInsets.symmetric(vertical: 6),
      child: ListView.builder(
        itemCount: messages.length + 1,
        itemBuilder: (context, index) {
          if (index == 0) {
            return const SizedBox(height: 40);
          }
          return ChatMessageCard(
            message: messages[index - 1],
          );
        },
      ),
    ),
    error: (e, s) => Text('Error: $e'),
    loading: () => Center(child: const CircularProgressIndicator()),
  );
}

以下是controllerProvider的代码:

class ChatController extends AutoDisposeAsyncNotifier<List<Message>> {
  Future<List<Message>> _fetchMessages() async {
    final resultEither = await ref.read(chatRepositoryProvider).getMessages();

    return resultEither
        .getOrElse((failure) => throw Exception(failure.toString()));
  }

  @override
  Future<List<Message>> build() async {
    return _fetchMessages();
  }

  Future<void> addMessage(String message) async {
    final currentMessages = state;

    final resultEither =
        await ref.read(chatRepositoryProvider).sendMessage(message);

    state = resultEither.fold(
      (l) => AsyncValue.error(l.toString(), StackTrace.current),
      (r) => AsyncValue.data([...currentMessages.value!, r]),
    );
  }
}

问题是,每次我添加新消息时,小部件会像应该一样重新构建,同时所有消息卡片也会重新构建。

我希望只重新构建新的聊天消息小部件,但找不到方法来实现这一点。

英文:

Im working on a live chat application using riverpod as my state management solution and wanted to know if there was a way to avoid rebuilding all the ListView elements everytime the widget is rebuilt.
This is the current code for the widget itself:

@override
  Widget build(BuildContext context, WidgetRef ref) {
    final chatController = ref.watch(chatControllerProvider);

    return chatController.when(
      data: (messages) =&gt; Padding(
        padding: const EdgeInsets.symmetric(vertical: 6),
        child: ListView.builder(
          itemCount: messages.length + 1,
          itemBuilder: (context, index) {
            if (index == 0) {
              return const SizedBox(height: 40);
            }
            return ChatMessageCard(
              message: messages[index - 1],
            );
          },
        ),
      ),
      error: (e, s) =&gt; Text(&#39;Error: $e&#39;),
      loading: () =&gt; Center(child: const CircularProgressIndicator()),
    );
  }

Here is the code for the controllerProvider:


class ChatController extends AutoDisposeAsyncNotifier&lt;List&lt;Message&gt;&gt; {
  Future&lt;List&lt;Message&gt;&gt; _fetchMessages() async {
    final resultEither = await ref.read(chatRepositoryProvider).getMessages();

    return resultEither
        .getOrElse((failure) =&gt; throw Exception(failure.toString()));
  }

  @override
  Future&lt;List&lt;Message&gt;&gt; build() async {
    return _fetchMessages();
  }

  Future&lt;void&gt; addMessage(String message) async {
    final currentMessages = state;

    final resultEither =
        await ref.read(chatRepositoryProvider).sendMessage(message);

    state = resultEither.fold(
      (l) =&gt; AsyncValue.error(l.toString(), StackTrace.current),
      (r) =&gt; AsyncValue.data([...currentMessages.value!, r]),
    );
  }


}

The thing is every time I add a new message the widget is rebuild as it should because of the state change, and all the message cards are rebuilt as well.

I want to have rebuild only the new chat messages widgets, but can't find a way to do it.

答案1

得分: 1

使用 ListView.builder 似乎不可能。唯一的尝试方法是使用普通的 ListView 并使用 ChatMessageCard() 小部件中的 select() 方法来跟踪索引。

无论如何,如果使用 ListView.builder,只有可见的小部件将被重建,而不是整个列表。

英文:

Using ListView.builder it seems impossible. The only thing you can try is to use a normal ListView and track the index in each ChatMessageCard() widget using the select() method.

In any case, only the visible widgets will be rebuilt, not the entire list, if you use ListView.builder.

huangapple
  • 本文由 发表于 2023年3月7日 02:49:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/75654705.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定