2

UPDATE: How this question differs from the duplicate?

Here we have the same component being rendered by 2 different routes. In the other question, OP wants to know how to re-mount a component being rendered by the same single route over and over, just by changing the route params.

Link: Component does not remount when route parameters change


I have the following situation on a ProductSearch component.

It might be rendered by two different <Route>'s:

They both display ProductSearch page with filters to corresponding products.

<Route exact path='/category/:slug' component={ProductSearchContainer}/>
<Route exact path='/search/:slug' component={ProductSearchContainer}/>

The 1st one happens when you click on a product category menu:

  • So the results are already inside a specific category.
  • Then it displays filters that are specific for that product category.

The 2nd one happens when you search products using the SearchBar with some text.

  • You're not inside a category yet, so it only displays generic filters like Price, Brand, Rating, etc...

The problem is that if you change straight from one route to the other, the component will simply re-render. And I would it like better for it to remount, because then I would get a fresh start on my selected filters active state and productList, etc...

For example, this would happen in the following scenario:

  1. The user clicks on category nav button Phones
  2. The ProductSearch component gets rendered for the Phones category
  3. The user filters a bunch of stuff and decides to do a text search and start from scratch
  4. The user searches for some random text
  5. The ProductSearch gets re-rendered (with the 2nd route) but all the filtered states will remain the same if I don't reset them.

Note the URL change in the GIF below:

enter image description here

QUESTION:

Is there a way to make sure my component will get remounted if it changes to a different route in this case?

Example on CodeSandbox:

https://codesandbox.io/s/react-routerremountonroutechangeso-881m3


Full Code: index.js

(in case the CodeSandbox link is not available anymore)

import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Link, Switch, Route } from "react-router-dom";

import "./styles.css";

function App() {
  return (
    <Router>
      <AllRoutes />
    </Router>
  );
}

function AllRoutes(props) {
  return (
    <Switch>
      <Route exact path="/" component={Home} />
      <Route exact path="/category/:slug" component={ProductSearch} />
      <Route exact path="/search/:slug" component={ProductSearch} />
    </Switch>
  );
}

function Home(props) {
  return (
    <div>
      <div>I am Home</div>
      <div>
        <Link to="/category/phones">Phones</Link>
      </div>
    </div>
  );
}

function ProductSearch(props) {
  console.log("Rendering ProductSearch...");

  useEffect(() => {
    console.log("ProductSearch mounted...");
    return () => console.log("ProductSearch unmounted...");
  }, []);

  // useEffect(() => {
  //   console.log('Inside useEffect for slug...');
  //   console.log(props.match.params.slug);
  // },[props.match.params.slug]);

  return (
    <div>
      <div>I am ProductSearch</div>
      <div>
        <Link to="/">Home</Link>
      </div>
      <div>
        <Link to="/search/phoneModelXYZ">Search for Phone XYZ</Link>
      </div>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

cbdeveloper
  • 27,898
  • 37
  • 155
  • 336
  • 2
    Possible duplicate of [Component does not remount when route parameters change](https://stackoverflow.com/questions/32261441/component-does-not-remount-when-route-parameters-change) - one of the answers there shows a way to force re-mount, the others explain why it's better not to. – Sergiu Paraschiv Jul 03 '19 at 14:57

1 Answers1

1

So here's what I've ended up doing:

By giving a key to the rendered component in the Route you can make it re-mount instead of re-render.

<Route exact path='/category/:slug' render={(routeProps)=>
  <ProductSearch {...routeProps} key={routeProps.match.params.slug}/>}
/>
<Route exact path='/search/:slug' render={(routeProps)=>
  <ProductSearch {...routeProps} key={'search'}/>}
/>

Now I get the following result:

enter image description here

cbdeveloper
  • 27,898
  • 37
  • 155
  • 336