Skip to content

Commit cb3405f

Browse files
committed
fix(bridge-react): hoist BridgeWrapper to prevent component recreation
1 parent a12226f commit cb3405f

File tree

4 files changed

+89
-38
lines changed

4 files changed

+89
-38
lines changed

.changeset/eight-mirrors-drum.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'remote6': patch
3+
'@module-federation/bridge-react': patch
4+
---
5+
6+
fix(bridge-react): hoist BridgeWrapper to prevent component recreation

apps/router-demo/router-host-2000/src/App.tsx

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, {
33
useEffect,
44
ForwardRefExoticComponent,
55
Suspense,
6+
useState,
67
} from 'react';
78
import { Route, Routes, useLocation } from 'react-router-dom';
89
import {
@@ -284,16 +285,26 @@ const App = () => {
284285
/>
285286
<Route
286287
path="/remote6/*"
287-
Component={() => (
288-
<Remote6App
289-
rootOptions={{
290-
identifierPrefix: 'remote6-instance-',
291-
onRecoverableError: (error: Error) => {
292-
console.error('[Host] Remote6 recoverable error:', error);
293-
},
294-
}}
295-
/>
296-
)}
288+
Component={() => {
289+
const [counter, setCounter] = useState(0);
290+
291+
return (
292+
<>
293+
<button onClick={() => setCounter(counter + 1)}>
294+
Increment
295+
</button>
296+
<Remote6App
297+
outerCounter={counter}
298+
rootOptions={{
299+
identifierPrefix: 'remote6-instance-',
300+
onRecoverableError: (error: Error) => {
301+
console.error('[Host] Remote6 recoverable error:', error);
302+
},
303+
}}
304+
/>
305+
</>
306+
);
307+
}}
297308
/>
298309
</Routes>
299310
</div>

apps/router-demo/router-remote6-2006/src/App.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from 'react-router';
99
import './App.css';
1010
import styled from '@emotion/styled';
11+
import { useState } from 'react';
1112

1213
const HomeDiv = styled.div`
1314
color: purple;
@@ -48,16 +49,21 @@ function Home() {
4849
}
4950

5051
function Detail() {
52+
const [counter, setCounter] = useState(0);
5153
return (
5254
<>
5355
<h2>Remote6 detail page</h2>
5456
<div>hello remote6 detail page with React Router v7</div>
5557
<div>🚀 Enhanced routing with better performance and DX</div>
56-
<Image
57-
width={200}
58-
src="https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp"
59-
alt="Sample image"
60-
/>
58+
<div style={{ fontSize: 40 }}>Inner Counter: {counter}</div>
59+
<button onClick={() => setCounter(counter + 1)}>Increment</button>
60+
<div>
61+
<Image
62+
width={200}
63+
src="https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp"
64+
alt="Sample image"
65+
/>
66+
</div>
6167
</>
6268
);
6369
}
@@ -171,7 +177,11 @@ const router = createBrowserRouter([
171177
},
172178
]);
173179

174-
const App = (info?: { basename?: string; initialEntries?: Array<string> }) => {
180+
const App = (info?: {
181+
outerCounter: number;
182+
basename?: string;
183+
initialEntries?: Array<string>;
184+
}) => {
175185
// React Router v7 supports more advanced routing features
176186
// For now, we'll use the basic router configuration
177187
// In a real app, you might want to handle basename and initialEntries
@@ -180,6 +190,7 @@ const App = (info?: { basename?: string; initialEntries?: Array<string> }) => {
180190

181191
return (
182192
<div className="remote6-app">
193+
<div style={{ fontSize: 40 }}>Outer Counter: {info?.outerCounter}</div>
183194
<RouterProvider router={router} />
184195
</div>
185196
);

packages/bridge/bridge-react/src/provider/versions/bridge-base.tsx

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,38 @@ export function createBaseBridgeComponent<T>({
4343
);
4444
};
4545

46+
const DefaultFallback = ({ error }: FallbackProps) => (
47+
<div role="alert">
48+
<p>Something went wrong:</p>
49+
<pre style={{ color: 'red' }}>{error.message}</pre>
50+
</div>
51+
);
52+
53+
const BridgeWrapper = ({
54+
basename,
55+
moduleName,
56+
memoryRoute,
57+
propsInfo,
58+
fallback,
59+
}: {
60+
basename?: string;
61+
moduleName?: string;
62+
memoryRoute?: any;
63+
propsInfo: T;
64+
fallback?: React.ComponentType<FallbackProps>;
65+
}) => (
66+
<ErrorBoundary FallbackComponent={fallback || DefaultFallback}>
67+
<RawComponent
68+
appInfo={{
69+
moduleName,
70+
basename,
71+
memoryRoute,
72+
}}
73+
propsInfo={propsInfo}
74+
/>
75+
</ErrorBoundary>
76+
);
77+
4678
return {
4779
async render(info: RenderParams) {
4880
LoggerInstance.debug(`createBridgeComponent render Info`, info);
@@ -64,29 +96,20 @@ export function createBaseBridgeComponent<T>({
6496
const beforeBridgeRenderRes =
6597
instance?.bridgeHook?.lifecycle?.beforeBridgeRender?.emit(info) || {};
6698

67-
const BridgeWrapper = ({ basename }: { basename?: string }) => (
68-
<ErrorBoundary
69-
FallbackComponent={fallback as React.ComponentType<FallbackProps>}
70-
>
71-
<RawComponent
72-
appInfo={{
73-
moduleName,
74-
basename,
75-
memoryRoute,
76-
}}
77-
propsInfo={
78-
{
79-
...propsInfo,
80-
basename,
81-
...(beforeBridgeRenderRes as any)?.extraProps,
82-
} as T
83-
}
84-
/>
85-
</ErrorBoundary>
86-
);
87-
8899
const rootComponentWithErrorBoundary = (
89-
<BridgeWrapper basename={basename} />
100+
<BridgeWrapper
101+
basename={basename}
102+
moduleName={moduleName}
103+
memoryRoute={memoryRoute}
104+
fallback={fallback as React.ComponentType<FallbackProps>}
105+
propsInfo={
106+
{
107+
...propsInfo,
108+
basename,
109+
...(beforeBridgeRenderRes as any)?.extraProps,
110+
} as T
111+
}
112+
/>
90113
);
91114

92115
if (bridgeInfo.render) {

0 commit comments

Comments
 (0)