FlashList high-performance list patterns. Use when implementing lists.
Replaces FlatList with Shopify's high-performance FlashList for scrollable lists with 50+ items. Use FLASHLIST ALWAYS when implementing lists—triggers on any list creation or performance issues.
/plugin marketplace add IvanTorresEdge/molcajete.ai/plugin install react-native@Molcajete.aiThis skill inherits all available tools. When active, it can use any tool Claude has access to.
This skill covers Shopify's FlashList for high-performance lists.
Use this skill when:
FLASHLIST ALWAYS - FlashList is 10x faster than FlatList. Use it for all lists.
npm install @shopify/flash-list
import { FlashList } from '@shopify/flash-list';
interface Item {
id: string;
title: string;
}
function ItemList({ items }: { items: Item[] }): React.ReactElement {
return (
<FlashList
data={items}
renderItem={({ item }) => (
<View className="p-4 border-b border-gray-200">
<Text className="text-lg">{item.title}</Text>
</View>
)}
estimatedItemSize={60} // Required!
keyExtractor={(item) => item.id}
/>
);
}
// Required for FlashList to calculate recycling
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={80} // Average height of items in pixels
/>
import { useCallback, memo } from 'react';
const ItemCard = memo(function ItemCard({ item }: { item: Item }) {
return (
<View className="p-4">
<Text>{item.title}</Text>
</View>
);
});
function ItemList({ items }: { items: Item[] }): React.ReactElement {
const renderItem = useCallback(
({ item }: { item: Item }) => <ItemCard item={item} />,
[]
);
return (
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={60}
/>
);
}
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={60}
keyExtractor={(item) => item.id} // Unique stable key
/>
interface ListItem {
id: string;
type: 'header' | 'item' | 'separator';
data: unknown;
}
<FlashList
data={items}
renderItem={({ item }) => {
switch (item.type) {
case 'header':
return <HeaderComponent data={item.data} />;
case 'separator':
return <SeparatorComponent />;
default:
return <ItemComponent data={item.data} />;
}
}}
getItemType={(item) => item.type} // Enables better recycling
estimatedItemSize={60}
/>
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={60}
overrideItemLayout={(layout, item) => {
// Set exact size for different item types
if (item.type === 'header') {
layout.size = 100;
} else if (item.type === 'separator') {
layout.size = 20;
} else {
layout.size = 60;
}
}}
/>
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={150}
horizontal
/>
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={180}
numColumns={2}
/>
import { useState } from 'react';
import { RefreshControl } from 'react-native';
function RefreshableList(): React.ReactElement {
const [refreshing, setRefreshing] = useState(false);
const onRefresh = async () => {
setRefreshing(true);
await fetchNewData();
setRefreshing(false);
};
return (
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={60}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
/>
);
}
function InfiniteList(): React.ReactElement {
const [items, setItems] = useState<Item[]>([]);
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
const loadMore = async () => {
if (loading || !hasMore) return;
setLoading(true);
const newItems = await fetchMoreItems();
if (newItems.length === 0) {
setHasMore(false);
} else {
setItems((prev) => [...prev, ...newItems]);
}
setLoading(false);
};
return (
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={60}
onEndReached={loadMore}
onEndReachedThreshold={0.5}
ListFooterComponent={loading ? <ActivityIndicator /> : null}
/>
);
}
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={60}
ListEmptyComponent={
<View className="flex-1 items-center justify-center p-8">
<Text className="text-gray-500">No items found</Text>
</View>
}
/>
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={60}
ListHeaderComponent={
<View className="p-4 bg-gray-100">
<Text className="text-xl font-bold">Items</Text>
</View>
}
ListFooterComponent={
<View className="p-4">
<Text className="text-gray-500 text-center">End of list</Text>
</View>
}
/>
interface Section {
title: string;
data: Item[];
}
// Use SectionList-like pattern
<FlashList
data={flattenedData}
renderItem={({ item }) => {
if (item.isHeader) {
return <StickyHeader title={item.title} />;
}
return <ItemCard item={item} />;
}}
stickyHeaderIndices={headerIndices}
estimatedItemSize={60}
getItemType={(item) => (item.isHeader ? 'header' : 'item')}
/>
import { useRef } from 'react';
import { FlashList } from '@shopify/flash-list';
function ScrollableList(): React.ReactElement {
const listRef = useRef<FlashList<Item>>(null);
const scrollToTop = () => {
listRef.current?.scrollToOffset({ offset: 0, animated: true });
};
const scrollToIndex = (index: number) => {
listRef.current?.scrollToIndex({ index, animated: true });
};
return (
<>
<FlashList
ref={listRef}
data={items}
renderItem={renderItem}
estimatedItemSize={60}
/>
<Button onPress={scrollToTop}>Scroll to Top</Button>
</>
);
}
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={60}
keyExtractor={(item) => item.id}
getItemType={(item) => item.type}
numColumns={1}
horizontal={false}
inverted={false}
showsVerticalScrollIndicator={true}
showsHorizontalScrollIndicator={false}
onEndReached={loadMore}
onEndReachedThreshold={0.5}
refreshControl={<RefreshControl />}
ListHeaderComponent={<Header />}
ListFooterComponent={<Footer />}
ListEmptyComponent={<EmptyState />}
ItemSeparatorComponent={() => <View className="h-px bg-gray-200" />}
/>
// Enable debug logs in development
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={60}
// Debug overlay shows recycling info
/>
estimatedItemSize is requiredgetItemType for different item layoutsThis skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.