技术

Antd组件事件循环问题

事件循环知识点的实际运用

在 Ant Design 的 Dropdown/Menu 里,

直接在菜单项的 onClick 回调里同步执行 history.push 会与 Dropdown 自身的事件流产生冲突——它内部会在同一个事件循环里去处理菜单的关闭、事件的冒泡/拦截等逻辑

如果在这当下就跳路由,Dropdown 的关闭动作可能还没来得及完成,就被页面切换打断了,导致跳转不生效或者出现一些奇怪的副作用。

所以可以添加setTimeout,让路由跳转逻辑进入下一个事件循环中,这样就能保证菜单先正常收起、事件先正常冒泡,再去切换路由,跳转就一定生效了。

   // 没有setTimeout的执行顺序:
   onClick() → history.push() → 页面跳转 → Antd清理逻辑被中断
   
   // 使用setTimeout(fn, 0)的执行顺序:
   onClick() → Antd完成内部处理 → 下一个事件循环 → history.push()

同理,如果是其他事件,也可以参考这种方法

项目中实际使用的场景,搜索以下代码

    const tranlateItem = {
      label: (
        <div className="cusButton">
          <IconFont type="icon-Refresh" style={{ fontSize: 24 }} />
          {f('多语言')}
        </div>
      ),
      key: 'translate',
      onClick: async () => {
        const currentLibrary = menuMap[`+${libraryId}`];
        const libraryName = currentLibrary?.name || '';

        const searchParams = new URLSearchParams({
          from: settingType,
          libraryType: libraryType,
          libraryName: libraryName,
          ownerType: ownerType,
          libraryId: libraryId,
          ...(ownerId && { ownerId: ownerId.toString() }),
          ...(params.wsid && { wsid: params.wsid })
        });
        //需要添加setTimeout,让antd组件逻辑先触发,再触发路由逻辑
        setTimeout(() => {
          history.push(`/defenseWeaver/translation/config?${searchParams.toString()}`);
        }, 0);
      },
    };