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.
9.5 KiB
9.5 KiB
📚 常用工具库使用指南
本文档介绍项目中已安装的常用工具库及其使用方法。
📦 已安装的库列表
工具类库
| 库名 | 版本 | 用途 |
|---|---|---|
| lodash-es | ^4.17.21 | JavaScript 工具函数库(ES modules 版本) |
| dayjs | ^1.11.19 | 轻量级日期处理库 |
| axios | ^1.13.1 | HTTP 请求库 |
| zustand | ^5.0.8 | 轻量级状态管理 |
| react-hook-form | ^7.66.0 | 表单处理库 |
| zod | ^4.1.12 | TypeScript 数据验证库 |
Expo 原生模块
| 库名 | 版本 | 用途 |
|---|---|---|
| @react-native-async-storage/async-storage | ^2.2.0 | 本地存储 |
| expo-image | ^3.0.10 | 优化的图片组件 |
| expo-haptics | ^15.0.7 | 触觉反馈 |
开发工具
| 库名 | 版本 | 用途 |
|---|---|---|
| @types/lodash-es | ^4.17.12 | Lodash-ES TypeScript 类型定义 |
🚀 快速开始
1. Lodash-ES - JavaScript 工具库
注意:使用
lodash-es而不是lodash,支持 ES modules 和更好的 tree-shaking。
// 推荐:按需导入(tree-shaking 友好)
import { map, filter, uniq, pick, cloneDeep, debounce } from 'lodash-es';
// 数组操作
map([1, 2, 3], (n) => n * 2); // [2, 4, 6]
filter([1, 2, 3, 4], (n) => n % 2 === 0); // [2, 4]
uniq([1, 2, 2, 3]); // [1, 2, 3]
// 对象操作
pick({ a: 1, b: 2, c: 3 }, ['a', 'b']); // { a: 1, b: 2 }
cloneDeep(obj); // 深拷贝
// 防抖和节流
const handleSearch = debounce((text) => {
console.log('Searching:', text);
}, 300);
// 也可以全量导入(不推荐,会增加包体积)
import _ from 'lodash-es';
_.map([1, 2, 3], (n) => n * 2);
2. Day.js - 日期处理
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/zh-cn';
dayjs.extend(relativeTime);
dayjs.locale('zh-cn');
// 格式化
dayjs().format('YYYY-MM-DD HH:mm:ss');
// 相对时间
dayjs().fromNow(); // '几秒前'
dayjs().subtract(1, 'day').fromNow(); // '1天前'
// 日期操作
dayjs().add(7, 'day'); // 7天后
dayjs().startOf('month'); // 本月第一天
3. Axios - HTTP 请求
import axios from 'axios';
// 创建实例
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
});
// 请求拦截器
api.interceptors.request.use(async (config) => {
const token = await AsyncStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// 使用
const data = await api.get('/users');
await api.post('/users', { name: 'John' });
4. Zustand - 状态管理
import { create } from 'zustand';
interface UserState {
user: User | null;
setUser: (user: User) => void;
}
export const useUserStore = create<UserState>((set) => ({
user: null,
setUser: (user) => set({ user }),
}));
// 在组件中使用
const user = useUserStore((state) => state.user);
const setUser = useUserStore((state) => state.setUser);
5. React Hook Form + Zod - 表单处理
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
email: z.string().email('请输入有效的邮箱'),
password: z.string().min(6, '密码至少6个字符'),
});
type FormData = z.infer<typeof schema>;
function LoginForm() {
const { control, handleSubmit, formState: { errors } } = useForm<FormData>({
resolver: zodResolver(schema),
});
const onSubmit = (data: FormData) => {
console.log(data);
};
return (
<Controller
control={control}
name="email"
render={({ field: { onChange, value } }) => (
<TextInput
value={value}
onChangeText={onChange}
placeholder="邮箱"
/>
)}
/>
);
}
6. AsyncStorage - 本地存储
import AsyncStorage from '@react-native-async-storage/async-storage';
// 存储
await AsyncStorage.setItem('key', JSON.stringify(value));
// 读取
const value = await AsyncStorage.getItem('key');
const data = value ? JSON.parse(value) : null;
// 删除
await AsyncStorage.removeItem('key');
// 清空
await AsyncStorage.clear();
7. Expo Image - 优化的图片组件
import { Image } from 'expo-image';
<Image
source={{ uri: 'https://example.com/image.jpg' }}
placeholder={require('@/assets/placeholder.png')}
contentFit="cover"
transition={1000}
style={{ width: 300, height: 300 }}
/>
8. Expo Haptics - 触觉反馈
import * as Haptics from 'expo-haptics';
// 轻触反馈
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
// 成功反馈
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
// 错误反馈
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
💡 实用示例
创建 API 工具类
// utils/api.ts
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
});
api.interceptors.request.use(async (config) => {
const token = await AsyncStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
api.interceptors.response.use(
(response) => response.data,
(error) => {
if (error.response?.status === 401) {
AsyncStorage.removeItem('token');
}
return Promise.reject(error);
}
);
export default api;
创建 Storage 工具类
// utils/storage.ts
import AsyncStorage from '@react-native-async-storage/async-storage';
class Storage {
static async setObject<T>(key: string, value: T): Promise<void> {
await AsyncStorage.setItem(key, JSON.stringify(value));
}
static async getObject<T>(key: string): Promise<T | null> {
const value = await AsyncStorage.getItem(key);
return value ? JSON.parse(value) : null;
}
static async remove(key: string): Promise<void> {
await AsyncStorage.removeItem(key);
}
}
export default Storage;
创建用户状态管理
// stores/userStore.ts
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';
interface User {
id: string;
name: string;
email: string;
}
interface UserState {
user: User | null;
setUser: (user: User) => void;
clearUser: () => void;
}
export const useUserStore = create<UserState>()(
persist(
(set) => ({
user: null,
setUser: (user) => set({ user }),
clearUser: () => set({ user: null }),
}),
{
name: 'user-storage',
storage: createJSONStorage(() => AsyncStorage),
}
)
);
日期格式化工具
// utils/date.ts
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/zh-cn';
dayjs.extend(relativeTime);
dayjs.locale('zh-cn');
export const formatDate = (date: Date | string | number) => {
return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
};
export const formatRelativeTime = (date: Date | string | number) => {
return dayjs(date).fromNow();
};
export const formatChatTime = (timestamp: number) => {
const date = dayjs(timestamp);
const now = dayjs();
if (date.isSame(now, 'day')) {
return date.format('HH:mm');
} else if (date.isSame(now.subtract(1, 'day'), 'day')) {
return '昨天 ' + date.format('HH:mm');
} else if (date.isSame(now, 'year')) {
return date.format('MM-DD HH:mm');
} else {
return date.format('YYYY-MM-DD');
}
};
📝 最佳实践
-
代码组织
- 将 API 配置放在
utils/api.ts - 将存储工具放在
utils/storage.ts - 将状态管理放在
stores/目录 - 将验证规则放在
schemas/目录
- 将 API 配置放在
-
性能优化
- 使用
_.debounce和_.throttle优化频繁触发的事件 - 使用 Zustand 的选择器避免不必要的重渲染
- 使用 Expo Image 的缓存策略
- 使用
-
类型安全
- 使用 Zod 定义数据结构并自动生成 TypeScript 类型
- 为 Zustand store 定义完整的类型
- 使用
@types/lodash获得完整的类型提示
-
错误处理
- 在 Axios 拦截器中统一处理错误
- 使用 try-catch 包裹异步操作
- 提供用户友好的错误提示
🔗 相关资源
- Lodash 文档
- Day.js 文档
- Axios 文档
- Zustand 文档
- React Hook Form 文档
- Zod 文档
- AsyncStorage 文档
- Expo Image 文档
- Expo Haptics 文档
提示:所有库都已安装并配置好,可以直接在项目中使用!🎉