feat: new project
This commit is contained in:
429
docs/USAGE_EXAMPLES.md
Normal file
429
docs/USAGE_EXAMPLES.md
Normal file
@@ -0,0 +1,429 @@
|
||||
# 💡 使用示例
|
||||
|
||||
本文档提供项目中各个工具和模块的实际使用示例。
|
||||
|
||||
## 📋 目录
|
||||
|
||||
- [登录功能示例](#登录功能示例)
|
||||
- [用户资料更新示例](#用户资料更新示例)
|
||||
- [搜索功能示例](#搜索功能示例)
|
||||
- [设置页面示例](#设置页面示例)
|
||||
- [列表加载示例](#列表加载示例)
|
||||
|
||||
---
|
||||
|
||||
## 登录功能示例
|
||||
|
||||
完整的登录页面实现,包含表单验证、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) - 项目结构和最佳实践
|
||||
|
||||
---
|
||||
|
||||
**提示**:这些示例都是可以直接使用的代码,复制到你的项目中即可!
|
||||
|
||||
Reference in New Issue
Block a user