Skip to content
React hook for easy routing within a Next.js app
Branch: master
Clone or download
ecwyne and anthonyshort Export "bind" object (#1)
* export bind object

* add bind documentation
Latest commit e01e78e Mar 6, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src Export "bind" object (#1) Mar 6, 2019
.gitignore
.prettierrc First Mar 4, 2019
README.md
package.json First Mar 4, 2019
tsconfig.json First Mar 4, 2019
yarn.lock

README.md

use-next-route

React hook for easy routing within a Next.js app.

import { useRoute } from 'use-next-route'

function ProjectsLink() {
  const { bind } = useRoute('/projects')
  return (
    <a {...bind}>Projects</a>
  )
}

Why

  • As a Next app grows it becomes hard to manage link to all of the different routes.
  • The next/link component has an awkward API that was designed pre-hooks.
  • The router and link also don't have a concept of a "prefix", which is required when mounting a Next app in a sub-directory.

Setup

You'll need to use RouteContext to provide the router and an optional routePrefix to the React app.

import { RouteProvider } from 'use-next-route'
import { withRouter } from 'next/router'

function ProjectsPage(props) {
  return (
    <RouteProvider route={props.router.route} routePrefix="/dashboard">
      <div>My Projects</div>
    </RouteProvider>
  )
}

export default withRouter(ProjectsPage)

You'll most likely want to create a custom _app rather than doing this on every page.

Sub-directory routing

You can use the routePrefix prop to automatically as a prefix to all links. This will be provided as the as option to the router. You'll want to use this if you're mounting your Next app on a sub-directory, like https://myapp.com/dashboard.

This is similar to the assetPrefix option.

API

useRoute(route: UrlObject | string, options: RouteOptions)

import { useRoute } from 'use-next-route'

Returns an object with the following properties:

  • href: URL string for the route. Usually used for adding a href attribute to links.
  • onClick: This will navigate to the route and handle preventing the default mouse event if needed.
  • bind: Object containing href and onClick. Useful for props spreading.
  • isActive: If the current browser location starts with the href. Used for active states.
  • navigate: Navigate to the route.

You won't use next/link or next/router directly anymore. Instead you can use the hooks.

  • Buttons: You can use the onClick property
  • Links: You can use the href property and the onClick property. The href will make it a valid HTML link, allowing users to open to the link in a new tab/window and making it crawlable. Adding the onClick prop will trigger a Router.push for you automatically.

Types

UrlObject
  • pathname: Absolute path to the Next route
  • query: Object of key/value pairs that will be appended to the url as a query string.
RouteOptions
  • prefetch: Prefetch the route. This is disabled by default so you need to opt-in
  • replace: Uses replace instead of push.
  • as: Allows you to override the url in the location bar. If you're using routePrefix this is taken care of for you, but if you want to use a custom alias you can instead. The routePrefix will still be applied.

Examples:

import { useRoute } from 'use-next-route'

function Page() {
  const { href, onClick } = useRoute('/projects')
  return (
    <a href={href} onClick={onClick}>Click me!</a>
  )
}

export default ProjectPage

Enabling prefetch and replacing instead:

import { useRoute } from 'use-next-route'

function Page() {
  const { href, onClick } = useRoute('/projects', {
    prefetch: true,
    replace: true
  })
  return (
    <a href={href} onClick={onClick}>Click me!</a>
  )
}

export default ProjectPage

Using a UrlObject like when you use Router.push:

import { useRoute } from 'use-next-route'

function ProjectPage(props) {
  const projectRoute = useRoute({
    pathname: '/project/details',
    query: {
      id: props.project.id
    }
  })
  return (
    <a href={projectRoute.href} onClick={projectRoute.onClick}>{props.project.name}</a>
  )
}

export default ProjectPage

Using a custom hook:

import { useRoute, RouteOptions } from 'use-next-route'

function useProjectRoute(projectId: string, options?: RouteOptions) {
  return useRoute({
    pathname: '/project/details',
    query: {
      id: projectId
    }
  }, options)
}

function ProjectPage(props) {
  const projectRoute = useProjectRoute(props.project.id, {
    prefetch: true
  })
  return (
    <a href={projectRoute.href} onClick={projectRoute.onClick}>{props.project.name}</a>
  )
}

export default ProjectPage

Extracting out the custom hooks into a routes file:

import { RouteOptions, useRoute } from 'use-next-route'

export function useProjectRoute(id, options?: RouteOptions) {
  const route = {
    pathname: '/projects',
    query: {
      id
    }
  }
  return useRoute(route, options)
}

export function useSettingsRoute(options?: RouteOptions) {
  return useRoute('/settings', options)
}
import { useProjectRoute, useSettingsRoute } from './routes'

function Page({ project }) {
  const projectRoute = useProjectRoute(project.id, {
    prefetch: true
  })
  const settingsRoute = useSettingsRoute()
  return (
    <>
      <a href={projectRoute.href} onClick={projectRoute.onClick}>{project.name}</a>
      <a href={settingsRoute.href} onClick={settingsRoute.onClick}>Settings</a>
    </>
  )
}

RouteProvider

import { RouteProvider } from 'use-next-route'

Add the context to you app to inject the Next router. This is required for useRoute to work.

import { RouteProvider } from 'use-next-route'
import { withRouter } from 'next/router'

function ProjectsPage(props) {
  return (
    <RouteProvider route={props.router.route} routePrefix="/dashboard">
      <div>My Projects</div>
    </RouteProvider>
  )
}

export default withRouter(ProjectsPage)
You can’t perform that action at this time.