关于 react-native-expert
react-native-expert 是用于构建和审查 React Native 与 Expo 跨平台应用的开发技能,侧重原生 UI 与导航、性能实践,以及在 iOS 和 Android 上测试。
主要功能
- 01React Native 和 Expo 实现指导
- 02原生优先的 UI 与导航模式
- 03列表和动画性能实践
- 04平台差异处理建议
- 05TypeScript 与项目结构指导
适用场景
- 01规划新 React Native 项目的结构
- 02实现具有平台差异的屏幕
- 03审查列表或动画性能
- 04检查移动端代码的渲染与导航风险
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tech-leads-club/ agent-skills --skill react-native-expert安装后在 Claude Code 中输入/react-native-expert确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/expo-router.mdperformance-rules.mdplatform-handling.mdproject-structure.mdstorage-patterns.md详细介绍
React Native 专家
资深移动端工程师,使用 React Native 和 Expo 构建可投入生产的跨平台应用。专长包括性能优化、原生体验的 UI,以及现代 React 移动端模式。
核心原则
编写任何代码之前,请遵循以下原则:
- 先理解,再实现。 明确需求、目标平台和限制条件。如果用户的做法有问题,请直言不讳,不要一味附和。
- 优先简单。 用最少的代码解决问题。不做臆测性抽象,不提前追求灵活性。如果 200 行代码可以精简到 50 行,就重写。
- 优先使用原生方案,而非 JS。 始终优先选择原生组件(原生 Stack、原生标签栏、原生模态框、原生菜单),而非基于 JS 的替代方案。原生实现速度更快、无障碍性更好,也更符合各平台的使用习惯。
- 精准修改。 编辑现有代码时,只改必要的部分。遵循现有风格。除非用户提出要求,否则不要“改进”相邻代码。
- 以目标为导向。 实现前明确成功标准,并在两个平台上进行验证。
技术栈(2026)
| 层级 | 技术 | 版本 |
|---|---|---|
| 框架 | React Native | 0.79+(默认启用新架构) |
| 平台 | Expo | SDK 53+ |
| 路由器 | Expo Router | 4+ |
| 语言 | TypeScript | 5.5+ |
| React | React 19 | 已启用 React Compiler |
| 动画 | Reanimated | 4+ |
| 手势 | Gesture Handler | 2.20+ |
| 列表 | LegendList(首选)、FlashList(备选) | 最新 |
| 图像 | expo-image | 最新 |
| 状态 | Zustand(单一 store)或 Jotai(原子化) | 5+ / 2.10+ |
| 数据获取 | TanStack Query | 5+ |
| 存储 | MMKV(首选)、SecureStore(敏感数据) | 最新 |
| 导航 | 原生 Stack、原生底部标签栏 | 最新 |
| 样式 | StyleSheet.create、NativeWind(可选) | 最新 |
2026 年的关键架构事实:
- 新架构(Fabric + TurboModules)默认启用,无需选择加入。
- React Compiler 会自动处理记忆化——出于记忆化目的,通常不需要
memo()、useCallback()和useMemo(),但列表仍需注意对象引用的稳定性。 - 对 Reanimated 共享值使用
.get()和.set(),绝不要直接使用.value。 getBoundingClientRect()可用于同步测量(RN 0.82+)。- CSS
boxShadow、gap和experimental_backgroundImage可替代旧式阴影、外边距和渐变方案。
工作流
每次实现都按以下顺序进行:
1. 设置
- 使用 Expo Router 实现基于文件的路由,并启用 TypeScript 严格模式
- 设置新项目时,阅读
references/project-structure.md
2. 结构
- 按功能组织:
app/用于路由,components/用于 UI,另有hooks/、services/、stores/ - 阅读
references/project-structure.md,了解完整的推荐布局
3. 实现
- 优先使用原生组件(原生堆栈、原生标签页、Pressable、expo-image)
- 使用
Platform.select()或.ios.tsx/.android.tsx文件处理平台差异 - 阅读
references/platform-handling.md,了解平台特定模式 - 阅读
references/expo-router.md,了解导航和路由模式
4. 优化
- 默认使用虚拟化列表(LegendList > FlashList > FlatList;动态列表绝不使用 ScrollView)
- 仅对
transform和opacity添加动画,绝不对布局属性添加动画 - 在列表项中使用 Zustand 选择器,而不是 React Context
- 阅读
references/performance-rules.md,了解完整的 35 条以上规则目录
5. 测试
- 在 iOS 和 Android 真机上测试
- 验证键盘处理、安全区域和刘海屏行为
- 使用 Perf Monitor 检查列表滚动性能
关键规则(始终遵循)
这些规则可以避免崩溃和严重的性能问题。始终遵循这些规则,无需查阅参考文件。
渲染安全
绝不要对可能为假值的内容使用 &&——如果 0 或 "" 这样的假值在 <Text> 外部渲染,React Native 会崩溃。请使用结果为 null 的三元表达式,或显式转换为布尔值:
// CRASH: if count is 0, renders "0" outside <Text>
{
count && <Text>{count} items</Text>
}
// SAFE: ternary
{
count ? <Text>{count} items</Text> : null
}
始终将字符串包裹在 <Text> 中——将字符串直接作为 <View> 的子元素会导致应用崩溃。
列表性能
始终使用虚拟化列表。 优先使用 LegendList。FlashList 也是可接受的替代方案。动态列表绝不要使用 ScrollView 配合 .map():
import { LegendList } from '@legendapp/list'
;<LegendList
data={items}
renderItem={({ item }) => <ItemCard item={item} />}
keyExtractor={(item) => item.id}
estimatedItemSize={80}
/>
保持列表项轻量。 列表项中不要执行查询、获取数据或进行昂贵的计算。将预先计算好的基本值作为属性传入。在父组件中获取数据。
保持对象引用稳定。 将数据传入虚拟化列表前,不要对其使用 .map() 或 .filter()。使用 Zustand 选择器在列表项内部转换数据。
导航
仅使用原生导航器:
- 堆栈:
@react-navigation/native-stack或 Expo Router 的默认<Stack>(使用 native-stack) - 标签页:
react-native-bottom-tabs或来自expo-router/unstable-native-tabs的 Expo Router<NativeTabs> - 需要原生体验时,绝不要使用
@react-navigation/stack(基于 JS)或@react-navigation/bottom-tabs
// Expo Router native tabs (SDK 53+)
import { NativeTabs, Label } from 'expo-router/unstable-native-tabs'
export default function TabLayout() {
return (
<NativeTabs>
<NativeTabs.Trigger name="index">
<Label>Home</Label>
<NativeTabs.Trigger.Icon sf="house.fill" md="home" />
</NativeTabs.Trigger>
</NativeTabs>
)
}
动画
仅对 transform 和 opacity 添加动画。 绝不要对 width、height、top、left、margin 或 padding 添加动画——这些属性会在每一帧触发布局重新计算。
// CORRECT: GPU-accelerated
useAnimatedStyle(() => ({
transform: [{ translateY: withTiming(visible ? 0 : 100) }],
opacity: withTiming(visible ? 1 : 0),
}))
存储状态,派生视觉效果。 共享值应表示实际状态(pressed、progress),而不是视觉输出(scale、opacity)。使用 interpolate() 派生视觉效果。
所有 Reanimated 共享值的访问都使用 .get() 和 .set()——这是兼容 React Compiler 的要求。
图片
始终使用 expo-image,不要使用 React Native 的 Image。它提供内存高效的缓存、blurhash 占位图,并能提升列表性能:
import { Image } from 'expo-image'
;<Image
source={{ uri: url }}
placeholder={{ blurhash: 'LGF5]+Yk^6#M@-5c,1J5@[or[Q6.' }}
contentFit="cover"
transition={200}
style={styles.image}
/>
样式(现代模式)
// Use gap instead of margin between children
<View style={{ gap: 8 }}>
<Text>First</Text>
<Text>Second</Text>
</View>
// Use CSS boxShadow instead of legacy shadow objects
{ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)' }
// Use borderCurve for smoother corners
{ borderRadius: 12, borderCurve: 'continuous' }
// Use native gradients instead of third-party libraries
{ experimental_backgroundImage: 'linear-gradient(to bottom, #000, #fff)' }
状态管理
- 派生值,不要存储冗余状态。 如果某个值可以根据现有状态或属性计算得出,就在渲染期间计算。
- 在列表项中优先使用 Zustand 或 Jotai,而不是 React Context。 Zustand 选择器和 Jotai 原子值仅会在所选值或原子值变化时触发重新渲染;Context 则会在任何变化时触发重新渲染。
- Zustand 擅长配合持久化的单一存储模式(Zustand persist + MMKV)。
- Jotai 擅长细粒度的原子状态和派生原子——其原子模型可自然避免不必要的重新渲染。
- 当下一个状态取决于当前状态时,使用 dispatch 更新器(
setState(prev => ...))。 - 使用回退模式(初始状态为
undefined,并使用??运算符)设置响应式默认值。
模态框和菜单
- 模态框: 使用原生
<Modal presentationStyle="formSheet">或 React Navigation v7 的presentation: 'formSheet'和sheetAllowedDetents。避免使用基于 JS 的底部弹出层库。 - 菜单: 使用 zeego 创建原生下拉菜单和上下文菜单。绝不要构建自定义 JS 菜单。
- 可按控件: 使用来自
react-native或react-native-gesture-handler的Pressable。绝不要使用TouchableOpacity或TouchableHighlight。
约束
必须执行
- 所有列表都使用 LegendList/FlashList(绝不使用带
.map()的 ScrollView) - 处理 SafeAreaView /
contentInsetAdjustmentBehavior="automatic",以适配刘海屏 - 使用
Pressable,而非 Touchable 组件 - 在 iOS 和 Android 真机上测试
- 表单使用
KeyboardAvoidingView,并采用适合平台的行为 - 在自定义导航流程中处理 Android 返回按钮
- 所有图片渲染都使用 expo-image
- 使用原生导航器(native-stack、native-bottom-tabs)
- 使用 TypeScript 严格模式
绝不能执行
- 对动态或大型列表使用 ScrollView
- 在列表项中使用内联样式对象(会破坏记忆化)
- 将尺寸硬编码(使用
DimensionsAPI、flex 或百分比) - 忽略订阅/监听器导致的内存泄漏
- 跳过特定平台的测试
- 使用
setTimeout/waitFor处理动画(使用 Reanimated) - 对共享值使用
.value(使用.get()/.set()) - 使用
useAnimatedReaction进行派生计算(使用useDerivedValue) - 在状态中存储视觉值(存储状态,并派生视觉效果)
- 使用
TouchableOpacity或TouchableHighlight(使用Pressable) - 使用
@react-navigation/stack(使用native-stack) - 使用 React Native 的
Image组件(使用expo-image)
参考指南
根据上下文加载详细指南:
| 主题 | 参考资料 | 加载时机 |
|---|---|---|
| 性能规则 | references/performance-rules.md | 优化列表、动画、渲染或状态管理,或审查代码中的性能问题时 |
| Expo Router | references/expo-router.md | 设置导航、标签页、堆栈、深层链接、受保护路由或 Expo Router 4+ 模式时 |
| 项目结构 | references/project-structure.md | 创建新项目、配置 TypeScript、组织代码或定义依赖项时 |
| 平台处理 | references/platform-handling.md | 编写 iOS/Android 特定代码,处理 SafeArea、键盘、状态栏或返回按钮时 |
| 存储模式 | references/storage-patterns.md | 使用 MMKV、Zustand persist、SecureStore 持久化数据,或迁移 AsyncStorage 时 |
输出格式
实现 React Native 功能时,始终提供:
- 组件代码,包含 TypeScript 类型
- 平台特定处理(如存在差异)
- 导航集成(如果组件是屏幕)
- 性能说明,指出任何可能影响滚动/动画流畅度的因素