'Reload entire list in Flutter, or modify single element at an index?

In flutter, is there any way to possibly modify one element of a list and then only re-render that widget? I imagine having to re-render the entire list just for one element being modified isn't the fastest solution. I've provided an example.

import 'package:flutter/material.dart';

void main() {
  runApp(
    MyApp(
      items: List<String>.generate(10000, (i) => 'Item $i'),
    ),
  );
}

class MyApp extends StatelessWidget {
  final List<String> items;

  const MyApp({Key? key, required this.items}) : super(key: key);

  final TextController textController =
  getIt<TextController>();

  @override
  Widget build(BuildContext context) {
    const title = 'Long List';

    return MaterialApp(
      title: title,
      home: ValueListenableBuilder(
      valueListenable: textController.textEditNotifer,
      builder: (context, List? textList, child) {
        return ListView.builder(
          itemCount: textList.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(textList[index]),
            );
          },
        ),
      ),
    );
  }
}

Let's assume I click on one of the list tile's to edit that tile's text(and it has the logic to notify the textEditNotifier when doing so). I'm not aware of any better solution than just reloading the entire list, that is not an extreme hassle. Is the performance hit significant in that it's worthwhile to explore other means which only re-render the individual list tile that was edited?



Solution 1:[1]

One way I could think of is to call setState inside the itemBuilder of your ListView. Any changes made within the itemBuilder only applies to that particular item.

Instead of directly returning a ListTile inside your itemBuilder, I would recommend creating a separate Stateful Widget and referring that inside your itemBuilder. This Stateful Widget returns those individual items of the ListView.

Calling setState when that particular item being edited would result only in that element rebuilding because setState would rebuild only that separate widget and not the entire ListView.

For example, instead of building a ListView like this:

...
ListView.builder(
                  shrinkWrap: true,
                  itemCount: textList.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text(textList[index]),
                    );
...

Do this:

...
    ListView.builder(
                      shrinkWrap: true,
                      itemCount: textList.length,
                      itemBuilder: (context, index) {
                        return TextItem();
...

Where TextItem() would be:

class TextItem extends StatefulWidget {
  const TextItem({Key? key}) : super(key: key);

  @override
  State<TextItem> createState() => _TextItemState();
}

class _TextItemState extends State<TextItem> {
  @override
  Widget build(BuildContext context) {
  return ListTile(
    title: Text(textList[index]),
  );
...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Novice Coder