You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确编写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 08:39:08