Router unmounts Routes on parent re-render
orangecoloured opened this issue · comments
I have this state in my root component which is passed then as a context value
export const GlobalStateContext = createContext({
stateGlobal: stateGlobalInitial,
setStateGlobal: (_state: Partial<AppStateProps>) => { return },
})
const [stateGlobal, setStateGlobal] = useReducer<AppStateProps, Partial<AppStateProps>>(
(state, newState) => ({ ...state, ...newState }),
stateGlobalInitial,
)
const contextValue = useMemo(
() => ({ stateGlobal, setStateGlobal }),
[stateGlobal]
)
<GlobalStateContext.Provider value={contextValue}>
<Menu />
</GlobalStateContext.Provider>
On each update components inside the <Router>
get re-mounted.
Components sitting outside of the <Router>
act normal.
const A: FunctionalComponent = () => {
useEffect(() => {
console.log('MOUNTED')
return (): void => {
console.log('UNMOUNTED')
}
}, [])
return <div>yo</div>
}
<div id="root">
<GlobalStateContext.Provider value={contextValue}>
<Menu />
</GlobalStateContext.Provider>
<div>
<Router>
<Route path="/" component={A} />
</Router>
</div>
</div>
So in the above example on each contextValue
update you get UNMOUNTED
in the console.
Is there a way to fix this behaviour? Or am I doing something wrong?
It seems like you're creating a new A
function on every render. Components should never be created within another component or render method, since that breaks referential equality and causes them to remount on every update.
Does not work | Works |
---|---|
function App() {
const A: FunctionalComponent = () => {
useEffect(() => {
console.log('MOUNTED')
return (): void => {
console.log('UNMOUNTED')
}
}, [])
return <div>yo</div>
}
return (
<div id="root">
<GlobalStateContext.Provider value={contextValue}>
<Menu />
</GlobalStateContext.Provider>
<div>
<Router>
<Route path="/" component={A} />
</Router>
</div>
</div>
);
} |
const A: FunctionalComponent = () => {
useEffect(() => {
console.log('MOUNTED')
return (): void => {
console.log('UNMOUNTED')
}
}, [])
return <div>yo</div>
}
function App() {
return (
<div id="root">
<GlobalStateContext.Provider value={contextValue}>
<Menu />
</GlobalStateContext.Provider>
<div>
<Router>
<Route path="/" component={A} />
</Router>
</div>
</div>
);
} |
@developit I think you are right. I've already updated my code to avoid this re-mount, but probably the previous logic was re-creating the component. Thank you.