Код-ревью Middle Виджеты и три дерева обновлено
Код-ревью: список задач
Вопрос
Виджет списка задач. Найдите проблемы с деревом, ключами и контекстом.
class TodoList extends StatefulWidget {
List<Todo> todos;
TodoList(this.todos);
@override
State<TodoList> createState() => _TodoListState();
}
class _TodoListState extends State<TodoList> {
@override
Widget build(BuildContext context) {
return Column(children: [
for (var i = 0; i < widget.todos.length; i++)
TodoTile(key: ValueKey(i), todo: widget.todos[i], onDelete: () async {
await api.delete(widget.todos[i].id);
setState(() => widget.todos.removeAt(i));
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Удалено')));
}),
Text('Всего: ${widget.todos.length}', key: UniqueKey()),
]);
}
}
Коротко
Корень проблем: состояние списка лежит в виджете и мутируется. Исправление: список в State (или в провайдере), удаление через новый список, ValueKey(todo.id), проверка if (!mounted) return; после await, ListView.builder для длинных списков, никаких ключей ради ключей.
Что должен найти ревьюер
- Ошибкастрока 2Изменяемое поле в виджете, который должен быть неизменяемым: список мутируется через
widget.todos.removeAt, а родитель об этом не знает. Состояние должно жить вStateили в стейт-менеджере. - Ошибкастрока 13Ключ по индексу: после удаления состояния
TodoTileсдвинутся на соседей. НуженValueKey(todo.id). - Ошибкастрока 14После
awaitнет проверкиmounted:setStateиcontextмогут использоваться после удаления виджета. - Производительностьстрока 12
Columnстроит все элементы сразу: для длинного списка нуженListView.builder. - Производительностьстрока 18
UniqueKey()вbuildпересоздаёт элементTextна каждом перестроении. Ключ здесь не нужен. - Стильстрока 3Нет
const-конструктора иsuper.key: виджет нельзя создать какconstи передать ключ.
Разбор
Корень проблем: состояние списка лежит в виджете и мутируется. Исправление: список в State (или в провайдере), удаление через новый список, ValueKey(todo.id), проверка if (!mounted) return; после await, ListView.builder для длинных списков, никаких ключей ради ключей.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Ещё по теме «Виджеты и три дерева»
- Flutter: когда элемент переиспользуется
- Flutter: что такое BuildContext
- Виды ключей во Flutter
- StatelessWidget и StatefulWidget
- Widget, Element, RenderObject
- Flutter: когда нужен GlobalKey
- Flutter: удаление элемента списка без ключей
- Flutter: что перестраивает setState