I'm guessing that this is React 101 and has been asked a stack of times, but I can't see what I'm doing wrong.
Something is causing this code to get into an endless render loop and crash. I suspected the isLoggedIn flag, but am not so sure now. x.loginSlice.isLoggedIn is a straight boolean which is being set in reducer created by redux-toolkits createSlice helper. I assume that it's not violating any of the 'don't mutate state' rules.
My assumption is that this should only re-render when the equality check function on useSelector detects a change in the redux store. Perhaps something else is doing it? Location perhaps? It's still eluding me as to exactly how location is being passed in 'magically' via react-router.
Can anyone see what I'm doing wrong?
Thank you :-)
const PrivateRoute: React.FC<{ path: string, exact: boolean, children: ReactNode }> = ({children, ...rest}) => {
const isLoggedIn = useSelector((x: RootState) => x.loginSlice.isLoggedIn, (x, y) => x===y)
console.log('rendering privateRoute')
return (
<Route
{...rest}
render={({location}) =>
isLoggedIn ? (
children
) : (
<Redirect
to={{
pathname: "/page/Login",
state: {from: location}
}}
/>
)
}
/>
);
}
const App: React.FC = () => {
core.RunSetup()
const darkMode = useAppSelector(x => x.settings.darkMode)
return (
<IonApp className={darkMode === 'dark' ? 'dark-theme' : ''}>
<IonReactRouter>
<IonSplitPane contentId="main">
<IonRouterOutlet id="main">
<Route path="/" exact={true}>
<Redirect to="/page/Login"/>
</Route>
<Route path="/page/:name" exact={true}>
<Page/>
</Route>
<PrivateRoute path="/study/Counter" exact={true}>
<LearningPageWrapper page={TestPages.counter}/>
</PrivateRoute>
</IonRouterOutlet>
<Menu/>
</IonSplitPane>;
</IonReactRouter>
</IonApp>
);
}
;
export default App;
Additional Resources
After reading some comments I've deeper into the other pages which are getting rendered.
According to react profiler:
- 'Router' seems to be the highest level component which is participating in the ongoing render loop
- "why did this render" for the Router is "State Changed:Location". I'm looking into the router docs more around this.
I've shared some files here if it's of any help. Included are the console log during the crash, the exported react profiler data and all the tsx files. I've hacked around with the later to try and make them as minimalistic as possible.
Thanks again for your help! Despite the hair loss I get the feeling I'm learning something important here.
Edit 2: It seems to be working, but I'm not sure why.
If I remove state: {from: location}
the problem seems to go away. I'm not sure why, but notice that this privateRoute is still rendering even when navigating to page/login
which is supposed to be just a normal route.
I'm wondering if this might be the resason. Perhaps the changing pathName in the location object is changing the props passed to PrivateRoute
and causing it to go into an endless loop.
Anyway - for now I'm unstuck. I'll leave the question open in case anyone wants to explain it all to me.