如何在模板字面量中使用Async Await?React组件场景问题
解决React组件中Autocomplete渲染异步数据的问题
你当前的写法存在两个核心问题:
- 直接在模板字符串里执行异步函数,会返回
Promise对象,模板字符串会把它转为[object Promise],所以显示的是字符串字面量而非实际邮编 - 异步操作的结果无法直接同步渲染到UI中,需要结合React状态管理来处理
正确实现步骤:
- 用状态存储每个选项的邮编:通过
useState创建一个对象,以place_id为键,存储对应的邮编或加载状态 - 封装异步请求函数:用
useCallback包裹请求逻辑,避免重复创建函数,同时处理请求竞态问题 - 在渲染选项时触发请求并处理状态:渲染每个选项时,检查是否已有对应的邮编,没有则触发请求,根据状态显示加载提示或实际邮编
完整代码示例:
import { useState, useCallback } from "react"; import { Autocomplete, TextField } from "@mui/material"; import usePlacesAutocomplete, { getGeocode, getZipCode } from "use-places-autocomplete"; const Places = () => { // 存储每个place_id对应的邮编,格式:{ [placeId]: string | "loading" | null } const [zipCodes, setZipCodes] = useState({}); // 封装获取邮编的异步函数,处理竞态问题 const fetchZipCode = useCallback(async (placeId) => { // 标记为加载中 setZipCodes(prev => ({ ...prev, [placeId]: "loading" })); try { const results = await getGeocode({ placeId }); const zipCode = getZipCode(results[0], true); // 更新状态,仅当当前请求的placeId未被其他请求覆盖时才更新 setZipCodes(prev => ({ ...prev, [placeId]: zipCode })); } catch (error) { console.error("获取邮编失败:", error); setZipCodes(prev => ({ ...prev, [placeId]: null })); } }, []); return ( <Autocomplete options={[]} // 替换为你的地址数据源 getOptionLabel={(option) => option.description} renderOption={(props, option) => { const placeId = option.place_id; // 若未加载过邮编,触发请求 if (!zipCodes[placeId]) { fetchZipCode(placeId); } const zipCode = zipCodes[placeId]; return ( <li {...props}> {option.description} {/* 根据状态显示不同内容 */} {zipCode === "loading" && " (加载中...)"} {zipCode && zipCode !== "loading" && ` (邮编:${zipCode})`} {zipCode === null && " (获取邮编失败)"} </li> ); }} renderInput={(params) => <TextField {...params} label="搜索地址" />} /> ); }; export default Places;
关键说明:
- 状态管理:用
zipCodes对象存储每个地址的邮编,避免重复请求同一地址的邮编 - 竞态处理:更新状态时先解构之前的状态,确保当前请求的结果不会被更早发起但延迟返回的请求覆盖
- UI反馈:添加加载状态和错误状态的提示,提升用户体验
内容的提问来源于stack exchange,提问作者Clippit
相关产品推荐
相关产品推荐

