RN 组件就是原生 UI
React Native 的 UI 组件与浏览器中的 HTML 元素有本质区别。当你在浏览器里写 <div>,浏览器使用自己的渲染引擎绘制一个盒子。但 React Native 里写 <View>,框架会调用平台原生 API 创建一个真正的原生视图——iOS 上是 UIView,Android 上是 android.view.View。
这就是为什么 React Native 的用户体验比 WebView 方案好得多:动画、滚动、手势等都是原生实现,系统的无障碍(Accessibility)、键盘管理、安全区域等也自然支持。
核心组件速查
Flexbox 布局——RN 的默认值与 Web 不同
React Native 使用 Flexbox 进行布局,与 CSS Flexbox 概念相同,但有几个重要的默认值差异,初学者经常在这里踩坑:
CSS Flexbox 默认值
- flexDirection: row(横向排列)
- alignContent: stretch
- flexShrink: 1
- position: static
RN Flexbox 默认值
- flexDirection: column(纵向排列)✦
- alignContent: flex-start ✦
- flexShrink: 0 ✦
- position: relative
最重要的一点:RN 中 flexDirection 默认是 column(垂直方向),而 Web CSS 默认是 row(水平方向)。理解这一点,就能避免大量布局困惑。
此外,RN 中的 flex: 1 非常常用,它让组件占满父容器的剩余空间。要让根容器撑满整个屏幕,只需给容器设置 flex: 1。
FlatList 虚拟化原理
FlatList 是 React Native 处理长列表的核心组件。理解它的虚拟化机制,能帮助你写出高性能的列表界面。
ScrollView。ScrollView 会一次性渲染所有子元素并保持在内存中,1000 条数据就意味着 1000 个原生视图同时存在,导致严重卡顿和内存溢出崩溃。
完整 FlatList 示例
import {
FlatList, View, Text, Image,
RefreshControl, StyleSheet,
ListRenderItem
} from 'react-native';
import { useState, useCallback } from 'react';
interface Post {
id: string;
author: string;
avatar: string;
content: string;
likes: number;
}
const POSTS: Post[] = Array.from({ length: 100 }, (_, i) => ({
id: String(i),
author: `用户 ${i + 1}`,
avatar: `https://i.pravatar.cc/40?img=${i % 70}`,
content: `这是第 ${i + 1} 条帖子的内容,展示 FlatList 的用法。`,
likes: Math.floor(Math.random() * 1000),
}));
// 抽离 renderItem 为独立组件,配合 React.memo 避免不必要的重渲染
const PostItem = React.memo(({ item }: { item: Post }) => (
<View style={styles.item}>
<Image source={{ uri: item.avatar }} style={styles.avatar} />
<View style={styles.itemBody}>
<Text style={styles.author}>{item.author}</Text>
<Text style={styles.content}>{item.content}</Text>
<Text style={styles.likes}>♥ {item.likes}</Text>
</View>
</View>
));
export default function FeedScreen() {
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = useCallback(async () => {
setRefreshing(true);
await new Promise(r => setTimeout(r, 1500)); // 模拟网络请求
setRefreshing(false);
}, []);
return (
<FlatList
data={POSTS}
renderItem={({ item }) => <PostItem item={item} />}
keyExtractor={item => item.id} // 必须提供,用于 diff 优化
initialNumToRender={10} // 首屏渲染数量
windowSize={5} // 渲染窗口(5倍屏高)
maxToRenderPerBatch={5} // 每批次渲染数量
removeClippedSubviews={true} // 裁剪屏幕外的视图(Android)
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor="#38bdf8"
/>
}
ListEmptyComponent={
<Text style={styles.empty}>暂无数据</Text>
}
/>
);
}
平台特定代码与样式
React Native 的目标是跨平台,但 iOS 和 Android 的设计语言天然不同——iOS 偏向扁平简洁,Android 遵循 Material Design。正确处理平台差异,是写出优质跨平台应用的关键。
import { Platform, StyleSheet } from 'react-native';
// 方式一:条件判断
const borderRadius = Platform.OS === 'ios' ? 12 : 8;
// 方式二:Platform.select(推荐,声明式)
const shadow = Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.15,
shadowRadius: 4,
},
android: {
elevation: 4, // Android 用 elevation 实现阴影
},
default: {},
});
// 方式三:平台特定文件(最干净的方案)
// Button.ios.tsx ← iOS 版本
// Button.android.tsx← Android 版本
// 导入时不需要指定后缀:import Button from './Button'
// Metro 会自动根据平台选择正确的文件
const styles = StyleSheet.create({
card: {
backgroundColor: '#1a2744',
borderRadius: 12,
padding: 16,
...shadow, // 展开平台特定阴影
},
});
shadow* 属性系列(shadowColor、shadowOffset 等)实现阴影;Android 用 elevation(越大越高、阴影越深)。两者无法互换。跨平台组件库(如 NativeWind、React Native Paper)通常封装了这种差异,但如果手写样式,必须用 Platform.select 分别处理。
StyleSheet 最佳实践
StyleSheet.create() 不只是组织代码的方式,它在运行时会将样式对象序列化为 ID 引用,减少跨线程传输的数据量。此外,它还提供完整的 TypeScript 类型推断,能在编写时发现样式属性拼写错误。
style={{ color: 'red' }}),每次渲染都会创建新对象,对垃圾回收造成压力。应始终用 StyleSheet.create 在组件外部定义样式,或使用样式数组 style={[styles.base, isActive && styles.active]}。
处理键盘遮挡(KeyboardAvoidingView)
import {
KeyboardAvoidingView, Platform,
ScrollView, TextInput
} from 'react-native';
export function CommentForm() {
return (
// iOS 用 padding,Android 用 height
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<ScrollView>
{/* 表单内容 */}
</ScrollView>
<TextInput
placeholder="写下你的评论..."
style={styles.input}
multiline
/>
</KeyboardAvoidingView>
);
}
核心组件与布局的关键要点:① RN 组件直接映射原生 UI——View → UIView/android.view.View,Text → UILabel/TextView,不经过 WebView;② Flexbox 是唯一的布局方式,默认 flexDirection: 'column'(与 Web 相反),flex: 1 表示占满剩余空间;③ FlatList 通过虚拟化只渲染可见条目,必须提供 keyExtractor;列表数据量超过 100 条必须用 FlatList 而非 ScrollView;④ 样式用 StyleSheet.create() 而非内联对象,可以享受编译时优化和类型检查;⑤ SafeAreaView 自动避开刘海屏和圆角区域,顶层容器始终用它包裹;⑥ KeyboardAvoidingView 处理软键盘遮挡,iOS 用 behavior='padding',Android 用 behavior='height';⑦ 平台差异用 Platform.OS 条件判断,或用 Platform.select() 声明式区分。