如何正确编写useEffect调用MobX Store方法并避免无限循环?
如何正确编写useEffect调用MobX Store方法并避免无限循环?
嗨,我看了你的代码,发现两个核心问题导致了无限循环和数据更新异常,咱们一步步来解决:
问题1:loadExternalAccounts的异步逻辑处理错误
你在runInAction里直接用了async/await的map循环,但runInAction是同步执行的,它不会等待异步请求完成,而且每个异步回调里的状态更新会零散触发MobX的响应,导致组件多次重渲染。
修改后的loadExternalAccounts代码:
loadExternalAccounts = async (accounts: any[]) => { try { console.log("accounts", accounts); // 先等待所有外部账户请求完成,统一收集结果 const externalAccounts = await Promise.all( accounts.map(async account => { const externalAccount = await agent.ExternalAccount.info('/mytoken', account.apiKey); externalAccount.externalId = account.id; return externalAccount; }) ); // 一次性更新状态,减少MobX的响应触发次数 runInAction(() => { externalAccounts.forEach(externalAccount => { this.externalAccountRegistry.set(externalAccount.externalId, externalAccount); }); }); console.log("this.externalAccountRegistry", this.externalAccountRegistry); } catch (error) { console.log(error); } }
这样做的好处是:所有异步请求并行完成后,再统一更新Map,避免了零散的状态变更触发多次组件渲染。
问题2:useEffect依赖项导致无限循环
你把accountsFromMap放进了useEffect的依赖数组,但它是MobX的计算属性,每次组件渲染时Array.from都会返回一个新数组,引用地址一直在变,导致useEffect每次都触发,陷入无限循环。
推荐用MobX自带的reaction来替代React的useEffect监听,更符合MobX的响应式逻辑:
export default observer(function AccountsTable() { const { accountStore, externalAccountStore } = useStore(); const { loadAccounts, accountsFromMap } = accountStore; const { loadExternalAccounts } = externalAccountStore; useEffect(() => { const loadData = async () => { // 先加载基础账户数据 await loadAccounts(); // 用MobX的reaction监听accountsFromMap的变化 const dispose = reaction( () => accountsFromMap, (accounts) => { // 确保有数据时才加载外部账户 if (accounts.length > 0) { loadExternalAccounts(accounts); } }, { fireImmediately: true } // 初始化时立刻执行一次 ); // 组件卸载时清理监听 return dispose; }; loadData(); }, [loadAccounts, loadExternalAccounts]); // 只依赖稳定的方法引用 return( <> {/* 你的组件内容 */} </> ) })
如果不想用reaction,也可以换一个稳定的依赖项,比如用accountStore.accountRegistry.size(数字类型,引用不会变化),但这种方式只能监听账户数量变化,无法监听内容更新,所以还是推荐用reaction。
备注:内容来源于stack exchange,提问作者Shury
相关产品推荐
相关产品推荐

