Re-render same component on url change in react
Asked Answered
S

8

11

I have a route which takes an id and renders the same component for every id, for example : <Route path='/:code' component={Card}/>

Now the in the Link tag I pass in an id to the component.Now the Card component fetches additional detail based on the id passed. But the problem is it renders only for one id and is not updating if I click back and goto the next id. I searched and found out that componentsWillReceiveProps can be used but during recent versions of React it has been deprecated. So how to do this?

Stevie answered 10/9, 2018 at 6:41 Comment(2)
possible duplicate of #38915566Primero
I am not sure if this will help but maybe try with react-router V6 (reactrouter.com/en/main/start/…) or try to recreate component every time Router is re-rendered (component={Card} vs component={() => <Card />})Ormandy
S
-3

In React Router v4 Adding a Switch tag after the Router tag fixes the problem Like this

<Router>
  <Switch>
  </Switch>
</Router>
Stevie answered 24/1, 2019 at 8:0 Comment(2)
What does this mean?Forsook
This doesn't make any senseArv
E
29

Putting current location as key on component solves problem.

<Route path='/:code' component={(props) => <Card {...props} key={window.location.pathname}/>}/>
Expository answered 27/3, 2020 at 16:35 Comment(0)
A
14

I just ran into a similar problem. I think you are conflating updating/rerendering and remounting. This diagram on the react lifecycle methods helped me when I was dealing with it.

If your problem is like mine you have a component like

class Card extend Component {
  componentDidMount() {
    // call fetch function which probably updates your redux store  
  }

  render () {
    return // JSX or child component with {...this.props} used, 
           // some of which are taken from the store through mapStateToProps
  }
}

The first time you hit a url that mounts this component everything works right and then, when you visit another route that uses the same component, nothing changes. That's because the component isn't being remounted, it's just being updated because some props changed, at least this.props.match.params is changing.

But componentDidMount() is not called when the component updates (see link above). So you will not fetch the new data and update your redux store. You should add a componentDidUpdate() function. That way you can call your fetching functions again when the props change, not just when the component is originally mounted.

componentDidUpdate(prevProps) {
  if (this.match.params.id !== prevProps.match.params.id) {
    // call the fetch function again
  }
}

Check the react documentation out for more details.

Athabaska answered 27/11, 2018 at 22:38 Comment(0)
C
2

I actually figured out another way to do this.

We'll start with your example code: <Route path='/:code' component={Card}/>

What you want to do is have <Card> be a wrapper component, functional preferrably (it won't actually need any state I don't think) and render the component that you want to have rendered by passing down your props with {...props}, so that it gets the Router properties, but importantly give it a key prop that will force it to re-render from scratch

So for example, I have something that looks like this:

<Route exact={false} path="/:customerid/:courierid/:serviceid" component={Prices} />

And I wanted my component to rerender when the URL changes, but ONLY when customerid or serviceid change. So I made Prices into a functional component like this:

function Prices (props) {
    const matchParams = props.match.params;
    const k = `${matchParams.customerid}-${matchParams.serviceid}`;
    console.log('render key (functional):');
    console.log(k);
    return (
        <RealPrices {...props} key={k} />
    )
}

Notice that my key only takes customerid and serviceid into account - it will rerender when those two change, but it won't re-render when courierid changes (just add that into the key if you want it to). And my RealPrices component gets the benefit of still having all the route props passed down, like history, location, match etc.

Casie answered 15/10, 2019 at 15:59 Comment(1)
this is the best practiceGlassworks
A
2

If you are looking for a solution using hooks.

If you are fetching data from some API then you can wrap that call inside a useEffect block and pass history.location.pathname as a parameter to useEffect.

Code:

import { useHistory } from "react-router";

    
const App = () => {
  const history = useHistory();

  useEffect(() => {
    //your api call here
  }, [history.location.pathname]);
};

useHistory hook from react-router will give the path name so the useEffect will be called everytime it (url) is changed

Arv answered 13/9, 2021 at 12:58 Comment(0)
S
1

as described by @theshubhagrwl but you can use location.href instead of location.pathname to work in all condition

import { useHistory } from "react-router";

    
const App = () => {
  const history = useHistory();

  useEffect(() => {
    // do you task here 
  }, [history.location.href]);
};
Strained answered 21/10, 2022 at 12:37 Comment(0)
A
0

You can use use UseLocation() from "react-router-dom" and then use that object in useEffect dependency array.

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

export default function Card() {
    const location = useLocation();

    useEffect(()=>{}, [location]);

    return(
        // your code here
    );
}
    
Anticlerical answered 4/2, 2023 at 11:26 Comment(0)
R
0

Best way to solve this problem is using UseLocation(), following is example which re- render the functional component whenever the url value changes:

import {useEffect} from 'react'
import {useLocation } from 'react-router-dom'

function Somecomponent(){
let location = useLocation()

useEffect(
()=>{

/* here is your fetch API or any other logic Code */

}
,[location.pathname]
);

}

export default Somecomponent
Rasla answered 20/5, 2024 at 12:4 Comment(0)
S
-3

In React Router v4 Adding a Switch tag after the Router tag fixes the problem Like this

<Router>
  <Switch>
  </Switch>
</Router>
Stevie answered 24/1, 2019 at 8:0 Comment(2)
What does this mean?Forsook
This doesn't make any senseArv

© 2022 - 2025 — McMap. All rights reserved.