使用Mobx Action获取任务时数据重复的原因排查
问题分析与解答
数据重复的原因
你的判断没错,React 18+的严格模式在开发环境下会自动执行两次空依赖的useEffect,这是React的调试机制,用来检测副作用代码是否能稳定运行。而你的fetchTasks方法里用this.tasks.push(...response.data.recordset),每次调用都会把后端返回的任务数组追加到现有tasks里,两次调用自然就导致数据重复了。
为什么没陷入无限循环
因为你的useEffect依赖是[](空数组),这意味着它只会在组件首次挂载时触发(严格模式下两次,但之后不会再触发)。哪怕TaskStore的tasks更新导致组件重渲染,useEffect因为没有监听任何依赖变化,也不会再次执行fetchTasks,所以不会出现无限循环的情况。
解决数据重复的几种方案
方案1:替换数组而非追加
修改fetchTasks里的赋值逻辑,直接替换整个tasks数组,而不是追加:
@action fetchTasks = async () => { try { const response: any = await axios.get('http://localhost:5000/test'); // 直接替换数组,覆盖原有内容 this.tasks = response.data.recordset; } catch (error) { console.error(error); } };
这样就算fetchTasks被调用两次,第二次的结果会覆盖第一次的,不会出现重复数据。
方案2:添加加载状态避免重复请求
在TaskStore里加一个标记,判断是否已经加载过任务,避免重复发起请求:
class TaskStore { constructor() { makeAutoObservable(this); } tasks = [] as Task[]; isTasksLoaded = false; // 新增加载状态标记 @action fetchTasks = async () => { // 如果已经加载过任务,直接返回 if (this.isTasksLoaded) return; try { const response: any = await axios.get('http://localhost:5000/test'); this.tasks.push(...response.data.recordset); this.isTasksLoaded = true; // 标记为已加载 } catch (error) { console.error(error); } }; }
方案3:了解React严格模式的行为(可选)
要记住React严格模式的两次执行只在开发环境存在,生产环境下useEffect只会执行一次。但还是推荐用前两种方案修复代码,不要依赖环境差异来规避问题。
内容的提问来源于stack exchange,提问作者Chan Kim
相关产品推荐
相关产品推荐

