How to Update Route Component in React
Updating a route component in React typically involves triggering a re-render or updating the component’s state when the URL path, query parameters, or route states change. Because React Router reuses mounted components to optimize performance, simply changing the URL does not always cause a component to unmount and remount. This article explains how to successfully update and refresh route components using React Router hooks, dependency arrays, and key-based re-rendering.
Why Route Components Do Not Automatically Update
By default, React Router optimizes rendering by keeping the same
component instance alive if the destination route renders the same
component. For example, navigating from /users/1 to
/users/2 keeps the same UserProfile component
mounted. Because the component does not remount, its internal
useState hooks do not re-initialize, which can make the UI
appear frozen or outdated.
To resolve this, you must either listen to the route parameter changes or force React to destroy and recreate the component.
Method 1: Use useEffect with useParams (Recommended)
The most efficient way to update a route component is to use the
useParams hook combined with a useEffect hook.
By adding the route parameters to the useEffect dependency
array, you can trigger data fetching or state updates whenever the URL
changes.
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
function UserProfile() {
const { userId } = useParams();
const [userData, setUserData] = useState(null);
useEffect(() => {
// This effect runs every time userId changes
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then((data) => setUserData(data));
}, [userId]); // Dependency array ensures update on route change
if (!userData) return <p>Loading...</p>;
return (
<div>
<h1>{userData.name}</h1>
</div>
);
}
export default UserProfile;Method 2: Force Component Remount Using the key Prop
If your component has complex nested state that is difficult to reset
manually, you can force React to completely unmount and remount the
component. This is achieved by passing the current route path as a
key prop to the component. When the key
changes, React treats it as a brand-new component.
import React from 'react';
import { Routes, Route, useLocation } from 'react-router-dom';
import UserProfile from './UserProfile';
function App() {
const location = useLocation();
return (
<Routes>
<Route
path="/users/:userId"
element={<UserProfile key={location.pathname} />}
/>
</Routes>
);
}By using location.pathname as the key,
React will destroy the old UserProfile instance and mount a
fresh one with clean state every time the URL path changes.
Method 3: Listening to Query Parameters with useSearchParams
If your route updates depend on query strings (e.g.,
/search?query=react), you should use the
useSearchParams hook. Similar to useParams,
you can use the search parameters inside a useEffect
dependency array to update the component.
import React, { useState, useEffect } from 'react';
import { useSearchParams } from 'react-router-dom';
function SearchResults() {
const [searchParams] = useSearchParams();
const query = searchParams.get('query');
const [results, setResults] = useState([]);
useEffect(() => {
fetch(`/api/search?q=${query}`)
.then((res) => res.json())
.then((data) => setResults(data));
}, [query]); // Triggers update whenever query parameter changes
return (
<div>
<h2>Results for: {query}</h2>
{/* Render results here */}
</div>
);
}Method 4: Programmatic Navigation and State Updates
If you need to update a route component from within another part of
your application, use the useNavigate hook. You can pass
state payload via the navigation function, which can then be accessed
inside the destination component using useLocation.
// 1. Trigger the update from the source component
import { useNavigate } from 'react-router-dom';
function NavigationButton() {
const navigate = useNavigate();
const handleUpdate = () => {
navigate('/dashboard', { state: { updated: true, timestamp: Date.now() } });
};
return <button onClick={handleUpdate}>Go to Dashboard</button>;
}
// 2. Receive the update in the destination component
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
function Dashboard() {
const location = useLocation();
useEffect(() => {
if (location.state?.updated) {
// Perform actions based on the passed state
console.log('Dashboard state updated at:', location.state.timestamp);
}
}, [location.state]);
return <h1>Dashboard</h1>;
}