feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: Keep List Items Lightweight
|
||||
impact: HIGH
|
||||
impactDescription: reduces render time for visible items during scroll
|
||||
tags: lists, performance, virtualization, hooks
|
||||
---
|
||||
|
||||
## Keep List Items Lightweight
|
||||
|
||||
List items should be as inexpensive as possible to render. Minimize hooks, avoid
|
||||
queries, and limit React Context access. Virtualized lists render many items
|
||||
during scroll—expensive items cause jank.
|
||||
|
||||
**Incorrect (heavy list item):**
|
||||
|
||||
```tsx
|
||||
function ProductRow({ id }: { id: string }) {
|
||||
// Bad: query inside list item
|
||||
const { data: product } = useQuery(['product', id], () => fetchProduct(id))
|
||||
// Bad: multiple context accesses
|
||||
const theme = useContext(ThemeContext)
|
||||
const user = useContext(UserContext)
|
||||
const cart = useContext(CartContext)
|
||||
// Bad: expensive computation
|
||||
const recommendations = useMemo(
|
||||
() => computeRecommendations(product),
|
||||
[product]
|
||||
)
|
||||
|
||||
return <View>{/* ... */}</View>
|
||||
}
|
||||
```
|
||||
|
||||
**Correct (lightweight list item):**
|
||||
|
||||
```tsx
|
||||
function ProductRow({ name, price, imageUrl }: Props) {
|
||||
// Good: receives only primitives, minimal hooks
|
||||
return (
|
||||
<View>
|
||||
<Image source={{ uri: imageUrl }} />
|
||||
<Text>{name}</Text>
|
||||
<Text>{price}</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**Move data fetching to parent:**
|
||||
|
||||
```tsx
|
||||
// Parent fetches all data once
|
||||
function ProductList() {
|
||||
const { data: products } = useQuery(['products'], fetchProducts)
|
||||
|
||||
return (
|
||||
<LegendList
|
||||
data={products}
|
||||
renderItem={({ item }) => (
|
||||
<ProductRow name={item.name} price={item.price} imageUrl={item.image} />
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**For shared values, use Zustand selectors instead of Context:**
|
||||
|
||||
```tsx
|
||||
// Incorrect: Context causes re-render when any cart value changes
|
||||
function ProductRow({ id, name }: Props) {
|
||||
const { items } = useContext(CartContext)
|
||||
const inCart = items.includes(id)
|
||||
// ...
|
||||
}
|
||||
|
||||
// Correct: Zustand selector only re-renders when this specific value changes
|
||||
function ProductRow({ id, name }: Props) {
|
||||
// use Set.has (created once at the root) instead of Array.includes()
|
||||
const inCart = useCartStore((s) => s.items.has(id))
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Guidelines for list items:**
|
||||
|
||||
- No queries or data fetching
|
||||
- No expensive computations (move to parent or memoize at parent level)
|
||||
- Prefer Zustand selectors over React Context
|
||||
- Minimize useState/useEffect hooks
|
||||
- Pass pre-computed values as props
|
||||
|
||||
The goal: list items should be simple rendering functions that take props and
|
||||
return JSX.
|
||||
Reference in New Issue
Block a user