/ react

Hooking into Route Changes in React Router v4

React Router v4 is coming up fast. The first beta was released this week which includes support for hooking into route changes. I needed the ability to run a couple things any time a route changed, so I came up with a simple component that runs as many things as I want when the url is updated.

A couple ideas of what to run on route changes:

  • We have a referral system that needs to check if there's a certain query parameter in the url.
  • setting a canonical url
  • Send a page view to google analytics on every page change.
  • Redirect users if they are not allowed on certain pages (ex a regular user hitting /admin)

Since the referral system came up, I decided it might be better to have a way to hook into these changes in a more general way.

Yes, I came up with this today, and yes it's a very easy thing to do!

After doing this I realized many people new to react router may be confused as to how this is done, so here's a quick guide on hooking into route changes!

Here's the component:

import { withRouter } from 'react-router'

@withRouter
export default class RouteChange extends React.Component {

  componentDidMount () {
    this.routeChanged()
  }

  componentDidUpdate (prevProps) {
    let { location: { pathname } } = this.props

    if (prevProps.location.pathname === pathname) return
    this.routeChanged()
  }

  routeChanged () {
    let { location, push, replace, actions } = this.props

    actions.forEach(action => {
      action(location, { push, replace })
    })
  }

  render () {
    return null
  }
}

Now create an actions file and register as many functions as you'd like that will be ran on route changes:

import referral from './referral'
import redirectWrongUser from './redirect-wrong-user'

export default [
  referral,
  redirectWrongUser
]

An example function might look like the referral code I made:

import qs from 'qs'
import ReferralRequest from './referral-request'

export default ({ pathname, search }) => {
  const requestParams = qs.parse(search)
  if (!requestParams.referrer) return
  ReferralRequest(requestParams)
}

And there you have it, a simple way to add in hooks on route changes! Let's add it right inside our top-level Router component:

import routeActions from './route-actions'

export default () => (
  <BrowserRouter>
    <div>
      <RouteChange 
        actions={routeActions}
      />
      <Container />
    </div>
  </BrowserRouter>
)