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.
 
 

11 KiB

💡 使用示例

本文档提供项目中各个工具和模块的实际使用示例。

📋 目录


登录功能示例

完整的登录页面实现,包含表单验证、API 调用、状态管理。

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 服务更新用户资料。

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>
  );
}

搜索功能示例

使用防抖优化搜索性能。

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>
  );
}

设置页面示例

使用状态管理和触觉反馈。

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>
  );
}

📚 更多示例

查看以下文档了解更多:


提示:这些示例都是可以直接使用的代码,复制到你的项目中即可!