Programmatic Navigation
Learning Goals
- Understand the use cases for programmatic navigation
- Use the
useHistory
hook to perform programmatic navigation - Use the
<Redirect>
component to perform programmatic navigation
Introduction
So far, we've used a couple components from React Router to allow our users to
navigate our React site: the NavLink
and Link
components. However, it would
also be useful to direct our users to another page without them needing to
click a link. For example:
- After logging in to the website, direct our user to the home page
- After logging out of the website, direct our user to the login page
- After creating a new item by filling out a form, direct our user to the detail page for that item
All of these actions require us to use programmatic navigation to change the browser URL, and show the user a new page in our application, without making the user click on a link.
Note: We have attached some files so you can see an example app in which programmatic navigation has been implemented. While the basic functionality is the same as what's described below, there are a number of differences for two reasons: 1) the code in the lesson is substantially pared down to make it easier to focus on the specific functionality being explained; and 2) the login/logout functionality is mocked in the example app so you don't need to run a server. We recommend that you read through the lesson first, focusing on understanding how programmatic navigation works. Once you've done that, feel free to start up the app and explore a (mostly) working example.
The useHistory Hook
To solve this problem, we can use another custom hook from React Router: the
useHistory
hook. Here's how it looks:
import { useHistory } from "react-router-dom";
function NavBar({ onLogout }) {
const history = useHistory();
function handleClick() {
// logout the user
onLogout();
// then navigate them to the login page
history.push("/login");
}
return (
<nav>
<button onClick={handleClick}>Logout</button>
</nav>
);
}
By calling history.push()
, we can effectively navigate the user to a new page
in response to any event in our application, not just when the user clicks a
link!
For another example, here's how you could use history.push()
to redirect the
user after logging in:
function Login({ onLogin }) {
const [formData, setFormData] = useState({
username: "",
password: "",
});
function handleChange(e) {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
}
function handleSubmit(e) {
e.preventDefault();
fetch("http://localhost:3001/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(formData),
})
.then((r) => r.json())
.then((user) => {
onLogin(user);
// after logging the user in, redirect to the home page!
history.push("/home");
});
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
name="username"
value={formData.username}
onChange={handleChange}
/>
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
<button type="submit">Login</button>
</form>
);
}
The Redirect Component
In addition to the useHistory
hook, React Router also provides a special
component for redirecting users to a new location: the Redirect
component.
This component is particularly useful in cases where you need to handle some
conditional rendering. For example:
function Home({ isSignedIn }) {
// if the user isn't signed in, redirect them to the login page
if (!isSignedIn) return <Redirect to="/login" />;
// otherwise, return the home page
return (
<div>
<h1>Home!</h1>
</div>
);
}
Conclusion
React Router gives us full control over how to navigate users around our
website. In general, the preferred approach is to use the <Link>
and
<NavLink>
components to let users perform navigation by clicking links.
However, there are certain scenarios when we want to navigate a user to a new
page after they perform some other type of action, like submitting a form or
logging out. React Router provides two tools to help us with these scenarios:
the useHistory
hook and the <Redirect>
component.