微前端架构中如何共享redux store?

问题描述 投票:0回答:4

我正在尝试按照微前端文章创建一个小项目来实现微前端架构。我正在为每个 MFE(微前端)创建多个存储库,并为该应用程序使用 Redux。我有以下架构:

  1. Frame
    - 一个集中式(主)存储库,负责基于路由渲染主要应用程序部分和 MFE(我正在使用
    connected-react-router
    )。它初始化 Redux 存储,并添加一个
    injectReducer
    函数来动态添加减速器,如 redux 文档中的 code splitting 中所述。该框架获取特定 MFE 的清单并呈现它。该框架还有一些用于身份验证目的的 redux 数据。
  2. MFEs
     - 这些是单独的功能应用程序,并按帧渲染。
现在我有一个问题,我想在我的 MFE 中使用

injectReducer

 函数来动态添加要存储的减速器。为此,我需要访问由框架创建的相同 
store
 实例。
正如
这个答案中提到的,理想的方法是导出创建的商店实例并使用它,但是我们如何在多个存储库中共享相同的商店实例?

reactjs redux react-redux micro-frontend
4个回答
14
投票
文章中有一条评论直接解决了这个问题:

如果您使用 redux,通常的方法是为整个应用程序建立一个单一的、全局的、共享的存储。然而,如果每个微前端都应该是自己独立的应用程序,那么每个微前端都有自己的 redux 存储是有意义的。 redux 文档甚至提到“将 Redux 应用程序隔离为更大应用程序中的组件”作为拥有多个商店的正当理由。

长话短说:不要分享你的 redux store

在微前端之间共享

任何东西

不再使它们成为独立的实体,并且违背了它的全部目的。现在它只是一个过度设计的庞然大物。只需将这些各自的存储库转换为整体存储库中定义明确的模块即可。仍然可以在统一的存储库中将职责划分到各自的孤岛中。只是需要更多纪律。


6
投票
eventListeners

CustomEvent
使用合成事件进行跨微前端通信,如下所示:

MF-1:

function Cart() { const [cartItems, addCartItems] = useState([]); const handleAddToCart = (event) => { addCartItems((currentItems) => [...currentItems, event.detail.item]); }; useEffect(() => { window.addEventListener('addToCart', handleAddToCart); return () => { window.removeEventListener('addToCart', handleAddToCart) } }, [handleAddToCart]); ... }

MF-2:

function itemLookUp() { const handleSubmit = (item) => { const customEvent = new CustomEvent('message', { detail: item }); window.dispatchEvent(customEvent) } ... }



3
投票

Github

https://github.com/microsoft/redux-micro-frontend
NPM

https://www.npmjs.com/package/redux-micro-frontend
文章

https://www.codezap.dev/post/state-management-ii-world-of-micro-frontends
也许能解决你的问题。


0
投票
这是你可以做到的


要使用模块联合在 MFE 之间共享,您可以使用带有公开路径的
ModuleFederationPlugin

从一个微前端 (MFE) 公开模块,如

'./remoteEntry.js'
。在主机 MFE 中,您可以使用
remotes
属性来使用此公开的模块,并指定其位置。最后,在主机 MFE 代码中导入共享模块,将其视为本地模块。

MF-1

/webpack.config.js

  plugins: [
    new ModuleFederationPlugin({
      name: "MF1",
      filename: "remoteEntry.js",
      remotes: {},
      exposes: {
        "./store": "./src/Redux/store.ts"
      }
    )]

MF-2

/webpack.config.js

  plugins: [
    new ModuleFederationPlugin({
      name: "MF2",
      filename: "remoteEntry.js",
      remotes: {
        MF1: "MF1@http://localhost:8080/remoteEntry.js",
      },
      exposes: {}
    )
  ]

你想用在哪里

import store from "MF1/store"; import React from "react"; import ReactDOM from "react-dom/client"; import { Provider } from "react-redux"; import { BrowserRouter as Router } from "react-router-dom"; import "./index.css"; const App = () => { console.log(store.getState(), "store"); return ( <Provider store={store}> <Router> // routes </Router> </Provider> ); }; const rootElement = document.getElementById("app"); if (!rootElement) throw new Error("Failed to find the root element"); const root = ReactDOM.createRoot(rootElement as HTMLElement); root.render(<App />);

	
© www.soinside.com 2019 - 2024. All rights reserved.