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

📚 常用工具库使用指南

本文档介绍项目中已安装的常用工具库及其使用方法。

📦 已安装的库列表

工具类库

库名 版本 用途
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');
  }
};

📝 最佳实践

  1. 代码组织

    • 将 API 配置放在 utils/api.ts
    • 将存储工具放在 utils/storage.ts
    • 将状态管理放在 stores/ 目录
    • 将验证规则放在 schemas/ 目录
  2. 性能优化

    • 使用 _.debounce_.throttle 优化频繁触发的事件
    • 使用 Zustand 的选择器避免不必要的重渲染
    • 使用 Expo Image 的缓存策略
  3. 类型安全

    • 使用 Zod 定义数据结构并自动生成 TypeScript 类型
    • 为 Zustand store 定义完整的类型
    • 使用 @types/lodash 获得完整的类型提示
  4. 错误处理

    • 在 Axios 拦截器中统一处理错误
    • 使用 try-catch 包裹异步操作
    • 提供用户友好的错误提示

🔗 相关资源


提示:所有库都已安装并配置好,可以直接在项目中使用!🎉