在移动应用中,网络请求 是实现与服务器进行数据交互的核心功能。React Native 基于 JavaScript 的特性,提供了多种方式进行网络请求,包括使用 fetch
API、axios
库以及 WebSocket 等。本章节将详细介绍如何在 React Native 中进行网络请求,包括基本用法、错误处理、请求拦截以及使用第三方库进行更复杂的网络操作。
1.1 网络请求概述
在 React Native 应用中,网络请求主要用于以下场景:
- 数据获取: 从服务器获取数据,如用户信息、文章列表等。
- 数据提交: 向服务器提交数据,如用户注册、登录、发布文章等。
- 实时通信: 通过 WebSocket 实现实时数据推送,如聊天应用、实时通知等。
React Native 提供了多种方式进行网络请求:
fetch
API: 内置于 JavaScript 的网络请求 API,简单易用。axios
库: 第三方网络请求库,功能更强大,支持拦截器、取消请求等。- WebSocket: 用于实现实时双向通信。
本章节将重点介绍 fetch
API 和 axios
库的使用。
1.2 使用 fetch
API
fetch
是 JavaScript 提供的一个用于进行网络请求的 API,React Native 对其进行了支持。
1.2.1 基本用法
语法:
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 请求
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 请求
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
捕获错误,并进行相应的处理。
示例:
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
函数来实现。
示例:
// 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;
// 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
是一个第三方网络请求库,功能更强大,支持拦截器、取消请求、请求超时等。相比 fetch
,axios
提供了更简洁的 API 和更丰富的功能。
1.3.1 安装 axios
npm install axios
1.3.2 基本用法
以下是一个使用 axios
发送 POST 请求的示例:
// 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,可以通过then
和catch
处理响应和错误。
- 使用
-
错误处理:
- 使用
try...catch
捕获请求错误,并进行相应处理(如显示错误提示)。
- 使用
-
加载状态:
- 使用
loading
状态控制ActivityIndicator
的显示,提示用户请求正在进行中。
- 使用
-
显示响应数据:
- 将响应数据存储在
response
状态中,并在界面上显示。
- 将响应数据存储在
1.3.3 拦截器
axios
提供了请求拦截器和响应拦截器,可以在请求发送前和响应返回后进行统一处理。
示例:添加请求头和响应处理
// 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;
// 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
实现。
示例:
// 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 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!
温馨提示:可搜老码小张公号联系导师