36

I am trying to have separate routes but same component for add/edit forms in my react app like the below:

<Switch>
        <Route exact path="/dashboard" component={Dashboard}></Route>
        <Route exact path="/clients" component={Clients}></Route>
        <Route exact path="/add-client" component={manageClient}></Route>
        <Route exact path="/edit-client" component={manageClient}></Route>        
        <Route component={ NotFound } />        
</Switch>

Now in the manageClient component, I parse the query params (I pass in a query string with client id in edit route), I render conditionally based on the query param passed.

The problem is that this doesn't remount the whole component again. Say an edit page is opened, and the user clicks on add component, the URL changes, but the component doesn't reload and hence remains on the edit page.

Is there a way to handle this?

Tomasz Mularczyk
  • 27,156
  • 17
  • 99
  • 146
beNerd
  • 3,088
  • 5
  • 43
  • 84
  • In the root DOM element of `manageClient`'s `render()` method, try to add a `key`, whose value is based on whatever querystring you give it. For example, try having it be `key="add"` for /add-client and `key="edit"` for /edit-client. (I actually don't know if this will work, which is why I'm not submitting it as an answer) – sme Feb 27 '18 at 04:18

4 Answers4

67

Using different key for each route should force components to rebuild:

    <Route 
      key="add-client"
      exact path="/add-client"
      component={manageClient} 
    />

    <Route 
      key="edit-client"
      exact path="/edit-client"
      component={manageClient} 
    />
  • Is it possible to catch the key/path from the component itself? – Jaison James Feb 21 '19 at 10:31
  • It's possible. You can get route props from components by `this.props.route.key` –  Feb 22 '19 at 11:06
  • This worked for me until I had a dynamic route (with an ID property in the route a la `/blog/post/:id`)... the key was unique to the URL and ANY ID, but navigating between two IDs maps to the same route and key twice, failing to re-render the route when navigating between two routes mapped to the same router entry... e.g. nav'ing between `/blog/post/1` and `/blog/post/2` does not re-render either... – Rimer Mar 26 '20 at 03:41
  • To clarify more, the "key" is to trigger diffing in react reconciliation. FYI https://github.com/ReactTraining/react-router/issues/5972 and https://reactjs.org/docs/reconciliation.html – silencej Jun 12 '20 at 14:43
8

One solution is use inline function with component, that will render a new component each time, But this is not a good idea.

Like this:

<Route exact path="/add-client" component={props => <ManageClient {...props} />}></Route>
<Route exact path="/edit-client" component={props => <ManageClient {...props} />}></Route> 

Better solution would be, use componentWillReceiveProps lifecycle method in ManageClient component. Idea is whenever we render same component for two routes and switching between them, then react will not unmount-mount component, it will basically update the component only. So if you are making any api call or require some data do all in this method on route change.

To check, use this code and see it will get called on route change.

componentWillReceiveProps(nextProps){
   console.log('route chnaged')
}

Note: Put the condition and make the api call only when route changes.

Mayank Shukla
  • 80,295
  • 14
  • 134
  • 129
  • 1
    I believe this is the better answer. Suggesting the use of componentWillReceiveProps as the location to make an API call was what I needed without unmounting/mounting the same component. – adam8810 Jun 23 '18 at 21:47
  • 4
    `componentWillReceiveProps` is deprecated now as of React 16.3 – Patrik Fuhrmann Jul 05 '18 at 09:12
0
<Route exact path={["/add-client", "/edit-client"]}>
  <manageClient />
</Route>

Reference

Version 5.2.0

https://reacttraining.com/react-router/web/api/Route/path-string-string

0

My problem was we used an common path in-between, which causes dynamic path to not working

      <Switch>
        <Route key="Home" path="/home" component={Home} />
        <Route key="PolicyPlan-create"  path="/PolicyPlan/create" component={PolicyPlanCreatePage} />
        {/* <Route key="PolicyPlan-list" path="/PolicyPlan" component={PolicyPlanListPage} /> */}
        <Route key="PolicyPlan-list" path="/PolicyPlan/list" component={PolicyPlanListPage} />            
        <Route key="PolicyPlan-edit"  path="/PolicyPlan/edit/:id" component={PolicyPlanCreatePage} />   
        <Route key="cardDesign" path="/cardDesign" component={cardDesign} />
        <Route key="Admin-create" path="/admin/create" component={RegisterPage} />
      </Switch>

So don't use the path like the commented one, now the code is working

.................
          this.props.history.push("/PolicyPlan/edit/" + row.PolicyPlanId);
.............    
Moumit
  • 4,822
  • 6
  • 41
  • 45