On url change i want to re render my component how should i do that
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
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()}
</>
);
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!!
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});
}
);
}
}