FlashList vs FlatList
Trade-offs, recycling, and migration checklist for Shopify FlashList - when the default list isn't fast enough.
Busque em todas as páginas da documentação
Trade-offs, recycling, and migration checklist for Shopify FlashList - when the default list isn't fast enough.
Cartão de receita de referência rápida - pronto para copiar e colar.
import { FlashList } from "@shopify/flash-list";
import { StyleSheet, Text, View } from "react-native";
interface Post {
id: string;
title: string;
}
const ESTIMATED_ROW_HEIGHT = 88;
export function PostFeed({ posts }: { posts: Post[] }) {
return (
<FlashList
data={posts}
estimatedItemSize={ESTIMATED_ROW_HEIGHT}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View style={styles.row}>
<Text style={styles.title} numberOfLines={2}>
{item.title}
</Text>
</View>
)}
ItemSeparatorComponent={() => <View style={styles.separator} />}
/>
);
}
const styles = StyleSheet.create({
row: { paddingHorizontal: 16, paddingVertical: 12, backgroundColor: "#fff" },
title: { fontSize: 16, fontWeight: "600", color: "#0f172a" },
separator: { height: 8 },
});Quando usar isso: Feeds com muitas imagens, timelines de chat ou qualquer lista onde a análise de desempenho mostra quedas de quadros durante a rolagem rápida em dispositivos Android de gama média.
import { memo, useCallback } from "react";
import { FlashList } from "@shopify/flash-list";
import { Image, StyleSheet, Text, View } from "react-native";
interface Product {
id: string;
name: string;
price: string;
imageUrl: string;
}
const PRODUCTS: Product[] = Array.from({ length: 200 }, (_, i) => ({
id: `p-${i}`,
name: `Product ${i + 1}`,
price: `$${(9.99 + (i % 50)).toFixed(2)}`,
imageUrl: `https://picsum.photos/seed/${i}/120/120`,
}));
const ESTIMATED_ROW_HEIGHT = 96;
const ProductRow = memo(function ProductRow({ item }: { item: Product }) {
return (
<View style={styles.row}>
<Image source={{ uri: item.imageUrl }} style={styles.thumb} />
<View style={styles.meta}>
<Text style={styles.name} numberOfLines={1}>
{item.name}
</Text>
<Text style={styles.price}>{item.price}</Text>
</View>
</View>
);
});
export default function ProductFeedScreen() {
const renderItem = useCallback(
({ item }: { item: Product }) => <ProductRow item={item} />,
[],
);
return (
<View style={styles.screen}>
<FlashList
data={PRODUCTS}
estimatedItemSize={ESTIMATED_ROW_HEIGHT}
keyExtractor={(item) => item.id}
renderItem={renderItem}
drawDistance={250}
contentContainerStyle={styles.list}
/>
</View>
);
}
const styles = StyleSheet.create({
screen: { flex: 1, backgroundColor: "#f8fafc" },
list: { paddingVertical: 8 },
row: {
flexDirection: "row",
alignItems: "center",
gap: 12,
paddingHorizontal: 16,
paddingVertical: 10,
backgroundColor: "#fff",
minHeight: ESTIMATED_ROW_HEIGHT,
},
thumb: { width: 72, height: 72, borderRadius: 8, backgroundColor: "#e2e8f0" },
meta: { flex: 1 },
name: { fontSize: 16, fontWeight: "600", color: "#0f172a" },
price: { fontSize: 14, color: "#2563eb", marginTop: 4 },
});O que isso demonstra:
estimatedItemSize definido para a altura típica da linha - necessário para a matemática de layout do FlashList.minHeight na linha alinha o tamanho renderizado com a estimativa para rolagem estável.memo em ProductRow emparelha com a reciclagem de views - as linhas devem tolerar reutilização sem estado obsoleto.drawDistance={250} pré-renderiza um pouco além da viewport para reduzir flashes em branco durante a rolagem rápida.keyExtractor / renderItem do FlatList - a migração é principalmente adição de props.estimatedItemSize porque ele dimensiona o conteúdo antes que todas as linhas sejam medidas - a estimativa impulsiona os cálculos de deslocamento até que a medição real chegue.data, renderItem, keyExtractor, separadores, cabeçalhos, onEndReached.| Aspecto | FlatList | FlashList |
|---|---|---|
| Reciclagem | Monta/desmonta linhas | Reutiliza um pool fixo de views |
| Dica de tamanho | getItemLayout opcional | estimatedItemSize obrigatório |
| Altura variável | Funciona; remede conforme necessário | Funciona; ajuste a estimativa + overrideItemLayout |
| Bundle | Embutido no RN | Dependência @shopify/flash-list |
| Superfície da API | Superset (maduro) | Quase substituição direta; algumas diferenças de props |
| Melhor ajuste | Listas curtas/médias, configurações | Feeds longos, imagens, chat, grades de marketplace |
npx expo install @shopify/flash-listFlatList → FlashList de @shopify/flash-listestimatedItemSize: Meça uma linha típica nas DevTools ou especificações de design (inclua padding).item.minHeight ou altura fixa próxima à estimativa quando possível.overrideItemLayout por tipo de item ou listas separadas por variante de layout.onEndReached: O comportamento do limite é semelhante, mas verifique as proteções de paginação.FlashList com cabeçalhos fixos ou mantenha SectionList até precisar do ganho de desempenho.console.time em torno de sessões de rolagem.// Antes
import { FlatList } from "react-native";
<FlatList data={items} renderItem={...} keyExtractor={...} />
// Depois
import { FlashList } from "@shopify/flash-list";
<FlashList
data={items}
estimatedItemSize={72}
renderItem={...}
keyExtractor={...}
/>| Prop | Propósito |
|---|---|
estimatedItemSize | Altura média da linha em dp - obrigatório |
drawDistance | Distância em pixels além da viewport para pré-renderizar (padrão ~250) |
overrideItemLayout | Sobrescrita de tamanho por índice para linhas heterogêneas |
estimatedListSize | { height, width } quando o tamanho da lista é conhecido antecipadamente |
getItemType | Retorna uma string de tipo para que os pools de reciclagem separem os layouts |
<FlashList
data={items}
estimatedItemSize={120}
getItemType={(item) => (item.pinned ? "pinned" : "normal")}
overrideItemLayout={(layout, item) => {
layout.size = item.pinned ? 160 : 96;
}}
renderItem={renderItem}
/>useState dentro de uma linha pode mostrar o estado do item anterior por um frame.useEffect sem dependências adequadas disparam no item errado.item ou em mapas pai (expandedIds); as linhas devem ser funções puras das props.import type { FlashListProps, ListRenderItem } from "@shopify/flash-list";
interface Article {
id: string;
headline: string;
}
type ArticleListProps = Pick<
FlashListProps<Article>,
"data" | "onEndReached" | "refreshing" | "onRefresh"
> & {
onPress: (article: Article) => void;
};
function ArticleList({ data, onPress, ...rest }: ArticleListProps) {
const renderItem: ListRenderItem<Article> = useCallback(
({ item }) => <ArticleRow article={item} onPress={() => onPress(item)} />,
[onPress],
);
return (
<FlashList
data={data}
estimatedItemSize={104}
keyExtractor={(item) => item.id}
renderItem={renderItem}
{...rest}
/>
);
}@shopify/flash-list, não de react-native.FlashListProps<T> espelha FlatListProps<T> para a maioria das props de lista.| Parâmetro | Tipo | Descrição |
|---|---|---|
estimatedItemSize | number | Altura média do item em pixels independentes de densidade - obrigatório |
data | readonly T[] | Array de origem (o mesmo que FlatList) |
renderItem | ListRenderItem<T> | Renderizador de linha - deve ser estável para reciclagem |
drawDistance | number | Distância de pré-renderização além das bordas da viewport |
overrideItemLayout | (layout, item, index) => void | Define layout.size para alturas de item conhecidas |
getItemType | (item, index) => string | Separa pools de reciclagem por variante de layout |
Falta de estimatedItemSize - FlashList avisa e recorre a suposições de layout ruins; a rolagem parece quebrada. Correção: Sempre defina-o; meça linhas reais no simulador.
Estimativa longe da realidade - Uma estimativa de 200px em linhas de 80px causa um salto quando a medição corrige. Correção: Meça a altura da linha p50; use overrideItemLayout para valores discrepantes.
Componentes de linha com estado - useState para "curtido" dentro da linha mostra o estado do item anterior após a reciclagem. Correção: Armazene o estado de interação no pai/item ou em mapas extraData.
Migrar sem memo - A reciclagem amplifica re-renderizações desnecessárias dentro das linhas. Correção: Use memo nos componentes de linha; renderItem estável com useCallback.
Usar FlashList para 10 linhas de configurações - Dependência extra e ajuste fino sem ganho mensurável. Correção: Mantenha FlatList ou ScrollView até que a análise de desempenho prove a necessidade.
Ignorar dimensões de imagem - Imagens carregando de forma assíncrona mudam a altura da linha após o primeiro layout, causando um salto em ambos os tipos de lista; pior quando a estimativa está errada. Correção: width/height fixos na Image, fundo de placeholder ou proporção conhecida.
Assumir 100% de paridade de API - Algumas props de borda diferem; teste ListHeaderComponent, numColumns e rolagem aninhada. Correção: Leia a documentação do @shopify/flash-list para sua versão; execute o checklist de migração no dispositivo.
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
FlatList | Listas padrão, configurações, < 100 linhas, sem reclamações de desempenho | Análise de desempenho mostra lentidão na rolagem nos dispositivos de destino |
FlashList | Feeds longos, imagens, chat, marketplace | Listas triviais onde o tamanho do bundle é mais importante |
SectionList | Dados agrupados com cabeçalhos de seção fixos | Feed plano de tipo único - FlashList é mais simples |
Legend List / outras listas da comunidade | Avaliando alternativas ao FlashList | Você quer compatibilidade com Expo mantida pelo Shopify primeiro |
ScrollView + map | Conteúdo estático muito curto | Qualquer lista que role por segundos a 60 fps |
Quase - troque a importação, adicione estimatedItemSize e audite os componentes de linha para segurança de reciclagem. A maioria das props (data, renderItem, keyExtractor, onEndReached, refresh) funciona da mesma forma. Teste seus layouts específicos de cabeçalho/rodapé e multi-colunas.
FlashList posiciona as linhas antes que todas sejam medidas. A estimativa impulsiona a matemática do deslocamento de rolagem até que a altura real de cada linha seja conhecida. Sem ela, a lista não pode virtualizar eficientemente.
Meça uma linha renderizada típica no inspetor de layout, incluindo padding e separadores. Use a mediana da altura se as linhas variarem ligeiramente. Para tipos mistos, use getItemType + overrideItemLayout.
Em vez de destruir uma view de linha quando ela sai da tela, FlashList a reutiliza para os dados de um novo item. A mesma árvore de views nativas é reutilizada - como a reutilização de células UITableView no iOS. Componentes de linha não devem conter estado local obsoleto.
Sim - npx expo install @shopify/flash-list fixa uma versão compatível para o seu SDK. Nenhum código nativo personalizado é necessário em fluxos de trabalho Expo padrão.
FlashList suporta cabeçalhos fixos e layouts heterogêneos, mas SectionList ainda é a escolha ergonômica para agrupamento { title, data }. Migre a renderização de itens para padrões FlashList quando o feed plano for o gargalo.
Distância em pixels além da viewport visível onde FlashList pré-renderiza itens. Valores mais altos reduzem flashes em branco durante a rolagem rápida ao custo de mais trabalho por frame. O padrão geralmente é bom; aumente em feeds com muitas imagens se você vir cintilação.
FlashList usa estimatedItemSize e overrideItemLayout em vez disso. overrideItemLayout permite que você defina layout.size por índice quando as alturas são conhecidas sem medição.
Sim - layouts de grade são suportados. Defina numColumns e certifique-se de que estimatedItemSize reflita a altura da linha (não a largura da célula). Teste o espaçamento horizontal e os pools de reciclagem para células de grade.
estimatedItemSize da altura real.minHeight nas linhas.overrideItemLayout para variantes conhecidas altas/baixas.Sim - especialmente com reciclagem. Combine memo no componente de linha, renderItem estável e estado apenas de props. Veja Otimização de Desempenho de Lista.
FlashList suporta o mesmo padrão - passe estado externo que afeta a renderização da linha para que as views recicladas sejam atualizadas quando a seleção ou o tema mudarem.
Para listas muito curtas, FlatList evita o ajuste da estimativa e o pacote extra. Meça - não migre preventivamente.
Veja @shopify/flash-list em Bibliotecas Essenciais para instalação, plugins de configuração e props avançadas.
Mesmo padrão onEndReached / onEndReachedThreshold do FlatList. Proteja as buscas com uma ref de carregamento. Veja Scroll Infinito e Paginação.
memo, manipuladores estáveis e conceitos de windowSize que se aplicam a ambas as listasVersões da Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0 e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026