• The love-hate Relationship between React Router and React Components
  • Original author: Kasra
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: Augustwuli
  • Proofreader: RicardoCao-Biker

As React developers, most of us enjoy the convenience of using the React Router for routing React applications.

Why we ❤️ React routing:

  • It works perfectly with React and follows the same principles
  • The navigational aspects of routing are easy to understand
  • Component composition, declarative UI, state management and it closely follows the React workflow (events => state changes => re-render)
  • Reliable browsing history features allow users to navigate through the application while tracking view state.

However, when using React routing, you will face some difficulties if your application-specific requirements become slightly more complex than the usual usage you see in every tutorial on the Web.

The good news is that even in those scenarios, the React route still allows us to solve problems in a clean way; But the solution may not be as obvious as it seems at first sight. Here’s an example from our Fjong development team at 👗 where we changed query parameters in the routing path and expected a component to be rerendered. The React Router didn’t behave that way.

Before we describe the specific problem and how we solve it, let’s talk about a few aspects of the huge relationship between React routing and the React component.

In love relationships

React Routes and React components have many connections. This is mainly because they all follow the same event loop as mentioned above (events => state changes => re-render). Now with this flow in mind, we’ll address a common problem with navigation in an application; Scroll to the top of the page when the route changes.

Suppose you have a set of components named Home, About, and Search

<Router history={History}>
  <Switch>
    <Route exact path="/" component={Home}/>
    <Route exact path="/about" component={About}/>
    <Route exact path="/search" component={Search}/>
    <Route exact component={NoMatch}/>
  </Switch>
</Router>
Copy the code

Now suppose that when you jump to /search, you have to scroll a few times to see what you want to see on the search page.

Then you type in the link to jump to/About in the address bar and suddenly see the bottom of the About Us page instead of the top, which can be annoying. There are a few ways around this, but the React route gives you all the tools necessary to do this correctly. Let’s look at the actual situation.

/* globals window */

/* Global Dependencies */
const React = require('react');
const { Component } = require('react');
const PropTypes = require('prop-types');
const { Route, withRouter } = require('react-router-dom');

class ScrollToTopRoute extends Component {

	componentDidUpdate(prevProps) {
		if (this.props.location.pathname !== prevProps.location.pathname) {
			window.scrollTo(0, 0);
		}
	}

	render() { const { component: Component, ... rest } = this.props;return<Route {... rest} render={props => (<Component {... props} />)} />; } } ScrollToTopRoute.propTypes = { path: PropTypes.string, location: PropTypes.shape({ pathname: PropTypes.string, }), component: PropTypes.instanceOf(Component), }; module.exports = withRouter(ScrollToTopRoute); // Usagein App.jsx
<Router history={History}>
  <Switch>
    <ScrollToTopRoute exact path="/" component={Home}/>
    <ScrollToTopRoute exact path="/about" component={About}/>
    <ScrollToTopRoute exact path="/search" component={Search}/>
    <ScrollToTopRoute exact component={NoMatch}/>
  </Switch>
</Router>
Copy the code

Hate relationship

But as with any relationship, things don’t go smoothly in every situation. This is the same with the React route and React components. To better understand this, let’s look at a possible scenario in the application.

Suppose you want to go from /search to /about, and then when you get to the About Us page, the page will obviously be re-rendered as you expect. The same goes for navigating from /about to /search.

Now suppose we start at /search? Tags = Dresses to/search? Tags =Bags when your SearchPage appends search query parameters to the URL and you want to rerender them. Here we change the search query on the React route path location.path = /search, which is recognized by the React route as a property on the same location object location.search =? tags=Dresses or ? Tags = Bags.

Neither the React route nor your components realize they need to rerender the page because technically, we’re still on the same page. The React component does not allow route jumps between the same path but different search queries to trigger re-rendering.

There seems to be a disconnect between our routing and components at the moment. So sad: (

So, how can we solve this problem? Each of them has a solution to the problem. The React route tells us if the search query parameters in the URL have changed and, more importantly, it does so according to the React correct lifecycle. The component is then responsible for deciding what to do with this information.

In this case, if the component needs to be rerendered (determined by a Boolean property called RouteKey (prop)) it will pass a unique key to the component, The key is a combination of location.pathname and location.search (this conveys the general rule of thumb for keys that keys should be unique, stable, and predictable). In this scenario, the component accepts a new key every time a route is requested; And even if you stay on the same page, it will re-render for you without any side effects. Let’s see how it works in practice!

/* globals window */

/** Global Dependencies */
const React = require('react');
const { Component } = require('react');
const PropTypes = require('prop-types');
const { Route, withRouter } = require('react-router-dom');

class ScrollToTopRoute extends Component {

	componentDidUpdate(prevProps) {
		if (this.props.location.pathname !== prevProps.location.pathname) {
			window.scrollTo(0, 0);
		}
	}

	render() { const { component: Component, RouteKey, location, ... rest } = this.props; /** * Sometimes we need to force a React Route to re-render when the * search params (query)in the url changes. React Router does not
		 * do this automatically if you are on the same page when the query
		 * changes. By passing the `RouteKey`ro the `ScrollToTopRoute` and
		 * setting it to true. we are passing the combination of pathname and * search params as a unique key to the component and that is a enough * and clear triggerfor the component to re-render without side effects
		 */
		const Key = RouteKey ? location.pathname + location.search : null;

		return<Route {... rest} render={props => (<Component {... props} key={Key} />)} />; } } ScrollToTopRoute.propTypes = { path: PropTypes.string, location: PropTypes.shape({ pathname: PropTypes.string, }), component: PropTypes.instanceOf(Component), RouteKey: PropTypes.boolean, }; module.exports = withRouter(ScrollToTopRoute); // Usagein App.jsx
<Router history={History}>
  <Switch>
    <ScrollToTopRoute exact path="/" component={Home}/>
    <ScrollToTopRoute exact path="/about" component={About}/>
    <ScrollToTopRoute exact path="/search" component={Search} RouteKey={true} />
    <ScrollToTopRoute exact component={NoMatch}/>
  </Switch>
</Router>
Copy the code

conclusion

We looked at examples of how React routes and components fit together perfectly, and what happens when they are slightly separated. It’s important to remember, however, that in most cases React routes follow the same principles and design patterns as React routes. Taking the time to familiarize yourself with these principles and their associated execution context will go a long way toward fixing bugs in React routes.

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.