name: code-patterns-practices description: React Native 编码模式、最佳实践和移动开发的常见解决方案。在实现功能或重构代码时使用。 allowed-tools: Read, Write, Edit
代码模式与实践
React Native 开发的常见模式和最佳实践。
何时使用
- 实现新功能
- 重构现有代码
- 选择架构模式
- 解决常见问题
- 提高代码质量
组件模式
自定义 Hooks
// 提取可复用逻辑
function useToggle(initial = false) {
const [value, setValue] = useState(initial);
const toggle = useCallback(() => setValue(v => !v), []);
return [value, toggle] as const;
}
// 用法
const [isOpen, toggleOpen] = useToggle();
复合组件
// 创建灵活的组件 API
interface TabsProps {
children: React.ReactNode;
defaultValue?: string;
}
function Tabs({ children, defaultValue }: TabsProps) {
const [active, setActive] = useState(defaultValue);
return (
<TabsContext.Provider value={{ active, setActive }}>
{children}
</TabsContext.Provider>
);
}
Tabs.List = TabsList;
Tabs.Trigger = TabsTrigger;
Tabs.Content = TabsContent;
// 用法
<Tabs defaultValue="home">
<Tabs.List>
<Tabs.Trigger value="home">首页</Tabs.Trigger>
<Tabs.Trigger value="profile">个人资料</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="home">首页内容</Tabs.Content>
<Tabs.Content value="profile">个人资料内容</Tabs.Content>
</Tabs>
渲染属性
// 共享组件逻辑
interface DataLoaderProps<T> {
loadData: () => Promise<T>;
children: (data: T | null, loading: boolean, error: Error | null) => React.ReactNode;
}
function DataLoader<T>({ loadData, children }: DataLoaderProps<T>) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
loadData()
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [loadData]);
return <>{children(data, loading, error)}</>;
}
// 用法
<DataLoader loadData={fetchUser}>
{(user, loading, error) => {
if (loading) return <Loading />;
if (error) return <Error error={error} />;
return <UserProfile user={user} />;
}}
</DataLoader>
状态管理模式
局部状态
// 尽可能保持简单
function Counter() {
const [count, setCount] = useState(0);
return <Button onPress={() => setCount(c => c + 1)}>计数: {count}</Button>;
}
共享状态(Context)
// 用于横切关注点
const ThemeContext = createContext<ThemeContextValue>(null!);
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) throw new Error('useTheme 必须在 ThemeProvider 内使用');
return context;
}
全局状态(Zustand)
// 用于应用级状态
import { create } from 'zustand';
interface UserState {
user: User | null;
setUser: (user: User) => void;
logout: () => void;
}
export const useUserStore = create<UserState>((set) => ({
user: null,
setUser: (user) => set({ user }),
logout: () => set({ user: null }),
}));
数据获取模式
使用 Async/Await
function useUserData(userId: string) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false;
async function fetchData() {
try {
const response = await fetch(`/api/users/${userId}`);
const result = await response.json();
if (!cancelled) {
setData(result);
}
} catch (err) {
if (!cancelled) {
setError(err);
}
} finally {
if (!cancelled) {
setLoading(false);
}
}
}
fetchData();
return () => {
cancelled = true;
};
}, [userId]);
return { data, loading, error };
}
性能模式
记忆化
// 昂贵计算
const expensiveValue = useMemo(() => {
return calculateExpensiveValue(data);
}, [data]);
// 稳定的回调函数
const handlePress = useCallback(() => {
doSomething(value);
}, [value]);
// 组件记忆化
const MemoizedChild = memo(function Child({ data }: ChildProps) {
return <View>{data}</View>;
});
懒加载
import { lazy, Suspense } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
);
}
错误处理模式
错误边界
class ErrorBoundary extends React.Component<
{ children: React.ReactNode },
{ hasError: boolean; error: Error | null }
> {
state = { hasError: false, error: null };
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
console.error('捕获的错误:', error, info);
}
render() {
if (this.state.hasError) {
return <ErrorScreen error={this.state.error} />;
}
return this.props.children;
}
}
Try-Catch 模式
async function saveData() {
try {
await api.save(data);
showSuccess('已保存!');
} catch (error) {
if (error instanceof NetworkError) {
showError('网络错误,请检查连接。');
} else if (error instanceof ValidationError) {
showError(error.message);
} else {
showError('出错了。');
}
}
}
移动端特有模式
安全区域处理
import { useSafeAreaInsets } from 'react-native-safe-area-context';
function Screen() {
const insets = useSafeAreaInsets();
return (
<View style={{ paddingTop: insets.top, paddingBottom: insets.bottom }}>
{/* 内容 */}
</View>
);
}
键盘避让
import { KeyboardAvoidingView, Platform } from 'react-native';
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={{ flex: 1 }}
>
{/* 输入表单 */}
</KeyboardAvoidingView>
最佳实践
- 保持组件小巧:单一职责,易于测试
- 提取自定义 Hooks:跨组件复用逻辑
- 使用 TypeScript:及早发现错误
- 处理加载和错误状态:更好的用户体验
- 清理副作用:防止内存泄漏
- 明智地优化:优化前先分析性能
- 测试行为:关注用户交互
应避免的反模式
- ❌ 巨型组件(>300 行)
- ❌ 属性透传(应使用 context/store)
- ❌ 在 useEffect 中缺少清理
- ❌ 在 render 中内联函数定义
- ❌ 直接修改状态
- ❌ 未经测量的过度优化