
本文详解如何正确使用 React 的 useState 和 useEffect 实现基于异步 API 数据的下拉菜单渲染,避免常见陷阱如变量赋值不触发重绘、无限重渲染等问题。
本文详解如何正确使用 react 的 `usestate` 和 `useeffect` 实现基于异步 api 数据的下拉菜单渲染,避免常见陷阱如变量赋值不触发重绘、无限重渲染等问题。
在 React 中,直接修改普通变量(如 let contactDropdown = >)不会触发组件重渲染——这是初学者最常忽略的核心机制。React 只响应 状态(state)的变化,而非普通变量的重新赋值。因此,即使你成功从 Microsoft Graph API 获取了联系人数据,并构造了 <select></select> 元素,若未通过 useState + setState 更新状态,UI 将始终保持初始空内容 >。
✅ 正确做法:用 useState 管理数据,用 useEffect 控制副作用
首先,将联系人数据本身存入状态(推荐方式),而非预渲染的 JSX:
import { useState, useEffect } from 'react';
const App = () => {
const [contacts, setContacts] = useState([]); // ✅ 存储原始数据,非 JSX
useEffect(() => {
const fetchContacts = async () => {
try {
await Office.onReady();
// 获取 Microsoft Graph 访问令牌
const graphTokenResponse = await graphAuth.getToken(graphLoginRequest);
const accessToken = graphTokenResponse.accessToken;
// 获取当前邮件信息
const message = await getMessage(
accessToken,
Office.context.mailbox.item.itemId
);
// 调用自定义后端接口获取联系人
const contactsData = await getContactsByEmail(
message.from.emailAddress.address
);
// ✅ 更新状态 → 触发重渲染
setContacts(contactsData);
} catch (error) {
console.error('Failed to load contacts:', error);
}
};
fetchContacts();
}, []); // ? 空依赖数组:仅在组件挂载时执行一次
// ✅ 渲染逻辑放在 return 中,基于最新 state
return (
<div>
{contacts.length > 0 ? (
<select aria-label="Select a contact">
{contacts.map((contact) => (
<option key={contact.id} value={contact.id}>
{contact.name}
</option>
))}
</select>
) : (
<p>Loading contacts or no results found.</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill10835" title="React 组件生成器"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20dee630206.jpg" alt="React 组件生成器" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill10835" title="React 组件生成器">React 组件生成器</a>
<p>根据项目规范生成 React 和 Vue 组件,包括 TypeScript 类型定义、Ant Design 5 集成、Tailwind CSS 样式及 Vitest 测试文件。当用户提出创建、生成或搭建前端组件的需求时启用,例如:“帮我写一个表格组件”、“生成一个弹窗”、“create a form component”、“写一个列表页”、“生成一个下拉选择器”。该能力在以下任一场景触发:涉及 React/TSX/Vue 组件生成、UI 组件创建,或为组件生成测试文件。</p>
</div>
<a href="/xiazai/skill10835" title="React 组件生成器" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div>
)}
</div>
);
};
export default App;⚠️ 关键注意事项
-
不要在组件顶层直接执行异步操作:否则每次渲染都会重复调用 API,极易导致无限循环(尤其当
setState触发重渲染时); -
避免将 JSX 存入 state:虽然
useState(<select>...</select>)在技术上可行,但不利于后续扩展(如添加搜索、分页、联动逻辑等),且违背“状态即数据”的设计原则; -
务必处理加载与错误状态:实际项目中应加入
loading和error状态,提升用户体验; -
确保
key唯一且稳定:contact.id是理想选择;若无 ID,避免使用index(可能导致 DOM 复用异常); -
Office.js 上下文需在
Office.onReady()后使用:本例已正确包裹,确保 Outlook 加载完成后再访问邮箱项。
✅ 总结
要让下拉框随 API 数据动态呈现,只需三步:
- 用
useState初始化联系人数据(如[]); - 用
useEffect(..., [])封装异步获取逻辑,确保只执行一次; - 在 JSX 中基于
contacts数组条件渲染<select></select>—— React 会自动响应状态更新并刷新 UI。
这才是符合 React 数据流规范、可维护、可扩展的标准实践。

















