Open m-s4n opened 3 years ago
@m-s4n Hey, I tried doing the same and couldn't find any re-renders. I checked it by adding a simple counter near bootstrap. How were you able to deduce that it's getting rendered more than once?
let counter = 0;
// Mount function to start up the app
const mount = (el, { onSignIn, onNavigate, defaultHistory, initialPath }) => {
console.log('AUth getting mounted ', ++counter);
https://i.stack.imgur.com/t2iei.png
If you write the outputs from the logs in the component, you will get the log as follows if you switch between different micro frontends through the link tags each time.
not into bootstrap
Got it. Something like this would work -
have a containerDiv ref near the switch [or which ever container div you intend the sub-app to load into]
export default () => {
const [isSignedIn, setIsSignedIn] = useState(false);
const containerDivRef = useRef(null);
useEffect(() => {
if (isSignedIn) {
history.push('/dashboard');
}
}, [isSignedIn]);
return (
<Router history={history}>
<StylesProvider generateClassName={generateClassName}>
<div>
<Header
onSignOut={() => setIsSignedIn(false)}
isSignedIn={isSignedIn}
/>
<div ref={containerDivRef}>
<Suspense fallback={<Progress />}>
<Switch>
<Route path="/auth">
<AuthLazy containerDivRef={containerDivRef} onSignIn={() => setIsSignedIn(true)} />
</Route>
and use ReactDOM to properly flush out the sub-app [I am sure we will have similar API in other frameworks/libs like ng or vue]
export default ({ onSignIn, containerDivRef }) => {
const history = useHistory();
useEffect(() => {
let authAppRoot = document.querySelector('#auth-app-root');
if (!authAppRoot) {
authAppRoot = document.createElement('div');
authAppRoot.id = '#auth-app-root';
containerDivRef.current.appendChild(authAppRoot);
}
const { onParentNavigate } = mount(authAppRoot, {
initialPath: history.location.pathname,
onNavigate: ({ pathname: nextPathname }) => {
const { pathname } = history.location;
if (pathname !== nextPathname) {
history.push(nextPathname);
}
},
onSignIn,
});
history.listen(onParentNavigate);
return () => ReactDOM.unmountComponentAtNode(authAppRoot);
}, []);
return null;
};
@StephenGrider it would be great if you can take a look at this problem
Cleaner solution -
function useReactMicroFEApp ({
history,
mount,
additional
}) {
const mountDivRef = useRef(null);
const thisRef = useRef({ mountDiv: null }); // as ref on an element looses the reference to it, once its removed from DOM but reactDOM would still be attached to the same
useEffect(() => {
thisRef.current.mountDiv = mountDivRef.current;
const { onParentNavigate } = mount(mountDivRef.current, {
initialPath: history.location.pathname,
onNavigate: ({ pathname: nextPathname }) => {
const { pathname } = history.location;
if (pathname !== nextPathname) {
history.push(nextPathname);
}
},
...additional,
});
history.listen(onParentNavigate);
return () => {
ReactDOM.unmountComponentAtNode(thisRef.current.mountDiv);
};
}, []);
return ({
mountDivRef,
})
}
export default ({ onSignIn }) => {
const history = useHistory();
const {mountDivRef} = useReactMicroFEApp({
history,
mount,
additional: {
onSignIn,
}
})
return <div ref={mountDivRef} />;
};
Similar to this, we should be able to create hooks for other libraries [ng, vue, etc.] and have proper cleanup mechanisms according to their implementations.
Thanks @KartheekJavvaji I tried it and it works fine.
import { mount } from "auth/AuthApp";
import React, { useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import { useHistory } from "react-router-dom";
function useReactMicroFEApp({ onSignIn }) {
const history = useHistory();
const mountDivRef = useRef(null);
const thisRef = useRef({ mountDiv: null });
useEffect(() => {
thisRef.current.mountDiv = mountDivRef.current;
const { onParentNavigate } = mount(mountDivRef.current, {
initialPath: history.location.pathname,
onNavigate: ({ pathname: nextPathname }) => {
const { pathname } = history.location;
if (pathname !== nextPathname) {
history.push(nextPathname);
}
},
onSignIn,
});
history.listen(onParentNavigate);
return () => {
/* --- clear up --- */
ReactDOM.unmountComponentAtNode(thisRef.current.mountDiv);
};
}, []);
return {
mountDivRef,
};
}
const AuthApp = ({ onSignIn }) => {
const { mountDivRef } = useReactMicroFEApp({
onSignIn,
});
return <div ref={mountDivRef} />;
};
export default AuthApp;
I wrote to you from udemy, there is a fatal error. 1)git clone https://github.com/StephenGrider/mfe.git
2) run mfe
3) switch between http://localhost:8080 and http://localhost:8080/auth/signin 4 or 5 times (soft switch)
4) components are rendering more than one
unfortunately: my big projects render many times and the performance decreases a lot over time.