Files
rn-app/docs/USAGE_EXAMPLES.md
2025-11-05 17:24:55 +08:00

429 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 💡 使用示例
本文档提供项目中各个工具和模块的实际使用示例。
## 📋 目录
- [登录功能示例](#登录功能示例)
- [用户资料更新示例](#用户资料更新示例)
- [搜索功能示例](#搜索功能示例)
- [设置页面示例](#设置页面示例)
- [列表加载示例](#列表加载示例)
---
## 登录功能示例
完整的登录页面实现包含表单验证、API 调用、状态管理。
```typescript
import React, { useState } from 'react';
import { View, TextInput, TouchableOpacity, Text, Alert } from 'react-native';
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { useRouter } from 'expo-router';
import {
loginSchema,
type LoginFormData,
authService,
useUserStore,
useHaptics,
} from '@/src';
export default function LoginScreen() {
const router = useRouter();
const haptics = useHaptics();
const login = useUserStore((state) => state.login);
const [loading, setLoading] = useState(false);
// 表单配置
const {
control,
handleSubmit,
formState: { errors },
} = useForm<LoginFormData>({
resolver: zodResolver(loginSchema),
defaultValues: {
email: '',
password: '',
},
});
// 提交处理
const onSubmit = async (data: LoginFormData) => {
try {
setLoading(true);
// 调用登录 API
const { user, token } = await authService.login(data);
// 更新状态
login(user, token);
// 触觉反馈
haptics.success();
// 跳转到首页
router.replace('/(tabs)');
} catch (error: any) {
haptics.error();
Alert.alert('登录失败', error.message || '请检查邮箱和密码');
} finally {
setLoading(false);
}
};
return (
<View style={{ padding: 20 }}>
{/* 邮箱输入 */}
<Controller
control={control}
name="email"
render={({ field: { onChange, value } }) => (
<View>
<TextInput
value={value}
onChangeText={onChange}
placeholder="邮箱"
keyboardType="email-address"
autoCapitalize="none"
style={{
borderWidth: 1,
borderColor: errors.email ? 'red' : '#ccc',
padding: 10,
borderRadius: 5,
}}
/>
{errors.email && (
<Text style={{ color: 'red', marginTop: 5 }}>
{errors.email.message}
</Text>
)}
</View>
)}
/>
{/* 密码输入 */}
<Controller
control={control}
name="password"
render={({ field: { onChange, value } }) => (
<View style={{ marginTop: 15 }}>
<TextInput
value={value}
onChangeText={onChange}
placeholder="密码"
secureTextEntry
style={{
borderWidth: 1,
borderColor: errors.password ? 'red' : '#ccc',
padding: 10,
borderRadius: 5,
}}
/>
{errors.password && (
<Text style={{ color: 'red', marginTop: 5 }}>
{errors.password.message}
</Text>
)}
</View>
)}
/>
{/* 登录按钮 */}
<TouchableOpacity
onPress={handleSubmit(onSubmit)}
disabled={loading}
style={{
backgroundColor: loading ? '#ccc' : '#007AFF',
padding: 15,
borderRadius: 5,
marginTop: 20,
}}
>
<Text style={{ color: 'white', textAlign: 'center', fontWeight: 'bold' }}>
{loading ? '登录中...' : '登录'}
</Text>
</TouchableOpacity>
</View>
);
}
```
---
## 用户资料更新示例
使用表单验证和 API 服务更新用户资料。
```typescript
import React, { useState } from 'react';
import { View, TextInput, TouchableOpacity, Text, Alert } from 'react-native';
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import {
updateProfileSchema,
type UpdateProfileFormData,
userService,
useUserStore,
useHaptics,
} from '@/src';
export default function EditProfileScreen() {
const haptics = useHaptics();
const user = useUserStore((state) => state.user);
const updateUser = useUserStore((state) => state.updateUser);
const [loading, setLoading] = useState(false);
const {
control,
handleSubmit,
formState: { errors },
} = useForm<UpdateProfileFormData>({
resolver: zodResolver(updateProfileSchema),
defaultValues: {
nickname: user?.nickname || '',
phone: user?.phone || '',
},
});
const onSubmit = async (data: UpdateProfileFormData) => {
try {
setLoading(true);
// 调用更新 API
const updatedUser = await userService.updateProfile(data);
// 更新本地状态
updateUser(updatedUser);
haptics.success();
Alert.alert('成功', '资料更新成功');
} catch (error: any) {
haptics.error();
Alert.alert('失败', error.message || '更新失败');
} finally {
setLoading(false);
}
};
return (
<View style={{ padding: 20 }}>
<Controller
control={control}
name="nickname"
render={({ field: { onChange, value } }) => (
<View>
<Text></Text>
<TextInput
value={value}
onChangeText={onChange}
placeholder="请输入昵称"
style={{ borderWidth: 1, padding: 10, marginTop: 5 }}
/>
{errors.nickname && (
<Text style={{ color: 'red' }}>{errors.nickname.message}</Text>
)}
</View>
)}
/>
<TouchableOpacity
onPress={handleSubmit(onSubmit)}
disabled={loading}
style={{
backgroundColor: '#007AFF',
padding: 15,
marginTop: 20,
borderRadius: 5,
}}
>
<Text style={{ color: 'white', textAlign: 'center' }}>
{loading ? '保存中...' : '保存'}
</Text>
</TouchableOpacity>
</View>
);
}
```
---
## 搜索功能示例
使用防抖优化搜索性能。
```typescript
import React, { useState, useEffect } from 'react';
import { View, TextInput, FlatList, Text } from 'react-native';
import { useDebounce } from '@/src';
export default function SearchScreen() {
const [searchText, setSearchText] = useState('');
const [results, setResults] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
// 防抖搜索函数
const debouncedSearch = useDebounce(async (text: string) => {
if (!text.trim()) {
setResults([]);
return;
}
try {
setLoading(true);
// 调用搜索 API
const response = await fetch(`/api/search?q=${text}`);
const data = await response.json();
setResults(data.results);
} catch (error) {
console.error('Search error:', error);
} finally {
setLoading(false);
}
}, 500);
// 监听搜索文本变化
useEffect(() => {
debouncedSearch(searchText);
}, [searchText]);
return (
<View style={{ flex: 1, padding: 20 }}>
<TextInput
value={searchText}
onChangeText={setSearchText}
placeholder="搜索..."
style={{
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
borderRadius: 5,
}}
/>
{loading && <Text style={{ marginTop: 10 }}>...</Text>}
<FlatList
data={results}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View style={{ padding: 10, borderBottomWidth: 1 }}>
<Text>{item.title}</Text>
</View>
)}
style={{ marginTop: 20 }}
/>
</View>
);
}
```
---
## 设置页面示例
使用状态管理和触觉反馈。
```typescript
import React from 'react';
import { View, Text, Switch, TouchableOpacity } from 'react-native';
import {
useSettingsStore,
useHaptics,
type Theme,
} from '@/src';
export default function SettingsScreen() {
const haptics = useHaptics();
const theme = useSettingsStore((state) => state.theme);
const notificationsEnabled = useSettingsStore((state) => state.notificationsEnabled);
const hapticsEnabled = useSettingsStore((state) => state.hapticsEnabled);
const setTheme = useSettingsStore((state) => state.setTheme);
const setNotificationsEnabled = useSettingsStore((state) => state.setNotificationsEnabled);
const setHapticsEnabled = useSettingsStore((state) => state.setHapticsEnabled);
const handleThemeChange = (newTheme: Theme) => {
haptics.selection();
setTheme(newTheme);
};
const handleToggle = (setter: (value: boolean) => void, value: boolean) => {
haptics.light();
setter(value);
};
return (
<View style={{ flex: 1, padding: 20 }}>
{/* 主题选择 */}
<View style={{ marginBottom: 20 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 10 }}>
</Text>
{(['light', 'dark', 'auto'] as Theme[]).map((t) => (
<TouchableOpacity
key={t}
onPress={() => handleThemeChange(t)}
style={{
padding: 15,
backgroundColor: theme === t ? '#007AFF' : '#f0f0f0',
marginBottom: 10,
borderRadius: 5,
}}
>
<Text style={{ color: theme === t ? 'white' : 'black' }}>
{t === 'light' ? '亮色' : t === 'dark' ? '暗色' : '自动'}
</Text>
</TouchableOpacity>
))}
</View>
{/* 通知开关 */}
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 15,
}}
>
<Text></Text>
<Switch
value={notificationsEnabled}
onValueChange={(value) => handleToggle(setNotificationsEnabled, value)}
/>
</View>
{/* 触觉反馈开关 */}
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<Text></Text>
<Switch
value={hapticsEnabled}
onValueChange={(value) => handleToggle(setHapticsEnabled, value)}
/>
</View>
</View>
);
}
```
---
## 📚 更多示例
查看以下文档了解更多:
- [工具库使用指南](./LIBRARIES.md) - 各个工具库的详细用法
- [项目结构说明](./PROJECT_STRUCTURE.md) - 项目结构和最佳实践
---
**提示**:这些示例都是可以直接使用的代码,复制到你的项目中即可!