BlogReactJS

How to remount your ReactJS component on URL or prop change

Written by Codemzy on July 24th, 2023

You can force ReactJS to remount a component using the `key` prop, resetting state, values, and data. The `key` prop can help you remount components on route URL and prop changes, and here's how I use this magical prop!

If you are using React Router, you might use the same component on multiple routes. For example, let's say you have an e-book app. Your React app lets people read a book. And your router is structured like this:

<Route path="books/:bookId" element={<BookInfo />} />
<Route path="books/:bookId/page/:pageId" element={<BookPage />} />

When your users move from /books/abc/page/1 to /books/abc/page/2, the BookPage component stays rendered. Just the props change. In this case, the pageId prop.

And that prop change can trigger a whole bunch of things. Like fetching page 2 from the server or whatever.

Usually, there's no problem.

But sometimes you might run into issues.

Let's imagine the user can highlight important lines from the page, and add notes. Each time they add a note or highlight part of the page, you check for changes, and autosave any changes to the server.

You can useEffect to reset state etc on a prop change, which most of the time is what I would do.

// clear state when page changes
React.useEffect(() => {
  return () => {
    setNotes(false); // clear notes
    setHighlights([]); // clear highlights
  }
}, [pageId]);

But in a few situations, when I had data stored in state, memo and refs, I found it hard to reset all of these data points at the same time. So there would be a brief moment where the pageId would be new, but the old state would still be stored.

And if you have things like autosave triggering off comparing these different data sources, well - navigating between routes can get a little buggy.

Forcing the component to remount means you start fresh with each route change (of turn of the page in this case!).

And it's really easy to do.

Force a remount in React Router

To force a remount in React Router, you can use the key prop. And that's not a prop that is specific to React Router - it's a special prop from ReactJS itself.

But you will mostly use the key prop to keep lists in order in ReactJS.

So if you have a setup like this:

<Route path="photos/team" element={<Photos type="team" />} />
<Route path="photos/projects" element={<Photos type="projects" />} />

You can give your components a unique key prop, and when that prop changes, the component will remount.

<Route path="photos/team" element={<Photos key="team" type="team" />} />
<Route path="photos/projects" element={<Photos key="projects" type="projects" />} />

The key prop is special, React uses it internally, so your component won't actually receive it. You still need to pass the type prop to get that info into the component.

I've not found anything in the React docs specifically for this use case of the key prop. But Kent C. Dodds shows a similar case for handling form state. And Kent knows a thing or two about React.

The exception to this is the key prop. This allows you to return the exact same element type, but force React to unmount the previous instance, and mount a new one. This means that all state that had existed in the component at the time is completely removed and the component is "reinitialized" for all intents and purposes.

- Kent C. Dodds Understanding React's key prop

So, we can use the key prop to force a remount in React Router.

Is this a hack? Possibly. Does it work? Yes.

Remount component on URL change

But what about our route parameters?

You might remember this route from the first example.

<Route path="books/:bookId/page/:pageId" element={<BookPage />} />

This won't work.

<Route path="books/:bookId/page/:pageId" element={<BookPage key=":pageId" />} />

Every page will just have the key ":pageId". And since every page has the same key, that's no remount for you or me. Damn! I thought this was going to be easy.

This won't work either.

<Route path="books/:bookId/page/:pageId" element={<BookPage key={:pageId} />} />

No, no, capital NO.

I use a parent component to make this happen.

import { useParams } from "react-router-dom";
import BookPage from './Page';

// reloads the page component on pageId param change
function PageReload() {
  let { pageId } = useParams();
  
  return (
    <BookPage key={pageId} />
  );
};

export default PageReload;

And then in the Route:

<Route path="books/:bookId/page/:pageId" element={<PageReload />} />

Now whenever the pageId changes, the PageReload component sends the key to the Page component, and ✨TA-DA✨, we get a reload.

But that's pretty hard-coded. If you need this in multiple routes with different components, here's a higher-order component to make things more reusable:

import { useParams } from "react-router-dom";

// hoc to reload a component on param change
function withParamReload(WrappedComponent, paramName) {
  let params = useParams();
  
  return (
    <WrappedComponent key={params[paramName]} />
  );
};

export default withParamReload;

Now we can add this higher-order component to any component we need reloading on a route param change, for example, our BookPage component:

import withParamReload from './withParamReload'

function BookPage(props) {
  //...
};

export default withParamReload(BookPage, "pageId");

And the router can go back to:

<Route path="books/:bookId/page/:pageId" element={<BookPage />} />

Remount component on prop change

It might not be a URL change or react-router route that triggers your need for a remount. It might be a prop change.

But the solution is the same. Use the key prop!

import ChildComponent from './ChildComponent'

function ParentComponent(props) {
  
  // ...
  
  return (
    <div>
      <h1>Amazing App</h1>
      <ChildComponent key={id} id={id} title="Amazing" description="Super cool." />
    </div>
  )
};

Now ChildComponent will remount whenever the id prop changes.


Only re-render when you need to! Don't start using the key prop everywhere because rerendering too much will hurt the performance of your React app. Most of the time, React will take care of rendering and you don't need to force it. Use with care!