React TypeScript多API调用及状态追加问题求助
React + TypeScript setState 问题与优化方案
1. 解决 useEffect 开发模式触发两次的问题
React 18 的 StrictMode 会在开发环境下重复执行挂载阶段的副作用(包括 useEffect),目的是提前检测潜在的逻辑漏洞。除了你已做的去重处理,还可以优化成更可靠的方案:
- 给获取地点数据的 useEffect 加上明确的空依赖数组
[],确保组件挂载时仅执行一次请求; - 用地点的唯一标识(比如
id)做去重,避免依赖内容去重的不确定性:// 假设原始地点数据有唯一id字段 const uniqueLocations = Array.from( new Map(rawLocations.map(item => [item.id, item])).values() );
2. 修复 reservationData 无法追加的问题
不要用 any[] 模糊类型定义,建议先明确预订数据的类型,同时用函数式更新确保状态更新的可靠性:
// 定义预订数据的具体类型 interface Reservation { id: string; locationId: string; date: string; // 根据实际API返回补充字段 } const [reservationData, setReservationData] = useState<Reservation[]>([]); // 获取新预订数据后,用函数式更新追加 setReservationData(prevData => [...prevData, ...newReservations]);
函数式更新能确保每次都是基于最新的状态值进行修改,避免 setState 异步特性导致的状态覆盖问题。
3. 代码重构与组件拆分建议
(1)抽离自定义 Hook 封装数据逻辑
把 API 请求和数据处理逻辑拆成独立的自定义 Hook,让组件只负责 UI 渲染:
// hooks/useLocations.ts import { useState, useEffect } from 'react'; import api from '../api'; interface LocationOption { label: string; value: string; } export const useLocations = () => { const [locations, setLocations] = useState<LocationOption[]>([]); const [loading, setLoading] = useState(false); useEffect(() => { const fetchLocations = async () => { setLoading(true); try { const res = await api.get('/locations'); // 直接在Hook里完成MultiSelect的格式转换 const formattedOptions = res.data.map(item => ({ label: item.name, value: item.id })); setLocations(formattedOptions); } catch (err) { // 这里可以添加错误提示,比如用Mantine的Notification组件 console.error('获取地点数据失败:', err); } finally { setLoading(false); } }; fetchLocations(); }, []); return { locations, loading }; };
同理可以封装 useReservations Hook,负责根据选中地点获取预订数据。
(2)拆分独立UI组件
把页面拆成专注单一职责的小组件:
LocationSelector:封装 Mantine MultiSelect 的配置,接收地点列表、选中值、 onChange 回调;ReservationList:接收预订数据数组,负责渲染列表项和空状态;
主组件只需要串联这两个组件,处理选中地点后的逻辑触发。
(3)状态管理进阶优化
如果后续业务逻辑变复杂,建议用 React Query 替代手动 setState 管理 API 数据:它自带加载/错误状态、数据缓存、自动刷新等能力,能大幅减少重复的状态管理代码。
(4)完善错误处理
给所有 API 请求添加错误捕获和用户提示,比如用 Mantine 的 showNotification 展示错误信息,避免静默失败影响用户体验。
内容的提问来源于stack exchange,提问作者midnight28
相关产品推荐
相关产品推荐

