I am a react newbie using react-router like this:
index.tsx
const router = createBrowserRouter([
{
path: '/',
element: <Root />, // Uses <Outlet />.
children: [
{
path: '/login/callback',
element: <Login />,
},
{
path: '/dashboard',
element: <Dash />,
},
],
},
]);
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
I need to add a new component to hold user information (whether there's a user logged in, and if so, their name and token).
Where would I place it and how would I use it given that:
<Login />
, where the user will be set.Root
component. If there is no current user, a login button will be rendered instead.interface User {...}
function UserInfo(): JSX.Element {
const [user, setUser] = useState<User>({});
...
}
and have setUser
be passed as a prop to <Login />
, while the <UserInfo />
component would be used inside <Root />
(eg to provide the user name).
I am wondering how I could accomplish that in a good way.
On the one hand, I think I should lift state up and move the useState
hook outside of UserInfo
and into index.tsx
.
I took a look at the react-router docs but I couldn't find a matching example.
I am not sure using a context would help here, but maybe could be placed inside Root
:
<Container sx={{ mt: 4, mb: 4 }}>
<UserInfo>
<div id="detail">
<Outlet />
</div>
</UserInfo>
</Container>
From what I can understand of your question you are wanting to store and expose out to various routed content a user
state. If any component other than UserInfo
needs this data then lifting state up is about the only viable solution. Promoting it to the Root
component makes sense since it can reference it and expose it out to it's sub-ReactTree via the Outlet
context it is already rendering/providing. Descendent components would use the useOutletContext
hook to access the provided value.
Example:
const Root = () => {
const [user, setUser] = useState<User>({});
...
return (
<Container sx={{ mt: 4, mb: 4 }}>
<UserInfo user={user} />
<div id="detail">
<Outlet context={{ user, setUser, /* anything else */ }} />
</div>
</Container>
);
};
interface UserContext {
user: User;
setUser: React.Dispatch<React.SetStateAction<User>>;
// ...anything else
}
const Login = () => {
...
const { setUser } = useOutletContext<UserContext>();
...
};