question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Performances: quick solution "withRouter" VS render a pathless <Route>.

See original GitHub issue

Here (https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md) it says:

Quick Solution

If you are running into this issue while using a higher-order component like connect (from react-redux) or observer (from Mobx), you can just wrap that component in a withRouter to remove the blocked updates.

// redux before const MyConnectedComponent = connect(mapStateToProps)(MyComponent) // redux after const MyConnectedComponent = withRouter(connect(mapStateToProps)(MyComponent))

This is not the most efficient solution, but will prevent the blocked updates issue. For more info regarding this solution, read the Redux guide. To understand why this is not the most optimal solution, read this thread.

So this is not optimal for performances and then it continues:

Recommended Solution

The key to avoiding blocked re-renders after location changes is to pass the blocking component the location object as a prop. This will be different whenever the location changes, so comparisons will detect that the current and next location are different.

What happens when the component isn’t being rendered by a <Route> and the component rendering it does not have the location in its variable scope? There are two approaches that you can take to automatically inject the location as a prop of your component.

What happens when the component isn’t being rendered by a <Route> and the component rendering it does not have the location in its variable scope? There are two approaches that you can take to automatically inject the location as a prop of your component.

Render a pathless <Route>. While <Route>s are typically used for matching a specific path, a pathless <Route> will always match, so it will always render its component. // pathless <Route> = <Blocker> will always be rendered

const MyComponent= () => (
  <SomeComponent>
    <Route component={Blocker} />
  </SomeComponent>
)

So I don’t understand: the second one is better than the first one?

Using this: <Route component={Blocker} /> is better (for performances) than this: withRouter(connect(mapStateToProps)(MyComponent))?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
pshrmncommented, Nov 18, 2017

@johnunclesam Using withRouter literally renders a pathless <Route>. If your only use for withRouter is to prevent blocked updates and you already have access to the location prop, then you are just adding extra components to your application by using withRouter instead of passing the location as a prop. If you don’t have access to the location, then just use withRouter.

For example, let’s imagine we have the following components:

const ConnectedOne = connect(...)(One);
const ConnectedTwo = connect(...)(Two);

const Thing = ({ location }) => (
  <div>
    {/* right now, these won't update when <Thing> re-renders */}
    <ConnectedOne />
    <ConnectedTwo />
  </div>
);

const App = () => (
  <Switch>
    <Route exact path='/thing' component={Thing} />
  </Switch>
);

ReactDOM.render((
  <BrowserRouter>
    <App />
  </BrowseRouter>
), holder);

The <Thing> component is rendered by a <Route>, which means that it is passed the location prop when it is rendered. Our <ConnectedOne> and <ConnectedTwo> components are wrapped in connect, which prevents them from re-rendering by default. However, our <Thing> can pass them the location prop, which will cause the shouldComponentUpdate method of the component returned by connect to return true.

const Thing = ({ location }) => (
  <div>
    <ConnectedOne location={location} />
    <ConnectedTwo location={location}  />
  </div>
);

Alternatively, we could just wrap ConnectedOne and ConnectedTwo in withRouter to get the same result.

const ConnectedOne = withRouter(connect(...)(One));
const ConnectedTwo = withRouter(connect(...)(Two));

const Thing = ({ location }) => (
  <div>
    {/* these won't update when <Thing> re-renders */}
    <ConnectedOne />
    <ConnectedTwo />
  </div>
);

What is the difference? Well, let’s take a look at the element trees that each approach will create:

// passing props
<BrowserRouter>
  <App>
    <Switch>
      <Route>
        <Thing>
          <div>
            <connect>
              <One />
            <connect>
              <Two />

// using withRouter
<BrowserRouter>
  <App>
    <Switch>
      <Route>
        <Thing>
          <div>
            <withRouter>
              <Route>
                <connect>
                  <One />
            <withRouter>
              <Route>
                <connect>
                  <Two />

Both of the above component trees have the same end result, but the latter adds extra components to your application. Is using withRouter going to have a huge performance hit on your application? Probably not unless you’re wrapping half of your components in withRouter. Still, if you already have access to the location component, you might as well just use the prop. The worst is when there is a component that is already rendered by a <Route> and gets wrapped in withRouter.

// don't do this!
const ConnectedThing = withRouter(connect(...)(Thing));
const App = () => (
  <Switch>
    <Route exact path='/thing' component={ConnectedThing} />
  </Switch>
);
/*
<App>
  <Switch>
    <Route>
      <withRouter>
        <Route>
          <connect>
            <Thing>
*/
0reactions
ghostcommented, Nov 18, 2017

Thanks @pshrmn. Much appreciated.

Read more comments on GitHub >

github_iconTop Results From Across the Web

quick solution "withRouter" VS render a pathless <Route ...
Quick Solution. If you are running into this issue while using a higher-order component like connect (from react-redux) or observer (from ...
Read more >
Changing a component to a container seems to break Routes ...
The quick solution to this is to use withRouter. ... is rendering App through a pathless route (which will always match and therefore...
Read more >
The Pathless Route. Which Will Thwart a React Router Gotcha
Routes can be set to render a component without specifying a path! To keep the history object flowing down from App. js to...
Read more >
Reactjs – Using global variables in Redux App – iTecNote
It can be a simple solution but as the official React homepage says, ... You can render a pathless route and it will...
Read more >
Ultimate React Router v6 Guide
React Router is by far the most popular routing library in React and this article goes in depth on everything you need to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found