Sharad Pawar
Sharad Pawar

Reputation: 286

On url change I want to re render my component how should I do that

I have two links that fetches the sample component but when I click on any one of them it gets loaded and when I click on another one it won't re-render only url gets changed. I want to re-render the component on both link clicks. Is there any way to do that??

Upvotes: 16

Views: 26044

Answers (4)

Andy
Andy

Reputation: 11492

I just had the same problem myself using a pure function component like this:

import { useHistory, Link, BrowserRouter, useLocation } from 'react-router-dom'

function Comp() {
  const history = useHistory()
//  useLocation()
  return (
    <>
      <p>current path is {history.location.pathname}</p>
      <Link to="/abc">click me</Link>
      <Link to="/xyz">click me</Link>
    </>
  )
}

export default function App() {
  return (
    <BrowserRouter>
      <Comp />
    </BrowserRouter>
  )
}

When you click the links, the URL in the title bar updates but the component does not re-render (i.e. the displayed path doesn't update)

In this case I found the solution is to include a call to useLocation() (shown commented out). You don't even need to do anything with the return value; adding this call makes the component magically re-render when ever the location changes.

Note this is with react-router 5.3. react-router 6 is changed beyond recognition so I don't know if the same problem still exists

Upvotes: 3

Reza
Reza

Reputation: 543

use location hook.

const location = useLocation();

const renderDOM = () => {
 // return your DOM, e.g. <p>hello</p>
}

useEffect(() => {
 // re render your component
 renderDOM();
},[location]);

return (
 <>
 {renderDOM()}
 </>
);

Upvotes: 7

Harkirat Saluja
Harkirat Saluja

Reputation: 8114

I was facing similar issue sometime back when I was working on a react project.

You need to use componentWillReceiveProps function in your component.

  componentWillReceiveProps(nextProps){
     //call your api and update state with new props
  }

UPDATE

For react version 16.3+ please use componentDidUpdate

componentDidUpdate (prevProps, prevState) {
  // update state 
}

To make it more clear when your component loads for the first time by calling url www.example.com/content/a componentDidMount() is run.

Now when you click another link say www.example.com/content/b same component is called but this time prop changes and you can access this new prop under componentWillReceiveProps(nextProps) which you can use to call api and get new data.

Now you can keep a common function say initializeComponent() and call it from componentDidMount() and componentWillReceiveProps()

Your router would look something like this:-

ReactDOM.render((
     <Router history={browserHistory}>
      <Route path="/content" component={app}>
        <IndexRoute component={home}/>
        <Route path="/content/:slug" component={component_name} />
      </Route>
    </Router>
), document.getElementById('app'));

So now when you call www.example.com/content/a, a would be taken as slug. Within that component if you call www.example.com/content/b , b would be taken as slug and would be available as nextProps parameter in componentWillReceiveProps.

Hope it helps!!

Upvotes: 29

Tomiwa
Tomiwa

Reputation: 1054

React 16.3+ discourages the use of componentWillReceiveProps.

React now recommends moving data updates into componentDidUpdate (source):


// After
class ExampleComponent extends React.Component {
  state = {
    externalData: null,
  };

  static getDerivedStateFromProps(props, state) {
    // Store prevId in state so we can compare when props change.
    // Clear out previously-loaded data (so we don't render stale stuff).
    if (props.id !== state.prevId) {
      return {
        externalData: null,
        prevId: props.id,
      };
    }

    // No state update necessary
    return null;
  }

  componentDidMount() {
    this._loadAsyncData(this.props.id);
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.externalData === null) {
      this._loadAsyncData(this.props.id);
    }
  }

  componentWillUnmount() {
    if (this._asyncRequest) {
      this._asyncRequest.cancel();
    }
  }

  render() {
    if (this.state.externalData === null) {
      // Render loading state ...
    } else {
      // Render real UI ...
    }
  }

  _loadAsyncData(id) {
    this._asyncRequest = loadMyAsyncData(id).then(
      externalData => {
        this._asyncRequest = null;
        this.setState({externalData});
      }
    );
  }
}

Upvotes: 1

Related Questions