React Native 全栈开发实战班 - 网络与数据之网络请求基础

在移动应用中,网络请求 是实现与服务器进行数据交互的核心功能。React Native 基于 JavaScript 的特性,提供了多种方式进行网络请求,包括使用 fetch API、axios 库以及 WebSocket 等。本章节将详细介绍如何在 React Native 中进行网络请求,包括基本用法、错误处理、请求拦截以及使用第三方库进行更复杂的网络操作。


1.1 网络请求概述

在 React Native 应用中,网络请求主要用于以下场景:

  • 数据获取: 从服务器获取数据,如用户信息、文章列表等。
  • 数据提交: 向服务器提交数据,如用户注册、登录、发布文章等。
  • 实时通信: 通过 WebSocket 实现实时数据推送,如聊天应用、实时通知等。

React Native 提供了多种方式进行网络请求:

  1. fetch API: 内置于 JavaScript 的网络请求 API,简单易用。
  2. axios 库: 第三方网络请求库,功能更强大,支持拦截器、取消请求等。
  3. WebSocket: 用于实现实时双向通信。

本章节将重点介绍 fetch API 和 axios 库的使用。


1.2 使用 fetch API

fetch 是 JavaScript 提供的一个用于进行网络请求的 API,React Native 对其进行了支持。

1.2.1 基本用法

语法:

javascript 复制代码
fetch(url, {
  method: 'GET', // 请求方法:GET, POST, PUT, DELETE, etc.
  headers: {
    'Content-Type': 'application/json',
    // 其他头部信息
  },
  body: JSON.stringify(data), // 请求体
})
  .then((response) => response.json())
  .then((json) => {
    // 处理响应数据
  })
  .catch((error) => {
    // 处理错误
  });

示例:GET 请求

javascript 复制代码
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';

const DataFetcher = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts/1')
      .then((response) => response.json())
      .then((json) => setData(json))
      .catch((error) => console.error(error));
  }, []);

  return (
    <View style={styles.container}>
      {data ? (
        <Text style={styles.text}>{JSON.stringify(data)}</Text>
      ) : (
        <Text>Loading...</Text>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 16,
  },
});

export default DataFetcher;

示例:POST 请求

javascript 复制代码
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

const DataPoster = () => {
  const [response, setResponse] = useState(null);

  const postData = () => {
    const data = { title: 'foo', body: 'bar', userId: 1 };

    fetch('https://jsonplaceholder.typicode.com/posts', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(data),
    })
      .then((response) => response.json())
      .then((json) => setResponse(json))
      .catch((error) => console.error(error));
  };

  return (
    <View style={styles.container}>
      <Button title="Post Data" onPress={postData} />
      {response && <Text style={styles.text}>{JSON.stringify(response)}</Text>}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 16,
    marginTop: 10,
  },
});

export default DataPoster;
1.2.2 错误处理

在网络请求中,错误处理是非常重要的。可以通过 catch 捕获错误,并进行相应的处理。

示例:

javascript 复制代码
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';

const ErrorHandlingExample = () => {
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch('https://invalid-url.com/data')
      .then((response) => response.json())
      .then((json) => {
        // 处理数据
      })
      .catch((error) => {
        console.error(error);
        setError('网络请求失败');
      });
  }, []);

  return (
    <View style={styles.container}>
      {error && <Text style={styles.text}>{error}</Text>}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 16,
    color: 'red',
  },
});

export default ErrorHandlingExample;
1.2.3 请求拦截

fetch 本身不支持请求拦截,但可以通过封装 fetch 函数来实现。

示例:

javascript 复制代码
// api.js
import { Platform } from 'react-native';

const api = {
  get: (url, headers = {}) => {
    return fetch(url, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        ...headers,
      },
    });
  },
  post: (url, data, headers = {}) => {
    return fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...headers,
      },
      body: JSON.stringify(data),
    });
  },
  // 其他方法:put, delete, etc.
};

// 添加请求拦截器
api.interceptors = {
  request: {
    use: (callback) => {
      const originalGet = api.get;
      api.get = (url, headers) => {
        return callback(originalGet(url, headers));
      };

      const originalPost = api.post;
      api.post = (url, data, headers) => {
        return callback(originalPost(url, data, headers));
      };
      // 其他方法
    },
  },
};

export default api;
javascript 复制代码
// App.js
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import api from './api';

api.interceptors.request.use((originalFetch) => (...args) => {
  // 添加请求头
  const [url, options] = args;
  options.headers = {
    ...options.headers,
    Authorization: 'Bearer token',
  };
  return originalFetch(url, options);
});

const App = () => {
  const fetchData = async () => {
    try {
      const response = await api.get('https://jsonplaceholder.typicode.com/posts/1');
      const json = await response.json();
      console.log(json);
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.text}>Fetch Data</Text>
      <Button title="Get Data" onPress={fetchData} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 18,
  },
});

export default App;

1.3 使用 axios

axios 是一个第三方网络请求库,功能更强大,支持拦截器、取消请求、请求超时等。相比 fetchaxios 提供了更简洁的 API 和更丰富的功能。

1.3.1 安装 axios
bash 复制代码
npm install axios
1.3.2 基本用法

以下是一个使用 axios 发送 POST 请求的示例:

javascript 复制代码
// components/PostData.js
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet, ActivityIndicator } from 'react-native';
import axios from 'axios';

const PostData = () => {
  const [response, setResponse] = useState(null);
  const [loading, setLoading] = useState(false);

  const handlePost = async () => {
    setLoading(true);
    try {
      const data = { title: 'foo', body: 'bar', userId: 1 };
      const res = await axios.post('https://jsonplaceholder.typicode.com/posts', data);
      setResponse(res.data);
    } catch (error) {
      console.error(error);
      alert('请求失败');
    } finally {
      setLoading(false);
    }
  };

  return (
    <View style={styles.container}>
      <Button title="Post Data" onPress={handlePost} />
      {loading && <ActivityIndicator size="large" color="#0000ff" />}
      {response && (
        <View style={styles.responseContainer}>
          <Text style={styles.responseText}>Response:</Text>
          <Text>{JSON.stringify(response)}</Text>
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  responseContainer: {
    marginTop: 20,
    padding: 10,
    backgroundColor: '#f0f0f0',
    borderRadius: 5,
  },
  responseText: {
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 5,
  },
});

export default PostData;

解释:

  • 发送 POST 请求:

    • 使用 axios.post 方法发送 POST 请求,第一个参数是请求的 URL,第二个参数是请求体数据。
    • axios.post 返回一个 Promise,可以通过 thencatch 处理响应和错误。
  • 错误处理:

    • 使用 try...catch 捕获请求错误,并进行相应处理(如显示错误提示)。
  • 加载状态:

    • 使用 loading 状态控制 ActivityIndicator 的显示,提示用户请求正在进行中。
  • 显示响应数据:

    • 将响应数据存储在 response 状态中,并在界面上显示。
1.3.3 拦截器

axios 提供了请求拦截器和响应拦截器,可以在请求发送前和响应返回后进行统一处理。

示例:添加请求头和响应处理

javascript 复制代码
// api.js
import axios from 'axios';

// 创建 axios 实例
const api = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com',
});

// 添加请求拦截器
api.interceptors.request.use(
  (config) => {
    // 在发送请求之前做些什么
    config.headers['Authorization'] = 'Bearer token';
    return config;
  },
  (error) => {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

// 添加响应拦截器
api.interceptors.response.use(
  (response) => {
    // 对响应数据做点什么
    return response;
  },
  (error) => {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);

export default api;
javascript 复制代码
// components/PostData.js
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet, ActivityIndicator } from 'react-native';
import api from '../api';

const PostData = () => {
  const [response, setResponse] = useState(null);
  const [loading, setLoading] = useState(false);

  const handlePost = async () => {
    setLoading(true);
    try {
      const data = { title: 'foo', body: 'bar', userId: 1 };
      const res = await api.post('/posts', data);
      setResponse(res.data);
    } catch (error) {
      console.error(error);
      alert('请求失败');
    } finally {
      setLoading(false);
    }
  };

  return (
    <View style={styles.container}>
      <Button title="Post Data" onPress={handlePost} />
      {loading && <ActivityIndicator size="large" color="#0000ff" />}
      {response && (
        <View style={styles.responseContainer}>
          <Text style={styles.responseText}>Response:</Text>
          <Text>{JSON.stringify(response)}</Text>
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  responseContainer: {
    marginTop: 20,
    padding: 10,
    backgroundColor: '#f0f0f0',
    borderRadius: 5,
  },
  responseText: {
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 5,
  },
});

export default PostData;

解释:

  • 创建 axios 实例:

    • 使用 axios.create 创建一个 axios 实例,并设置 baseURL
  • 请求拦截器:

    • 在请求发送前添加 Authorization 请求头。
  • 响应拦截器:

    • 在响应返回后进行统一处理,例如处理错误码、格式化数据等。
  • 使用 axios 实例:

    • 在组件中使用 api.post 发送请求,无需重复添加请求头。
1.3.4 取消请求

axios 支持取消请求,可以通过 CancelToken 实现。

示例:

javascript 复制代码
// components/CancelablePost.js
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet, ActivityIndicator } from 'react-native';
import axios from 'axios';

const CancelablePost = () => {
  const [response, setResponse] = useState(null);
  const [loading, setLoading] = useState(false);
  let cancelToken;

  const handlePost = async () => {
    setLoading(true);
    cancelToken = axios.CancelToken.source();
    try {
      const data = { title: 'foo', body: 'bar', userId: 1 };
      const res = await axios.post('https://jsonplaceholder.typicode.com/posts', data, {
        cancelToken: cancelToken.token,
      });
      setResponse(res.data);
    } catch (error) {
      if (axios.isCancel(error)) {
        console.log('请求取消');
      } else {
        console.error(error);
        alert('请求失败');
      }
    } finally {
      setLoading(false);
    }
  };

  const handleCancel = () => {
    if (cancelToken) {
      cancelToken.cancel('用户取消请求');
    }
  };

  return (
    <View style={styles.container}>
      <Button title="Post Data" onPress={handlePost} />
      <Button title="Cancel Request" onPress={handleCancel} />
      {loading && <ActivityIndicator size="large" color="#0000ff" />}
      {response && (
        <View style={styles.responseContainer}>
          <Text style={styles.responseText}>Response:</Text>
          <Text>{JSON.stringify(response)}</Text>
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  responseContainer: {
    marginTop: 20,
    padding: 10,
    backgroundColor: '#f0f0f0',
    borderRadius: 5,
  },
  responseText: {
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 5,
  },
});

export default CancelablePost;

解释:

  • 取消请求:
    • 使用 CancelToken.source() 创建一个取消令牌。
    • 在发送请求时,将取消令牌传递给 axios.post
    • 通过调用 cancelToken.cancel('用户取消请求') 可以取消请求。

作者简介

前腾讯电子签的前端负责人,现 whentimes tech CTO,专注于前端技术的大咖一枚!一路走来,从小屏到大屏,从 Web 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!

温馨提示:可搜老码小张公号联系导师

相关推荐
sure28215 小时前
React Native中创建自定义渐变色
前端·react native
墨狂之逸才15 小时前
React Native 物理按键扫码监听终极方案:从冲突到完美共存
react native
ServBay16 小时前
告别面条代码,PSL 5.0 重构 PHP 性能与安全天花板
后端·php
JaguarJack3 天前
FrankenPHP 原生支持 Windows 了
后端·php·服务端
BingoGo3 天前
FrankenPHP 原生支持 Windows 了
后端·php
是梦终空4 天前
React Native 性能优化指南
react native·性能优化
JaguarJack4 天前
PHP 的异步编程 该怎么选择
后端·php·服务端
BingoGo4 天前
PHP 的异步编程 该怎么选择
后端·php
JaguarJack5 天前
为什么 PHP 闭包要加 static?
后端·php·服务端
LING5 天前
RN容器启动优化实践
android·react native