在 React 开发中,async/await
是处理异步操作的强大工具,尤其适用于需要等待后台任务完成后再更新 UI 的场景。以下是 8 种典型应用场景和对应的代码示例:
1. 数据获取 (API 请求)
从服务器获取数据是最常见的异步操作场景。
import React, { useState, useEffect } from 'react';
const DataFetcher = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const jsonData = await response.json();
setData(jsonData);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return <div>{JSON.stringify(data)}</div>;
};
export default DataFetcher;
2. 表单提交
处理表单提交时,使用 async/await
等待服务器响应。
import React, { useState } from 'react';
const AsyncForm = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [status, setStatus] = useState('idle');
const handleSubmit = async (e) => {
e.preventDefault();
setStatus('submitting');
try {
const response = await fetch('https://api.example.com/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name, email }),
});
if (!response.ok) {
throw new Error('Failed to submit');
}
setStatus('success');
} catch (error) {
setStatus(`Error: ${error.message}`);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
/>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<button type="submit" disabled={status === 'submitting'}>
{status === 'submitting' ? 'Submitting...' : 'Submit'}
</button>
{status === 'success' && <div>Submitted successfully!</div>}
{status.startsWith('Error') && <div>{status}</div>}
</form>
);
};
export default AsyncForm;
3. 异步状态管理
在组件中管理异步状态。
import React, { useState } from 'react';
const AsyncStateExample = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const jsonData = await response.json();
setData(jsonData);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
};
return (
<div>
<button onClick={fetchData} disabled={loading}>
{loading ? 'Loading...' : 'Fetch Data'}
</button>
{data && <div>{JSON.stringify(data)}</div>}
</div>
);
};
export default AsyncStateExample;
4. 异步路由切换
在使用 React Router 时,完成异步操作后再切换路由。
import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
const AsyncRouteExample = () => {
const [username, setUsername] = useState('');
const history = useHistory();
const handleLogin = async () => {
try {
await new Promise((resolve) => setTimeout(resolve, 1000));
history.push('/dashboard');
} catch (error) {
console.error('Login failed:', error);
}
};
return (
<div>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="Username"
/>
<button onClick={handleLogin}>Login</button>
</div>
);
};
export default AsyncRouteExample;
5. 异步数据预加载
在组件渲染前预加载数据。
import React, { useState, useEffect } from 'react';
const AsyncDataPreload = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const preloadData = async () => {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const jsonData = await response.json();
setData(jsonData);
} catch (error) {
console.error('Error preloading data:', error);
} finally {
setLoading(false);
}
};
preloadData();
}, []);
if (loading) return <div>Loading data...</div>;
return <div>{JSON.stringify(data)}</div>;
};
export default AsyncDataPreload;
6. 第三方 API 调用
与浏览器 API 或第三方 SDK 交互。
async function getGeolocation() {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
}
function LocationButton() {
const [position, setPosition] = useState(null);
const handleClick = async () => {
try {
const pos = await getGeolocation();
setPosition({
lat: pos.coords.latitude,
lng: pos.coords.longitude
});
} catch (err) {
alert('无法获取位置信息');
}
};
return (
<div>
<button onClick={handleClick}>获取当前位置</button>
{position && <Map coordinates={position} />}
</div>
);
}
7. 文件上传/下载
处理文件上传并跟踪进度。
import axios from 'axios';
function FileUploader() {
const [progress, setProgress] = useState(0);
const uploadFile = async (file) => {
const formData = new FormData();
formData.append('file', file);
await axios.post('/api/upload', formData, {
onUploadProgress: (e) => {
setProgress(Math.round((e.loaded * 100) / e.total));
}
});
};
return (
<div>
<input type="file" onChange={e => uploadFile(e.target.files[0])} />
{progress > 0 && <ProgressBar value={progress} />}
</div>
);
}
8. 路由导航拦截
防止用户在有未保存更改时离开页面。
import { useNavigate, useLocation } from 'react-router-dom';
function EditArticle() {
const [isDirty, setIsDirty] = useState(false);
const navigate = useNavigate();
useEffect(() => {
const unblock = navigate.block((tx) => {
if (isDirty && !window.confirm('有未保存的更改,确定离开?')) {
tx.retry();
}
});
return () => unblock();
}, [isDirty]);
const saveArticle = async () => {
await fetch('/api/articles', { method: 'PUT' });
setIsDirty(false);
navigate('/articles');
};
return (/* 编辑器 UI */);
}
关键注意事项
组件卸载时的处理 在
useEffect
中使用标志位避免组件卸载后的状态更新。
useEffect(() => {
let isMounted = true;
const fetchData = async () => {
const data = await fetch('/api/data');
if (isMounted) setData(data);
};
fetchData();
return () => { isMounted = false; };
}, []);
错误处理 捕获并处理异步操作中的错误,避免未处理的承诺拒绝。
try {
await fetchData();
} catch (error) {
if (error.name !== 'AbortError') {
showErrorToast(error.message);
}
}
防抖优化 对频繁触发的异步操作使用防抖。
const search = useDebouncedCallback(async (query) => {
const results = await fetchResults(query);
setResults(results);
}, 500);
通过以上示例和注意事项,可以全面了解在 React 中如何使用 async/await
处理各种异步场景,提升应用的响应性和用户体验。
React 中 async/await
的典型应用场景包括:
网络请求(GET/POST/PUT/DELETE)
文件操作(上传/下载)
浏览器 API 调用(地理位置/摄像头)
定时任务(延迟执行)
WebSocket 通信
数据库操作(IndexedDB)
动画序列控制
第三方库集成(支付 SDK)
合理使用异步操作可以使:
代码逻辑更清晰(避免回调地狱)
错误处理更直观(try/catch 统一捕获)
用户体验更友好(加载状态/进度提示)
码字不易,各位大佬点点赞呗