Components and Hooks

This component can be used as a drop-in replacement for <a> tags. Internally, it renders an <a> tag so that statically rendered links will work even if JavaScript is disabled.

Props

active: boolean (optional)

Allows you to explicit enable or disable the activeClassName and activeStyle props.

activeClassName: string (optional)

Will be added to your link’s className if the app’s current URL matches the href prop, or if the active prop is set to true.

activeStyle: object (optional)

Will be merged into your link’s style if the app’s current URL matches the href prop, or if the active prop is set to true.

exact: bool (optional)

If true, the link will only be considered to “match” the current URL if it is an exact match.

By default, a partial match at the beginning of the current URL will also be considered a match. This facilitates nav links, which often need to be highlighted when child pages are active.

href: string (required)

The url to navigate to; identical to the href attribute of a HTML <a> tag.

prefetch: boolean (optional)

If specified, the linked page’s content will be fetched as soon as the link is rendered.

<NotFoundBoundary>

You can wrap a <NotFoundBoundary> around a view to show a “not found” message when no route can be found to be rendered by the view.

Props

render: (error: NotFoundError) => React.Node

Example

function Layout() {
  return (
    <NotFoundBoundary render={() =>
      <h1>Not Found</h1>
    }>
      <View />
    </NotFoundBoundary>
  )
}

<Router>

Your app’s <Router> component is responsible for subscribing to the latest navigation state, and passing that state to Navi’s other components.

By default, <Router> creates a navigation object internally, passing through the routes, basename, context and history props. However, if you’d like to define your navigation object manually — i.e. for static or server rendering support — then you can pass it in via the navigation prop.

Props

Your app’s Navigation object, as returned from createBrowserNavigation() or createMemoryNavigation()

By default, this will be created internally.

basename: string (optional)

The basename to use for the created navigation object. Only used when a navigation prop is not manually supplied.

children: React.ReactNode (optional)

If you don’t pass in any children, then a <View> will be rendered by default.

context: Context (optional)

The <Router> object will keep your navigation object’s context in sync with this prop by calling it’s setContext() method.

This will be used even if you supply a navigation prop.

history: History (optional)

The history to use for the created navigation object. Only used when a navigation prop is not manually supplied.

routes: Matcher

The routes to use for the created navigation object. Only used when a navigation prop is not manually supplied.

<View>

Renders the content for the next matched view that hasn’t already been rendered.

If the content is a React element or component, then the children render function is optional, and that content will be rendered by default. Otherwise, you’ll need to provide a child function to specify how to render the route content.

Suspense

When the page initially loads, it can be the case that no content is available — even for previous routes. In this case, <View> will use React Suspense to pause execution until content is available. However, React requires you to wrap the suspended <View> with a <Suspense fallback>, so that you can decide what will be shown in place of the not-yet-ready content. If you’ve used React.lazy(), then this should be familiar — otherwise, check out the example below.

As React doesn’t yet support Suspense for server-side rendering, you’ll want to avoid using <Suspense> for statically rendered apps. Instead, wait for Navi’s initial content to render before calling ReactDOMServer.render() by creating a custom navigation object and using its navigation.getRoute() function, before passing the navigation object to your <Router> component’s navigation prop.

Props

children: (view, route) => React.ReactNode (optional)

If provided, the component’s children must be a render prop that receives the view’s value as its first argument, and the current Route as its second.

If a children prop is not provided, the default behavior is to render the next unrendered view from route.views.

Examples

Basic Usage

A <View> can be placed anywhere inside a <Router> component — it doesn’t have to be a direct descendent. You’ll often want your <View> to be nested within a <Suspense> component, or a <Layout> component, like so:

import { Router, View } from 'react-navi'

ReactDOM.render(
  <Router navigation={navigation}>
    <Layout>
      <View />
    </Layout>
  </Router>,
  document.getElementById('root')
);

Usage with render prop

By suppling a render prop, you can manually decide how to render the next unrendered view. This makes it possible to specify view objects other than React elements and components

<View>
  {(view, route) => 
    React.isValidElement(content)
      ? content
      : React.createElement(content)
  }
</View>

Usage with React Suspense

By wrapping your content in a React <Suspense> element, you can specify a fallback element to display while your app’s initial content is loading.

Note that until <Suspense> gets server-rendering support, this only makes sense for apps that are not pre-rendered with ReactDOMServer.render(). For static or server rendered apps, use navigation.getRoute() to wait for the initial content to load before hydrating the pre-rendered HTML with ReactDOM.hydrate().

import React, { Suspense } from 'react'
import { Router, View } from 'react-navi'
import Layout from './Layout'

ReactDOM.render(
  <Router routes={routes}>
    <Layout>
      <Suspense fallback={null}>
        <View />
      </Suspense>
    </Layout>
  </Router>,
  document.getElementById('root')
);

useCurrentRoute()

A React Hook that allows you to access the latest non-busy Route, which contains all information that Navi knows about the current page, including:

  • data
  • title
  • url
  • views
  • etc.

You can also access the result of useCurrentRoute() by passing a child function to the <CurrentRoute> component, similar to the API for React context consumers.

Example

You can use useCurrentRoute() to retrieve the current page’s title, and display it as part of a <Layout> component.

import { useCurrentRoute } from 'react-navi'

function Layout({ children }) {
  let route = useCurrentRoute()

  return (
    <div className="Layout">
      <h1>{route.title}</h1>
      {children}
    </div>
  )
}

useLoadingRoute()

A React Hook that outputs the Route object for any page whose content is currently being fetched. If no page is currently being fetched, then it outputs undefined.

Use useLoadingRoute() to display a loading overlay when the user has requested a navigation that hasn’t completed yet.

You can also access the result of useLoadingRoute() by passing a child function to the <LoadingRoute> component, similar to the API for React context consumers.

Example

import { useLoadingRoute } from 'react-navi'

function Layout({ children }) {
  let loadingRoute = useLoadingRoute()

  return (
    <div className="Layout">
      <BusyIndicator show={!!loadingRoute} />
      { children }
    </div>
  )
}

useNavigation()

A React Hook that returns your app’s navigation store, which can be used to facilitate programmatic navigation.

You can also access the result of useNavigation() by passing a child function to the <NaviConsumer> component, similar to the API for React context consumers.

Example

You can use useNavigation() to programmatically navigate after a form is successfully submitted.

import React, { useState } from 'react'
import { useNavigation } from 'react-navi'

function EmailForm() {
  let navigation = useNavigation()
  let [email, setEmail] = useState()

  function handleSubmit() {
    navigation.navigate('/thanks')
  }

  return (
    <form onSubmit={handleSubmit} className="EmailForm">
      <input value={email} onChange={e => setEmail(e.target.value)} />
      <button>Join 13,000 other subscribers</button>
    </div>
  )
}