I have a UserContext
that is set when App
renders. App
retrieves the current user from a server, and then sets the user context in a provider.
So whenever I navigating to a link, App
renders, get's the current user from the server, and sets it. This allows all the children have access to the user.
Problem with <Redirect>
But I'm running into a problem when I use <Redirect>
.
If the user updates on the server, then App
needs to re-render in order to get the updated user object.
But on a redirect App
doesn't re-render which leads to an outdated user context until the user refreshes the page in order to re-render App
.
Example: Login to see your profile
In my code below I have a login button. When the user logs in the page redirects to their profile.
But even though the user is successfully logged in on the server, the user context hasn't updated. This is because redirect doesn't re-render App
.
Is there a way to get redirect to re-render app or some other solution?
Code
The relevant code is below.
The full code is available on the repo here. Download, run npm i
, npm start
, and then either select and play Compounded Server/React
in the debugger or run node currentUserServer/server.js
to start the server without the debugger tools.
Frontend
App.js
import React, { useEffect, useContext, useState } from "react";
import { UserContext } from "./contexts/UserContext";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Login from "./Login";
import Profile from "./Profile";
const currentUser = async () => {
const user = await fetch("/users/current", {}).then(async (res) => {
const userJson = await res.json();
return userJson;
});
return user;
};
export default function App() {
const [user, setUser] = useState(null);
useEffect(() => {
currentUser().then((user) => {
setUser(user);
});
}, []);
return (
<Router>
<div className="App">
<UserContext.Provider value={user}>
<Switch>
<Route path="/profile">
<Profile />
</Route>
<Route path="/">
<Login />
</Route>
</Switch>
</UserContext.Provider>
</div>
</Router>
);
}
Login.js
import React, { useContext, useState } from "react";
import { Redirect } from "react-router-dom";
import { UserContext } from "./contexts/UserContext";
export default function Login() {
const [next, setNext] = useState(false);
const currentUser = useContext(UserContext);
return (
<div>
Logged In:{" "}
{!currentUser || currentUser.message === "not logged in"
? "No One"
: currentUser.username}{" "}
<br></br>
<button
onClick={() => {
fetch("/login", { method: "POST" }).then((res) => {
if (res.status === 201) setNext(true);
});
}}
>
Login
</button>
<button
onClick={() => {
fetch("/logout", { method: "DELETE" });
}}
>
Logout
</button>
{next && <Redirect to="/profile" />}
</div>
);
}
Profile.js
import React, { useContext } from "react";
import { UserContext } from "./contexts/UserContext";
export default function Profile() {
const currentUser = useContext(UserContext);
return (
<div>
{currentUser && !currentUser.message
? "You're logged in and can edit your profile."
: "You're not logged in."}
</div>
);
}