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 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!

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

相关推荐
是Dream呀1 小时前
Python从0到100(七十八):神经网络--从0开始搭建全连接网络和CNN网络
网络·python·神经网络
kaixin_learn_qt_ing2 小时前
了解RPC
网络·网络协议·rpc
安全小王子3 小时前
Kali操作系统简单介绍
网络·web安全
Smile灬凉城6663 小时前
反序列化为啥可以利用加号绕过php正则匹配
开发语言·php
Hacker_LaoYi4 小时前
【漏洞分析】DDOS攻防分析(四)——TCP篇
网络·tcp/ip·ddos
爱吃水果蝙蝠汤4 小时前
DATACOM-IP单播路由(BGP)-复习-实验
网络·网络协议·tcp/ip
Sun_12_24 小时前
SQL注入(SQL lnjection Base)21
网络·数据库
奥顺5 小时前
PHPUnit使用指南:编写高效的单元测试
大数据·mysql·开源·php
网络安全Jack5 小时前
网络安全概论——身份认证
网络·数据库·web安全