HOWTO · React
在 React 中发出 POST 请求的不同方法
使用 API 对于构建任何 Web 应用程序都是必不可少的。在本文中,我们将探讨如何在 React 应用程序中发出 POST 请求。
本页内容
React 不要求使用特定的 HTTP 客户端。对于新应用,可以从浏览器内置的 fetch() 开始;如果需要更方便的响应和错误处理,可以选择 axios;维护已使用 jQuery 的代码库时,可以继续使用 jQuery AJAX;也可以用 React Query 管理 mutation 状态。以下示例都将同一份示例个人资料数据发送到 https://api.example.test/profiles。这是占位端点,不是实际服务;请替换为你自己管理的 API。
使用 Fetch API
现代浏览器内置了 fetch(),它很适合发送简单的 POST 请求。将请求方法设为 POST,通过 Content-Type 请求头标明 JSON 请求体,并使用 JSON.stringify() 序列化对象。下面的函数接收一个 fetch 实现,因此请求构造和响应处理都包含在函数中。它使用本地响应进行演示,不会连接服务器。
async function createProfile(fetchImpl) {
const response = await fetchImpl('https://api.example.test/profiles', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Sam Lee', role: 'developer' }),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
const demoFetch = async (url, options) => ({
ok: true,
json: async () => ({ url, method: options.method, profile: JSON.parse(options.body) }),
});
createProfile(demoFetch).then((result) => console.log(result.profile.name, result.method));
返回的响应体会将提交的个人资料放在 profile 属性下,因此最后一行读取的是 result.profile.name。在组件中,可以从提交处理函数调用同一套请求逻辑,并使用组件状态显示结果。解析成功响应体之前,先检查 response.ok:对于 404 或 500 等 HTTP 响应,Fetch 仍会兑现 Promise;网络故障则会使 Promise 被拒绝。服务器可能不返回 JSON 响应体,因此只有在 API 承诺返回 JSON 时才解析 JSON。此示例使用内存中的响应,不会访问占位端点。
使用 Axios
在打包应用中,使用包管理器安装 axios,然后从该包导入它。post(url, data) 方法接受 JavaScript 对象,并会将其序列化为 JSON;请求成功后,服务器响应体位于 response.data 中。下面的浏览器示例从 esm.sh 导入模块,以便让示例保持自包含;它仅供说明,尚未执行。
<div id="root"></div>
<script type="module">
import React, { useState } from 'https://esm.sh/react';
import { createRoot } from 'https://esm.sh/react-dom/client';
import axios from 'https://esm.sh/axios';
function ProfileForm() {
const [profile, setProfile] = useState(null);
const [error, setError] = useState('');
async function handleSubmit(event) {
event.preventDefault();
setError('');
try {
const response = await axios.post('https://api.example.test/profiles', {
name: 'Sam Lee',
role: 'developer',
});
setProfile(response.data.profile ?? response.data);
} catch (requestError) {
const message = requestError.response
? `Request failed: ${requestError.response.status}`
: 'Network request failed';
setError(message);
}
}
return React.createElement('form', { onSubmit: handleSubmit },
React.createElement('button', { type: 'submit' }, 'Create profile'),
profile && React.createElement('p', null, `Created ${profile.name}`),
error && React.createElement('p', { role: 'alert' }, error));
}
createRoot(document.getElementById('root')).render(React.createElement(ProfileForm));
</script>
默认情况下,Axios 会针对非成功的 HTTP 状态码拒绝请求。下面的处理函数会区分服务器返回了响应和请求未收到响应这两种情况,并将相应结果存入 React 状态,而不会把错误当作成功的个人资料返回。如果拦截器、共享配置或响应转换能简化较大的应用,Axios 会很有用。只发送一个请求时,Fetch 可以避免添加依赖。
使用 jQuery AJAX
维护已经加载 jQuery 的应用时,jQuery AJAX 最实用。在 React 组件中,应由 React 负责渲染,并在 AJAX 回调中更新状态;不要用 jQuery 修改由 React 管理的 DOM 节点。下面的浏览器和包示例仅供说明,尚未执行。使用该组件前,请通过应用现有的包管理设置添加 jQuery。
<div id="root"></div>
<script type="module">
import React, { useState } from 'https://esm.sh/react';
import { createRoot } from 'https://esm.sh/react-dom/client';
import $ from 'https://esm.sh/jquery';
function ProfileForm() {
const [profile, setProfile] = useState(null);
const [error, setError] = useState('');
function handleSubmit(event) {
event.preventDefault();
setError('');
$.ajax({
url: 'https://api.example.test/profiles',
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify({ name: 'Sam Lee', role: 'developer' }),
success: (data) => setProfile(data.profile ?? data),
error: (xhr, status, requestError) => {
setError(xhr.responseJSON?.message || requestError || status);
},
});
}
return React.createElement('form', { onSubmit: handleSubmit },
React.createElement('button', { type: 'submit' }, 'Create profile'),
profile && React.createElement('p', null, `Created ${profile.name}`),
error && React.createElement('p', { role: 'alert' }, error));
}
createRoot(document.getElementById('root')).render(React.createElement(ProfileForm));
</script>
这里的 contentType 用于描述 JSON 请求体,而 dataType 告诉 jQuery 按预期解析 JSON 响应。成功和失败时,回调都会更新 React 状态。这些选项不能保证服务器会接受请求或返回约定的格式。对于新的 React 项目,Fetch 或 Axios 通常更直接,也不需要额外引入 jQuery 依赖。
使用 React Query
当组件需要共享服务器状态行为,或需要清晰展示待处理、成功和错误状态时,React Query 可以将 POST 请求作为 mutation 管理。将网络请求放在 mutation 函数中,由用户提交操作触发,并根据已安装的库版本渲染其公开的状态。以下是与版本无关的工作流程,并非可以直接复制的 hook 签名:提交个人资料数据 → 执行 POST mutation → 显示待处理提示 → 显示返回的个人资料或错误。此概念示例尚未执行;在确定包名、导入方式、hook 签名或状态属性名称之前,请查阅与你已安装版本相对应的 React Query 文档。
与用于读取数据的 query 相比,mutation 更适合会更改服务器数据的操作。操作成功后,应根据应用的数据流更新或使相关缓存失效。其他示例中的端点和 JSON 数据应保持一致,同时不要假定请求成功就会自动刷新所有视图。
使用 XMLHttpRequest
XMLHttpRequest 是一种浏览器 API,无需请求库即可发送 JSON POST 请求。它与 Fetch 不同,尽管两者都是浏览器内置选项。下面的事件驱动浏览器示例仅供说明,尚未在配置的运行环境中执行。
<div id="root"></div>
<script type="module">
import React, { useState } from 'https://esm.sh/react';
import { createRoot } from 'https://esm.sh/react-dom/client';
function ProfileForm() {
const [profile, setProfile] = useState(null);
const [error, setError] = useState('');
function handleSubmit(event) {
event.preventDefault();
setProfile(null);
setError('');
const request = new XMLHttpRequest();
request.open('POST', 'https://api.example.test/profiles');
request.setRequestHeader('Content-Type', 'application/json');
request.addEventListener('load', () => {
if (request.status < 200 || request.status >= 300) {
setError(`Request failed: ${request.status}`);
return;
}
try {
const data = JSON.parse(request.responseText);
setProfile(data.profile ?? data);
} catch {
setError('The server response was not valid JSON');
}
});
request.addEventListener('error', () => setError('Network request failed'));
request.send(JSON.stringify({ name: 'Sam Lee', role: 'developer' }));
}
return React.createElement('form', { onSubmit: handleSubmit },
React.createElement('button', { type: 'submit' }, 'Create profile'),
profile && React.createElement('p', null, `Created ${profile.name}`),
error && React.createElement('p', { role: 'alert' }, error));
}
createRoot(document.getElementById('root')).render(React.createElement(ProfileForm));
</script>
load 处理程序负责处理 HTTP 响应,因此会在解析响应体前检查状态码。error 处理程序负责处理网络故障。这两种情况都会更新 React 状态;在生产代码中,如果组件卸载,还应中止尚未完成的请求或忽略其结果。对于大多数新代码,Fetch 更简单;如果正在维护依赖 XMLHttpRequest 的代码,或应用需要事件驱动的接口,XMLHttpRequest 也可能适用。
结论
发送简单的浏览器 POST 请求时使用 Fetch;需要客户端功能时考虑 Axios;需要 mutation 状态管理和缓存协调时使用 React Query。维护现有 jQuery 代码时可以保留 jQuery AJAX;如果 XMLHttpRequest 的事件驱动 API 更适合应用,也可以选择它。无论采用哪种方式,都应根据服务器 API 设置请求体和请求头、检查响应,并在 React 界面中显示请求状态。
常见问题
POST 请求有什么作用?
POST 会向服务器发送数据供其处理,例如创建资源。提交数据的具体含义由 API 定义;POST 并不只用于更新现有资源。
应该使用 Fetch 还是 Axios?
Fetch 内置于现代浏览器,足以处理许多请求,但代码必须检查 HTTP 状态码,因为 HTTP 错误响应不会使它的 Promise 被拒绝。Axios 提供统一的响应对象,并默认针对非成功的 HTTP 状态码拒绝请求。请根据应用需求和已有依赖来选择。
可以在 React 中使用 jQuery 吗?
可以,尤其是在维护已经使用 jQuery 的应用时。让 React 管理它渲染的 DOM,并通过 AJAX 回调更新 React 状态。对于新代码,Fetch 或 Axios 通常更直接。
React Query 能为 POST 请求提供什么?
它会将请求作为 mutation 处理,并帮助将待处理、成功和错误状态与服务器状态管理联系起来。具体 API 取决于已安装的版本;实现细节请查阅该版本的文档。
应该如何处理 POST 请求错误?
应根据服务器约定检查 HTTP 状态码和响应数据,并向用户显示错误状态。使用 Fetch 时,检查 response.ok,因为 HTTP 失败仍会产生响应。使用 Axios 时,应处理被拒绝的请求,并区分服务器响应和网络故障。使用 jQuery 或 XMLHttpRequest 时,应通过相应的错误或网络事件处理问题,并更新 React 状态。