技术文档中心
首页
React
Vue
TypeScript
Kotlin
React Native
Electron
Android
首页
React
Vue
TypeScript
Kotlin
React Native
Electron
Android
  • 基础入门

    • React Native 学习指南
    • 核心组件
    • 样式
  • 进阶内容

    • 导航
    • 网络请求
    • 本地存储
    • 常用 API

网络请求

Fetch API

GET 请求

import { useState, useEffect } from 'react';
import { View, Text, ActivityIndicator, FlatList } from 'react-native';

function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchUsers();
  }, []);

  const fetchUsers = async () => {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/users');
      
      if (!response.ok) {
        throw new Error('网络请求失败');
      }
      
      const data = await response.json();
      setUsers(data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <ActivityIndicator size="large" color="#007AFF" />
      </View>
    );
  }

  if (error) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text style={{ color: 'red' }}>错误: {error}</Text>
      </View>
    );
  }

  return (
    <FlatList
      data={users}
      keyExtractor={item => item.id.toString()}
      renderItem={({ item }) => (
        <View style={{ padding: 15, borderBottomWidth: 1, borderBottomColor: '#eee' }}>
          <Text style={{ fontSize: 16, fontWeight: 'bold' }}>{item.name}</Text>
          <Text style={{ color: '#666' }}>{item.email}</Text>
        </View>
      )}
    />
  );
}

POST 请求

import { useState } from 'react';
import { View, TextInput, TouchableOpacity, Text, Alert } from 'react-native';

function CreateUser() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [loading, setLoading] = useState(false);

  const handleSubmit = async () => {
    if (!name || !email) {
      Alert.alert('错误', '请填写所有字段');
      return;
    }

    setLoading(true);

    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/users', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          name,
          email
        })
      });

      if (!response.ok) {
        throw new Error('创建失败');
      }

      const data = await response.json();
      Alert.alert('成功', `用户创建成功,ID: ${data.id}`);
      setName('');
      setEmail('');
    } catch (error) {
      Alert.alert('错误', error.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <View style={{ padding: 20 }}>
      <TextInput
        style={{
          borderWidth: 1,
          borderColor: '#ddd',
          padding: 10,
          marginBottom: 10,
          borderRadius: 5
        }}
        placeholder="姓名"
        value={name}
        onChangeText={setName}
      />
      
      <TextInput
        style={{
          borderWidth: 1,
          borderColor: '#ddd',
          padding: 10,
          marginBottom: 20,
          borderRadius: 5
        }}
        placeholder="邮箱"
        value={email}
        onChangeText={setEmail}
        keyboardType="email-address"
      />
      
      <TouchableOpacity
        style={{
          backgroundColor: loading ? '#ccc' : '#007AFF',
          padding: 15,
          borderRadius: 5,
          alignItems: 'center'
        }}
        onPress={handleSubmit}
        disabled={loading}
      >
        <Text style={{ color: '#fff', fontWeight: 'bold' }}>
          {loading ? '提交中...' : '提交'}
        </Text>
      </TouchableOpacity>
    </View>
  );
}

PUT/PATCH 请求

const updateUser = async (id, updates) => {
  try {
    const response = await fetch(`https://api.example.com/users/${id}`, {
      method: 'PUT', // 或 'PATCH'
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(updates)
    });

    const data = await response.json();
    return data;
  } catch (error) {
    console.error('更新失败:', error);
    throw error;
  }
};

DELETE 请求

const deleteUser = async (id) => {
  try {
    const response = await fetch(`https://api.example.com/users/${id}`, {
      method: 'DELETE'
    });

    if (response.ok) {
      Alert.alert('成功', '删除成功');
    }
  } catch (error) {
    Alert.alert('错误', '删除失败');
  }
};

Axios

安装

yarn add axios

基础使用

import axios from 'axios';
import { useState, useEffect } from 'react';

function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    axios.get('https://jsonplaceholder.typicode.com/users')
      .then(response => {
        setUsers(response.data);
        setLoading(false);
      })
      .catch(error => {
        console.error(error);
        setLoading(false);
      });
  }, []);

  // 渲染逻辑...
}

配置实例

// api/client.js
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';

const apiClient = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json'
  }
});

// 请求拦截器
apiClient.interceptors.request.use(
  async (config) => {
    // 添加 token
    const token = await AsyncStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    
    console.log('请求:', config.method.toUpperCase(), config.url);
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 响应拦截器
apiClient.interceptors.response.use(
  (response) => {
    console.log('响应:', response.status, response.config.url);
    return response.data;
  },
  async (error) => {
    if (error.response) {
      // 服务器返回错误
      const { status, data } = error.response;
      
      if (status === 401) {
        // token 过期,清除并跳转登录
        await AsyncStorage.removeItem('token');
        // 导航到登录页
      } else if (status === 403) {
        Alert.alert('错误', '没有权限');
      } else if (status === 500) {
        Alert.alert('错误', '服务器错误');
      }
      
      return Promise.reject(data);
    } else if (error.request) {
      // 请求发送但没有响应
      Alert.alert('错误', '网络连接失败');
    } else {
      // 其他错误
      Alert.alert('错误', error.message);
    }
    
    return Promise.reject(error);
  }
);

export default apiClient;

API 封装

// api/user.js
import apiClient from './client';

export const userAPI = {
  // 获取用户列表
  getUsers: () => apiClient.get('/users'),
  
  // 获取单个用户
  getUser: (id) => apiClient.get(`/users/${id}`),
  
  // 创建用户
  createUser: (data) => apiClient.post('/users', data),
  
  // 更新用户
  updateUser: (id, data) => apiClient.put(`/users/${id}`, data),
  
  // 删除用户
  deleteUser: (id) => apiClient.delete(`/users/${id}`),
  
  // 登录
  login: (credentials) => apiClient.post('/auth/login', credentials),
  
  // 注册
  register: (data) => apiClient.post('/auth/register', data)
};

使用封装的 API

import { useState, useEffect } from 'react';
import { userAPI } from './api/user';

function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    loadUsers();
  }, []);

  const loadUsers = async () => {
    try {
      const data = await userAPI.getUsers();
      setUsers(data);
    } catch (error) {
      console.error('加载失败:', error);
    } finally {
      setLoading(false);
    }
  };

  const handleDelete = async (id) => {
    try {
      await userAPI.deleteUser(id);
      setUsers(users.filter(u => u.id !== id));
      Alert.alert('成功', '删除成功');
    } catch (error) {
      Alert.alert('错误', '删除失败');
    }
  };

  // 渲染逻辑...
}

自定义 Hook

useFetch

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let isMounted = true;

    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url);
        
        if (!response.ok) {
          throw new Error('请求失败');
        }
        
        const json = await response.json();
        
        if (isMounted) {
          setData(json);
          setError(null);
        }
      } catch (err) {
        if (isMounted) {
          setError(err.message);
        }
      } finally {
        if (isMounted) {
          setLoading(false);
        }
      }
    };

    fetchData();

    return () => {
      isMounted = false;
    };
  }, [url]);

  return { data, loading, error };
}

// 使用
function UserList() {
  const { data: users, loading, error } = useFetch(
    'https://jsonplaceholder.typicode.com/users'
  );

  if (loading) return <ActivityIndicator />;
  if (error) return <Text>错误: {error}</Text>;

  return (
    <FlatList
      data={users}
      keyExtractor={item => item.id.toString()}
      renderItem={({ item }) => <Text>{item.name}</Text>}
    />
  );
}

useAPI

import { useState } from 'react';

function useAPI(apiFunc) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const execute = async (...args) => {
    try {
      setLoading(true);
      setError(null);
      const result = await apiFunc(...args);
      setData(result);
      return result;
    } catch (err) {
      setError(err.message);
      throw err;
    } finally {
      setLoading(false);
    }
  };

  return { data, loading, error, execute };
}

// 使用
function CreateUser() {
  const { loading, error, execute } = useAPI(userAPI.createUser);

  const handleSubmit = async () => {
    try {
      const result = await execute({ name: 'John', email: 'john@example.com' });
      Alert.alert('成功', `用户创建成功,ID: ${result.id}`);
    } catch (error) {
      Alert.alert('错误', '创建失败');
    }
  };

  return (
    <TouchableOpacity onPress={handleSubmit} disabled={loading}>
      <Text>{loading ? '提交中...' : '提交'}</Text>
    </TouchableOpacity>
  );
}

图片上传

import { useState } from 'react';
import { View, Image, TouchableOpacity, Text, Alert } from 'react-native';
import { launchImageLibrary } from 'react-native-image-picker';

function ImageUpload() {
  const [image, setImage] = useState(null);
  const [uploading, setUploading] = useState(false);

  const selectImage = () => {
    launchImageLibrary(
      {
        mediaType: 'photo',
        quality: 0.8
      },
      (response) => {
        if (response.didCancel) {
          return;
        }
        
        if (response.errorCode) {
          Alert.alert('错误', response.errorMessage);
          return;
        }
        
        setImage(response.assets[0]);
      }
    );
  };

  const uploadImage = async () => {
    if (!image) {
      Alert.alert('提示', '请先选择图片');
      return;
    }

    setUploading(true);

    const formData = new FormData();
    formData.append('file', {
      uri: image.uri,
      type: image.type,
      name: image.fileName || 'image.jpg'
    });

    try {
      const response = await fetch('https://api.example.com/upload', {
        method: 'POST',
        headers: {
          'Content-Type': 'multipart/form-data',
        },
        body: formData
      });

      const data = await response.json();
      Alert.alert('成功', '上传成功');
    } catch (error) {
      Alert.alert('错误', '上传失败');
    } finally {
      setUploading(false);
    }
  };

  return (
    <View style={{ padding: 20 }}>
      {image && (
        <Image
          source={{ uri: image.uri }}
          style={{ width: 200, height: 200, marginBottom: 20 }}
        />
      )}
      
      <TouchableOpacity
        style={{
          backgroundColor: '#007AFF',
          padding: 15,
          borderRadius: 5,
          marginBottom: 10
        }}
        onPress={selectImage}
      >
        <Text style={{ color: '#fff', textAlign: 'center' }}>选择图片</Text>
      </TouchableOpacity>
      
      <TouchableOpacity
        style={{
          backgroundColor: uploading ? '#ccc' : '#34C759',
          padding: 15,
          borderRadius: 5
        }}
        onPress={uploadImage}
        disabled={uploading || !image}
      >
        <Text style={{ color: '#fff', textAlign: 'center' }}>
          {uploading ? '上传中...' : '上传图片'}
        </Text>
      </TouchableOpacity>
    </View>
  );
}

实战:完整的登录流程

// screens/LoginScreen.js
import React, { useState } from 'react';
import {
  View,
  Text,
  TextInput,
  TouchableOpacity,
  StyleSheet,
  Alert,
  ActivityIndicator
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { userAPI } from '../api/user';

function LoginScreen({ navigation }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading] = useState(false);

  const handleLogin = async () => {
    if (!email || !password) {
      Alert.alert('错误', '请填写所有字段');
      return;
    }

    setLoading(true);

    try {
      const response = await userAPI.login({ email, password });
      
      // 保存 token
      await AsyncStorage.setItem('token', response.token);
      await AsyncStorage.setItem('user', JSON.stringify(response.user));
      
      // 跳转到主页
      navigation.replace('Home');
    } catch (error) {
      Alert.alert('登录失败', error.message || '请检查用户名和密码');
    } finally {
      setLoading(false);
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>登录</Text>
      
      <TextInput
        style={styles.input}
        placeholder="邮箱"
        value={email}
        onChangeText={setEmail}
        keyboardType="email-address"
        autoCapitalize="none"
      />
      
      <TextInput
        style={styles.input}
        placeholder="密码"
        value={password}
        onChangeText={setPassword}
        secureTextEntry
      />
      
      <TouchableOpacity
        style={[styles.button, loading && styles.buttonDisabled]}
        onPress={handleLogin}
        disabled={loading}
      >
        {loading ? (
          <ActivityIndicator color="#fff" />
        ) : (
          <Text style={styles.buttonText}>登录</Text>
        )}
      </TouchableOpacity>
      
      <TouchableOpacity onPress={() => navigation.navigate('Register')}>
        <Text style={styles.link}>还没有账号?立即注册</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    justifyContent: 'center',
    backgroundColor: '#fff'
  },
  title: {
    fontSize: 32,
    fontWeight: 'bold',
    marginBottom: 40,
    textAlign: 'center'
  },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    padding: 15,
    borderRadius: 8,
    marginBottom: 15,
    fontSize: 16
  },
  button: {
    backgroundColor: '#007AFF',
    padding: 15,
    borderRadius: 8,
    marginTop: 10
  },
  buttonDisabled: {
    backgroundColor: '#ccc'
  },
  buttonText: {
    color: '#fff',
    textAlign: 'center',
    fontSize: 16,
    fontWeight: 'bold'
  },
  link: {
    color: '#007AFF',
    textAlign: 'center',
    marginTop: 20
  }
});

export default LoginScreen;
最近更新: 2026/2/6 15:39
Contributors: hailong
Prev
导航
Next
本地存储