Код-ревью Middle Списки и производительность обновлено

Код-ревью: лента заказов

Вопрос

Экран истории заказов. Найдите проблемы списка.

export function Orders() {
  const [orders, setOrders] = useState<Order[]>([]);
  const [selected, setSelected] = useState<string | null>(null);
  const loadMore = async () => {
    const page = await api.orders(orders.length);
    setOrders([...orders, ...page]);
  };
  return (
    <ScrollView>
      <FlatList
        data={orders}
        keyExtractor={(_, i) => String(i)}
        renderItem={({ item }) => (
          <OrderRow order={item} selected={item.id === selected} onPress={() => setSelected(item.id)} />
        )}
        onEndReached={loadMore}
      />
    </ScrollView>
  );
}

Коротко

Список не кладут в ScrollView той же ориентации (шапку делают через ListHeaderComponent). Ключи по id, загрузка с флагом и курсором, функциональное обновление состояния, memo строк и extraData для внешнего состояния.

Что должен найти ревьюер

  1. Ошибкастрока 9
    FlatList внутри вертикального ScrollView: виртуализация ломается, все элементы рендерятся, RN выводит предупреждение.
  2. Ошибкастрока 12
    Ключ по индексу: при обновлении списка строки перепутают состояние. Использовать item.id.
  3. Ошибкастрока 4
    Нет флага загрузки: onEndReached может вызваться повторно и загрузить одну страницу дважды. Нет обработки ошибки и признака конца.
  4. Ошибкастрока 5
    Пагинация по смещению orders.length даёт дубли и пропуски, если на сервере появились новые заказы. Лучше курсор.
  5. Ошибкастрока 6
    [...orders, ...page] берёт orders из замыкания: при двух быстрых вызовах одна страница потеряется. Использовать функциональное обновление setOrders(prev => ...).
  6. Производительностьстрока 13
    Инлайновый renderItem и новая стрелка onPress на каждый рендер: строки не могут быть мемоизированы. Плюс selected не передан в extraData.

Разбор

Список не кладут в ScrollView той же ориентации (шапку делают через ListHeaderComponent). Ключи по id, загрузка с флагом и курсором, функциональное обновление состояния, memo строк и extraData для внешнего состояния. Ещё проще взять useInfiniteQuery.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.

Термины по теме