Skip to content

Commit babe294

Browse files
authored
Merge pull request #13 from maximcoding/fix/react-navigation-static-config-v1.0.1
Fix/react navigation static config v1.0.1
2 parents 0577256 + 6e4e819 commit babe294

File tree

69 files changed

+1084
-3206
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1084
-3206
lines changed

.claude/skills/vercel-react-native-skills/AGENTS.md

Lines changed: 12 additions & 2891 deletions
Large diffs are not rendered by default.

.claude/skills/vercel-react-native-skills/README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ optimized for agents and LLMs.
1010
- `_template.md` - Template for creating new rules
1111
- `area-description.md` - Individual rule files
1212
- `metadata.json` - Document metadata (version, organization, abstract)
13-
- **`AGENTS.md`** - Compiled output (generated)
13+
- **`AGENTS.md`** - Short pointer + stack summary for this starter (not a compiled rollup)
1414

1515
## Rules
1616

@@ -21,8 +21,7 @@ optimized for agents and LLMs.
2121

2222
### List Performance (HIGH)
2323

24-
- `list-performance-virtualize.md` - Use virtualized lists (LegendList,
25-
FlashList)
24+
- `list-performance-virtualize.md` - Use virtualized lists (FlashList primary)
2625
- `list-performance-function-references.md` - Keep stable object references
2726
- `list-performance-callbacks.md` - Hoist callbacks to list root
2827
- `list-performance-inline-objects.md` - Avoid inline objects in renderItem
@@ -44,7 +43,7 @@ optimized for agents and LLMs.
4443

4544
### Navigation (HIGH)
4645

47-
- `navigation-native-navigators.md` - Use native stack and native tabs
46+
- `navigation-native-navigators.md` - Native stack + bottom tabs (this template)
4847

4948
### React State (MEDIUM)
5049

.claude/skills/vercel-react-native-skills/SKILL.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Reference these guidelines when:
2828
- Configuring native modules or fonts
2929
- Structuring projects with native dependencies
3030

31-
> **Project constraints:** Bare workflow only, no Nativewind, no Tailwind. Styling uses `StyleSheet.create()` with theme tokens only. Font setup uses `react-native-asset`. Use React Native's built-in `Image` or `react-native-fast-image`.
31+
> **Project constraints:** Bare workflow only, no Nativewind, no Tailwind. Styling uses `StyleSheet.create()` with theme tokens only. Font setup uses `react-native-asset`. Use React Native's built-in `Image` or `react-native-fast-image`. **Lists:** prefer `@shopify/flash-list` (examples in `rules/` use FlashList). **Monorepo** rules apply only in a multi-package repo; this starter is a **single app**—skip them unless you adopt a monorepo layout.
3232
3333
## Rule Categories by Priority
3434

@@ -64,7 +64,7 @@ Reference these guidelines when:
6464

6565
### 3. Navigation (HIGH)
6666

67-
- `navigation-native-navigators` - Use native stack and native tabs over JS navigators
67+
- `navigation-native-navigators` - Use `@react-navigation/native-stack` for stacks; this template uses `@react-navigation/bottom-tabs` with a custom tab bar (optional: Callstack native bottom tabs if you add the dependency)
6868

6969
### 4. UI Patterns (HIGH)
7070

@@ -93,8 +93,8 @@ Reference these guidelines when:
9393

9494
### 7. Monorepo (MEDIUM)
9595

96-
- `monorepo-native-deps-in-app` - Keep native dependencies in app package
97-
- `monorepo-single-dependency-versions` - Use single versions across packages
96+
- `monorepo-native-deps-in-app` - Keep native dependencies in app package (**ignore** in single-package apps)
97+
- `monorepo-single-dependency-versions` - Single versions across packages (**ignore** unless monorepo)
9898

9999
### 8. Configuration (LOW)
100100

@@ -118,6 +118,6 @@ Each rule file contains:
118118
- Correct code example with explanation
119119
- Additional context and references
120120

121-
## Full Compiled Document
121+
## Pointer doc
122122

123-
For the complete guide with all rules expanded: `AGENTS.md`
123+
[`AGENTS.md`](AGENTS.md) in this folder summarizes the stack and links to repository-wide [`AGENTS.md`](../../../AGENTS.md). **All expanded examples** live under `rules/`—there is no monolithic compiled rollup (avoids drift from this starter).

.claude/skills/vercel-react-native-skills/rules/_sections.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ runtime crashes or broken UI.
1414
## 2. List Performance (list-performance)
1515

1616
**Impact:** HIGH
17-
**Description:** Optimizing virtualized lists (FlatList, LegendList, FlashList)
17+
**Description:** Optimizing virtualized lists (FlatList, **FlashList** in this starter)
1818
for smooth scrolling and fast updates.
1919

2020
## 3. Animation (animation)

.claude/skills/vercel-react-native-skills/rules/fonts-config-plugin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ tags: fonts, performance, config-plugin
1010
For managed workflow: use the font config plugin to embed fonts at build time instead of
1111
`useFonts` or `Font.loadAsync`. Embedded fonts are more efficient.
1212

13-
**For bare React Native:** use `react-native-asset` via `npm run link` to link font files. See AGENTS.md.
13+
**For bare React Native:** use `react-native-asset` via `npm run link` to link font files. See repository root **`AGENTS.md`** (project-wide rules).
1414

1515
**Incorrect (async font loading):**
1616

.claude/skills/vercel-react-native-skills/rules/list-performance-callbacks.md

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,65 @@
22
title: Hoist callbacks to the root of lists
33
impact: MEDIUM
44
impactDescription: Fewer re-renders and faster lists
5-
tags: tag1, tag2
5+
tags: lists, performance, flashlist, callbacks
66
---
77

88
## List performance callbacks
99

10-
**Impact: HIGH (Fewer re-renders and faster lists)**
10+
When passing behavior into list rows, **avoid creating new function instances inside `renderItem` on every parent render**. Hoist stable handlers to the list parent and pass **ids or item references** into memoized row components.
1111

12-
When passing callback functions to list items, create a single instance of the
13-
callback at the root of the list. Items should then call it with a unique
14-
identifier.
12+
**Incorrect (creates a new callback per row, per parent render):**
1513

16-
**Incorrect (creates a new callback on each render):**
14+
```tsx
15+
import { FlashList } from '@shopify/flash-list'
1716

18-
```typescript
1917
return (
20-
<LegendList
18+
<FlashList
19+
data={items}
20+
estimatedItemSize={72}
2121
renderItem={({ item }) => {
22-
// bad: creates a new callback on each render
2322
const onPress = () => handlePress(item.id)
24-
return <Item key={item.id} item={item} onPress={onPress} />
23+
return <Row item={item} onPress={onPress} />
2524
}}
2625
/>
2726
)
2827
```
2928

30-
**Correct (a single function instance passed to each item):**
29+
**Correct (stable `renderItem`; row closes over `item` only inside memoized child):**
3130

32-
```typescript
33-
const onPress = useCallback(() => handlePress(item.id), [handlePress, item.id])
31+
```tsx
32+
import { FlashList } from '@shopify/flash-list'
33+
import { memo, useCallback } from 'react'
34+
import { Pressable } from 'react-native'
35+
36+
const handlePress = useCallback((id: string) => {
37+
// ...
38+
}, [])
39+
40+
const renderItem = useCallback(
41+
({ item }: { item: Item }) => <Row item={item} onPressItem={handlePress} />,
42+
[handlePress],
43+
)
3444

3545
return (
36-
<LegendList
37-
renderItem={({ item }) => (
38-
<Item key={item.id} item={item} onPress={onPress} />
39-
)}
46+
<FlashList
47+
data={items}
48+
estimatedItemSize={72}
49+
keyExtractor={(item) => item.id}
50+
renderItem={renderItem}
4051
/>
4152
)
53+
54+
const Row = memo(function Row({
55+
item,
56+
onPressItem,
57+
}: {
58+
item: Item
59+
onPressItem: (id: string) => void
60+
}) {
61+
const onPress = useCallback(() => onPressItem(item.id), [item.id, onPressItem])
62+
return <Pressable onPress={onPress}>{/* ... */}</Pressable>
63+
})
4264
```
4365

44-
Reference: [Link to documentation or resource](https://example.com)
66+
Reference: [FlashList performance](https://shopify.github.io/flash-list/docs/fundamentals/performant-components)

.claude/skills/vercel-react-native-skills/rules/list-performance-function-references.md

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,20 @@
22
title: Optimize List Performance with Stable Object References
33
impact: CRITICAL
44
impactDescription: virtualization relies on reference stability
5-
tags: lists, performance, flatlist, virtualization
5+
tags: lists, performance, flatlist, flashlist, virtualization
66
---
77

88
## Optimize List Performance with Stable Object References
99

10-
Don't map or filter data before passing to virtualized lists. Virtualization
11-
relies on object reference stability to know what changed—new references cause
12-
full re-renders of all visible items. Attempt to prevent frequent renders at the
13-
list-parent level.
10+
Don't map or filter data before passing to virtualized lists in ways that **replace every row object on each keystroke**. Virtualization works best when **element identities** in `data` are stable. Prefer moving dynamic text (e.g. search keyword) into **selectors inside row components** or stable derived stores.
1411

1512
Where needed, use context selectors within list items.
1613

1714
**Incorrect (creates new object references on every keystroke):**
1815

1916
```tsx
17+
import { FlashList } from '@shopify/flash-list'
18+
2019
function DomainSearch() {
2120
const { keyword, setKeyword } = useKeywordZustandState()
2221
const { data: tlds } = useTlds()
@@ -31,8 +30,10 @@ function DomainSearch() {
3130
return (
3231
<>
3332
<TextInput value={keyword} onChangeText={setKeyword} />
34-
<LegendList
33+
<FlashList
3534
data={domains}
35+
estimatedItemSize={56}
36+
keyExtractor={(item) => item.tld}
3637
renderItem={({ item }) => <DomainItem item={item} keyword={keyword} />}
3738
/>
3839
</>
@@ -43,23 +44,24 @@ function DomainSearch() {
4344
**Correct (stable references, transform inside items):**
4445

4546
```tsx
46-
const renderItem = ({ item }) => <DomainItem tld={item} />
47+
import { FlashList } from '@shopify/flash-list'
48+
49+
const renderItem = ({ item }: { item: Tld }) => <DomainItem tld={item} />
4750

4851
function DomainSearch() {
4952
const { data: tlds } = useTlds()
5053

5154
return (
52-
<LegendList
53-
// good: as long as the data is stable, LegendList will not re-render the entire list
55+
<FlashList
5456
data={tlds}
57+
estimatedItemSize={56}
58+
keyExtractor={(item) => item.name}
5559
renderItem={renderItem}
5660
/>
5761
)
5862
}
5963

6064
function DomainItem({ tld }: { tld: Tld }) {
61-
// good: transform within items, and don't pass the dynamic data as a prop
62-
// good: use a selector function from zustand to receive a stable string back
6365
const domain = useKeywordZustandState((s) => s.keyword + '.' + tld.name)
6466
return <Text>{domain}</Text>
6567
}
@@ -71,11 +73,16 @@ Creating a new array instance can be okay, as long as its inner object
7173
references are stable. For instance, if you sort a list of objects:
7274

7375
```tsx
74-
// good: creates a new array instance without mutating the inner objects
75-
// good: parent array reference is unaffected by typing and updating "keyword"
7676
const sortedTlds = tlds.toSorted((a, b) => a.name.localeCompare(b.name))
7777

78-
return <LegendList data={sortedTlds} renderItem={renderItem} />
78+
return (
79+
<FlashList
80+
data={sortedTlds}
81+
estimatedItemSize={56}
82+
keyExtractor={(item) => item.name}
83+
renderItem={renderItem}
84+
/>
85+
)
7986
```
8087

8188
Even though this creates a new array instance `sortedTlds`, the inner object
@@ -84,6 +91,8 @@ references are stable.
8491
**With zustand for dynamic data (avoids parent re-renders):**
8592

8693
```tsx
94+
import { FlashList } from '@shopify/flash-list'
95+
8796
const useSearchStore = create<{ keyword: string }>(() => ({ keyword: '' }))
8897

8998
function DomainSearch() {
@@ -92,17 +101,17 @@ function DomainSearch() {
92101
return (
93102
<>
94103
<SearchInput />
95-
<LegendList
104+
<FlashList
96105
data={tlds}
97-
// if you aren't using React Compiler, wrap renderItem with useCallback
106+
estimatedItemSize={56}
107+
keyExtractor={(item) => item.name}
98108
renderItem={({ item }) => <DomainItem tld={item} />}
99109
/>
100110
</>
101111
)
102112
}
103113

104114
function DomainItem({ tld }: { tld: Tld }) {
105-
// Select only what you need—component only re-renders when keyword changes
106115
const keyword = useSearchStore((s) => s.keyword)
107116
const domain = `${keyword}.${tld.name}`
108117
return <Text>{domain}</Text>

.claude/skills/vercel-react-native-skills/rules/list-performance-inline-objects.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Avoid Inline Objects in renderItem
33
impact: HIGH
44
impactDescription: prevents unnecessary re-renders of memoized list items
5-
tags: lists, performance, flatlist, virtualization, memo
5+
tags: lists, performance, flashlist, virtualization, memo
66
---
77

88
## Avoid Inline Objects in renderItem
@@ -14,10 +14,14 @@ values directly from `item` instead.
1414
**Incorrect (inline object breaks memoization):**
1515

1616
```tsx
17+
import { FlashList } from '@shopify/flash-list'
18+
1719
function UserList({ users }: { users: User[] }) {
1820
return (
19-
<LegendList
21+
<FlashList
2022
data={users}
23+
estimatedItemSize={72}
24+
keyExtractor={(item) => item.id}
2125
renderItem={({ item }) => (
2226
<UserRow
2327
// Bad: new object on every render
@@ -44,10 +48,14 @@ renderItem={({ item }) => (
4448
**Correct (pass item directly or primitives):**
4549

4650
```tsx
51+
import { FlashList } from '@shopify/flash-list'
52+
4753
function UserList({ users }: { users: User[] }) {
4854
return (
49-
<LegendList
55+
<FlashList
5056
data={users}
57+
estimatedItemSize={72}
58+
keyExtractor={(item) => item.id}
5159
renderItem={({ item }) => (
5260
// Good: pass the item directly
5361
<UserRow user={item} />

.claude/skills/vercel-react-native-skills/rules/list-performance-item-expensive.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ function ProductRow({ name, price, imageUrl }: Props) {
4949
**Move data fetching to parent:**
5050

5151
```tsx
52+
import { FlashList } from '@shopify/flash-list'
53+
5254
// Parent fetches all data once
5355
function ProductList() {
5456
const { data: products } = useQuery(['products'], fetchProducts)
5557

5658
return (
57-
<LegendList
59+
<FlashList
5860
data={products}
61+
estimatedItemSize={88}
62+
keyExtractor={(item) => item.id}
5963
renderItem={({ item }) => (
6064
<ProductRow name={item.name} price={item.price} imageUrl={item.image} />
6165
)}

0 commit comments

Comments
 (0)