ant-design-pro icon indicating copy to clipboard operation
ant-design-pro copied to clipboard

🧐[问题]ant-design-pro使用umijs/plugin-qiankun useModel 父子应用通信无法在刷新应用时保持最新的全局数据

Open hanxzi opened this issue 3 years ago • 1 comments

🧐 问题描述

  1. 最新的v5 pro 项目为微前端主应用,使用useModel通信。父子应用通信无法在刷新应用时保持最新的全局数据。疑惑怎么样setQiankunGlobalState可以保持在登录后刷新页面不会变成初始化状态的state。
  2. src/pages/Welcome.tsx 使用 const { qiankunGlobalState, setQiankunGlobalState } = useModel('@@qiankunStateFromMaster'); 报错 TypeError: Cannot read property 'qiankunGlobalState' of undefined; 项目地址 https://github.com/hanxzi/micro-app-umi-demo

复现方式

打开主应用http://localhost:8000/user/login 用户名:admin 密码:ant.design登录 在src/app.ts 初始化全局qiankunGlobalState值{"slogan":"Hello initialState Main App"}。src/pages/user/Login/index.tsx 登录操作修改全局 qiankunGlobalState 为{"slogan":"Hello Login Qiankun"},点击左侧菜单子应用sub-app-umi 正常输出{"slogan":"Hello Login Qiankun"}。手动刷新http://localhost:8000/sub-app-umi路由 子应用sub-app-umi 输出变成初始化状态{"slogan":"Hello initialState Main App"} 。 点击修改全局 state设置新的state,刷新后也回到最初状态值。

💻 示例代码

//main-app/src/app.ts
export const useQiankunStateForSlave =  () => {
  const [qiankunGlobalState, setQiankunGlobalState] = useState({"slogan":"Hello initialState  Main App"});
  return {
    qiankunGlobalState,
    setQiankunGlobalState,
  };
};
}
//main-app/src/pages/user/Login/index.tsx
const { initialState, setInitialState } = useModel('@@initialState');
  const { setQiankunGlobalState } = useModel('@@qiankunStateForSlave');
  const intl = useIntl();

  const fetchUserInfo = async () => {
    const userInfo = await initialState?.fetchUserInfo?.();
    if (userInfo) {
      await setInitialState((s) => ({
        ...s,
        currentUser: userInfo,
      }));
      setQiankunGlobalState({"slogan":"Hello Login Qiankun"})
    }
  };
}
}
//main-app/src/pages/Welcome.tsx
const { qiankunGlobalState, setQiankunGlobalState } = useModel('@@qiankunStateFromMaster');
return (
  <PageContainer>
    <Card>
      <div>{JSON.stringify(qiankunGlobalState)}</div>
    </Card>
  </PageContainer>
  }
//sub-app-umi/src/pages/index.tsx
export default function IndexPage() {
const { qiankunGlobalState, setQiankunGlobalState } = useModel('@@qiankunStateFromMaster');
return (
  <div>
    <div>{JSON.stringify(qiankunGlobalState)}</div>
    <button onClick={() => {setQiankunGlobalState({"slogan":"Hello Change App Umi"}) }}>修改全局 state</button>
  </div>
);
}

🚑 其他信息

WX20210722-150355@2x WX20210722-150309@2x WX20210722-150238@2x WX20210722-162034@2x

hanxzi avatar Jul 22 '21 08:07 hanxzi

@hanxzi 老哥,有解决吗?

niexq avatar Aug 07 '21 12:08 niexq

TAutomatically replying with ChatGPT can be attempted, but it cannot be guaranteed to be completely accurate and may not fully address all issues. Please feel free to reply if you have any further questions or concerns. 此回复基于 ChatGPT 自动生成,可以尝试下方案,官方人员会在一定时间后继续继续处理。

你好 @hanxzi,感谢你的提问。根据你提供的信息,我初步判断是因为在子应用 sub-app-umi 中,由于是在刷新页面时重新加载,导致全局状态值被重新初始化。

对于这个问题,解决方案是在子应用中监听 qiankun 的应用生命周期函数 mountunmount,分别在这两个生命周期函数中通过setQiankunGlobalState()传递key-value值到主应用中。主应用有更新时,子应用可以通过qiankun生命周期函数 update中取回 setGlobalState,执行更新state。

同时,建议你可以查阅 @umijs/plugin-qiankun 的官方文档以及Github上的 issues,学习更多关于这个问题的解决方案。

代码示例如下:

// 在父应用中注册生命周期钩子函数并暴露给子应用
export const qiankun = {
  // ...
  async mount(props) {
    // ...
    props.setGlobalState({
      myGlobalState: { ... },
      // other properties
    });
  },
  async unmount(props) {
    // ...
    props.setGlobalState({}); // clear global state
  },
  async update(props) {
    // ...
    const { setGlobalState } = props;
    setGlobalState({
      myGlobalState: { ... },
      // other properties
    });
  },
};

// 在子应用中获取和更新全局状态
const { myGlobalState, setMyGlobalState } = useModel('@@qiankunStateForSlave');

useEffect(() => {
  props.onGlobalStateChange((initialGlobalState, prevGlobalState) => {
    // 每次接收到全局状态的更新都触发此处的回调,更新本地 state
    setMyGlobalState(initialGlobalState.myGlobalState);
  });
});

// 修改全局状态
setMyGlobalState({
  ...myGlobalState,
  myProp: myNewPropValue,
});

希望以上方案对你有所帮助。感谢你的使用!

chenshuai2144 avatar Mar 07 '23 08:03 chenshuai2144