You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

429 lines
11 KiB

# 💡 使用示例
本文档提供项目中各个工具和模块的实际使用示例。
## 📋 目录
- [登录功能示例](#登录功能示例)
- [用户资料更新示例](#用户资料更新示例)
- [搜索功能示例](#搜索功能示例)
- [设置页面示例](#设置页面示例)
- [列表加载示例](#列表加载示例)
---
## 登录功能示例
完整的登录页面实现,包含表单验证、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);
1 month ago
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) - 项目结构和最佳实践
---
**提示**:这些示例都是可以直接使用的代码,复制到你的项目中即可!