I've created dynamic routing on my site, which changes when a user login successfully. The fact of logging I keep in global state, which observers by mobx. When the user login successfully, routes changes too, and it works correctly, but in the console, there is the next problem: Error
Error in text variant:
react-dom.development.js:67 Warning: React has detected a change in the order of Hooks called by AppRouter. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks
Previous render Next render
- useState useState
- useState useState
- useRef useRef
- useDebugValue useDebugValue
- useEffect useEffect
- useContext useContext
- undefined useContext ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There is a screenshot of the route's component: Routes component Routes component code:
import { observer } from "mobx-react-lite";
import { useContext } from "react";
import { Navigate, Route, Routes } from "react-router-dom";
import { Context } from "../..";
import { adminPaths, guestPaths, userPaths } from "./paths";
const AppRouter = () => {
const { userStore } = useContext(Context);
return (
<Routes>
<Route path='/*' element={<Navigate to='/' />} />
{
userStore.isAuth && userPaths.map(({ path, component }) =>
<Route path={path} element={component()} />)
}
{
userStore.isAuth && adminPaths.map(({ path, component }) =>
<Route path={path} element={component()} />)
}
{
guestPaths.map(({ path, component }) => <Route path={path} element={component()} />)
}
</Routes>
)
}
export default observer(AppRouter);
When I remove the observer in this component, error disappeared, but routes don't update after login.
Routes configuration code: Routes configuration Routes configuration code:
import AdminCabinet from "../../pages/admin-cabinet/admin-cabinet";
import HomePage from "../../pages/home-page/home-page";
import UserCabinet from "../../pages/user-cabinet/user-cabinet";
export const guestPaths = [
{
name: 'Home',
path: '/',
component: HomePage
}
];
export const userPaths = [
{
name: 'Personal cabinet',
path: '/personalCabinet',
component: UserCabinet
}
];
export const adminPaths = [
{
name: 'Admin cabinet',
path: '/adminCabinet',
component: AdminCabinet
}
];
I would be grateful if someone helps me with this problem.
CodePudding user response:
Issue
The only overt issue I see with your code is that you are directly invoking your React components instead of rendering them as JSX for React to handle and manage the component lifecycle of.
Example:
import UserCabinet from "../../pages/user-cabinet/user-cabinet";
const userPaths = [
{
name: "Personal cabinet",
path: "/personalCabinet",
component: UserCabinet,
},
];
...
const AppRouter = () => {
const { userStore } = useContext(Context);
return (
<Routes>
...
{userStore.isAuth && userPaths.map(({ path, component }) => (
<Route path={path} element={component()} /> // <-- invoking component
))}
...
</Routes>
);
};
Solution
The element
prop should receive JSX. When destructuring component
rename it to Component
so it has a valid React component name and render as JSX. Don't forget to use a valid React key for the mapped routes.
Example:
import UserCabinet from "../../pages/user-cabinet/user-cabinet";
const userPaths = [
{
name: "Personal cabinet",
path: "/personalCabinet",
component: UserCabinet,
},
];
...
const AppRouter = () => {
const { userStore } = useContext(Context);
return (
<Routes>
...
{userStore.isAuth && userPaths.map(({ path, component: Component }) => (
<Route
key={path}
path={path}
element={<Component />} // <-- pass as JSX
/>
))}
...
</Routes>
);
};