To force remounting on React components, we can set the key prop of the component to a new value. then the Component component will be remounted since key changed from 1 to 2.
To remount a component when a prop changes, use the React key attribute as described in this post on the React blog: When a key changes, React will create a new component instance rather than update the current one. The example below shows how the key attribute can be used.
Calling history. push() inside of a component seems to cause the entire react component to unmount and remount; causing pointless remote service calls.
React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.
If you do need a component remount when route changes, you can pass a unique key to your component's key attribute (the key is associated with your path/route). So every time the route changes, the key will also change which triggers React component to unmount/remount. I got the idea from this answer
Here is my answer, similar to some of the above but with code.
<Route path="/page/:pageid" render={(props) => (
<Page key={props.match.params.pageid} {...props} />)
} />
If the link is directing to the same route with just a different param, it's not remounting, but instead receiving new props. So, you could use the componentWillReceiveProps(newProps)
function and look for newProps.params.projectId
.
If you're trying to load data, I would recommend fetching the data on before the router handles the match using static methods on the component. Check out this example. React Router Mega Demo. That way, the component would load the data and automatically update when the route params change without needing to rely on componentWillReceiveProps
.
You have to be clear, that a route change will not cause a page refresh, you have to handle it yourself.
import theThingsYouNeed from './whereYouFindThem'
export default class Project extends React.Component {
componentWillMount() {
this.state = {
id: this.props.router.params.id
}
// fire action to update redux project store
this.props.dispatch(fetchProject(this.props.router.params.id))
}
componentDidUpdate(prevProps, prevState) {
/**
* this is the initial render
* without a previous prop change
*/
if(prevProps == undefined) {
return false
}
/**
* new Project in town ?
*/
if (this.state.id != this.props.router.params.id) {
this.props.dispatch(fetchProject(this.props.router.params.id))
this.setState({id: this.props.router.params.id})
}
}
render() { <Project .../> }
}
If you have:
<Route
render={(props) => <Component {...props} />}
path="/project/:projectId/"
/>
In React 16.8 and above, using hooks, you can do:
import React, { useEffect } from "react";
const Component = (props) => {
useEffect(() => {
props.fetchResource();
}, [props.match.params.projectId]);
return (<div>Layout</div>);
}
export default Component;
In there, you are only triggering a new fetchResource
call whenever props.match.params.id
changes.
Based on answers by @wei, @Breakpoint25 and @PaulusLimma I made this replacement component for the <Route>
. This will remount the page when the URL changes, forcing all the components in the page to be created and mounted again, not just re-rendered. All componentDidMount()
and all other startup hooks are executed also on the URL change.
The idea is to change components key
property when the URL changes and this forces React to re-mount the component.
You can use it as a drop-in replacement for <Route>
, for example like this:
<Router>
<Switch>
<RemountingRoute path="/item/:id" exact={true} component={ItemPage} />
<RemountingRoute path="/stuff/:id" exact={true} component={StuffPage} />
</Switch>
</Router>
The <RemountingRoute>
component is defined like this:
export const RemountingRoute = (props) => {
const {component, ...other} = props
const Component = component
return (
<Route {...other} render={p => <Component key={p.location.pathname + p.location.search}
history={p.history}
location={p.location}
match={p.match} />}
/>)
}
RemountingRoute.propsType = {
component: PropTypes.object.isRequired
}
This has been tested with React-Router 4.3.
@wei's answer works great, but in some situations I find it better to not set a key of inner component, but route itself. Also, if path to component is static, but you just want component to remount each time user navigates to it (perhaps to make an api-call at componentDidMount()), it is handy to set location.pathname to key of route. With it route and all it's content gets remounted when location changes.
const MainContent = ({location}) => (
<Switch>
<Route exact path='/projects' component={Tasks} key={location.pathname}/>
<Route exact path='/tasks' component={Projects} key={location.pathname}/>
</Switch>
);
export default withRouter(MainContent)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With