Ever since we announced Redux Little Router, we’ve worked hard to simplify the API, reduce boilerplate, and ease adoption for beginners. To advance these goals, we’ve introduced two new features: nested routes and nested fragments.

Check out Redux Little Router on GitHub!

Nested Routes

The first step in installing Redux Little Router into your project is to define a “route configuration.” This associates arbitrary metadata with your routes, allowing you to retrieve useful route-specific values when the current URL matches a route (think page titles, data requirements, or conditional visibility of child components).

Prior to v9.0.0, the route configuration looked like this:

const routes = {
  '/': {
    title: 'Home'
  },
  '/messages': {
    title: 'Message'
  },
  '/messages/:user': {
    title: 'Message History'
  }
};

There’s problems with this approach. There’s significant repetition of child routes, which irritates more as your routes grow. Worse, flat routes discard all knowledge of hierarchy. Knowing details about parent routes is the only way to enable features that depend on their position in the route hierarchy (consider an “up” button that allows users to travel up the route tree).

Nested routes solve both problems in a backwards-compatible way. Route definitions now look like this:

const routes = {
  '/': {
    title: 'Home'
    '/messages': {
      title: 'Message',
      '/:user': {
        title: 'Message History'
      }
    }
  },
  '/flat-routes-still-work': {
    title: 'Flat routes still work!'
  }
};

The result key of your router reducer now recursively attaches parent route results!

// For a URL matching /messages/:user
{
  pathname: '/messages/a-user-has-no-name',
  params: {
    user: 'a-user-has-no-name'
  },
  query: {
    some: 'thing'
  },
  result: {
    title: 'Message History'
    parent: {
      title: 'Message'
      parent: {
        title: 'Home'
      }
    }
  }
}

Notice that nested and flat routes can intermingle, with the caveat that flat routes won’t receive any parent route results.route

Nested Fragments

Treating routes as flat led to even worse problems for <Fragment>s. Consider the following:

<Fragment forRoutes={['/', '/messages', '/messages/:user']}>
  <h1>Home</h1>
  <Fragment forRoutes={['/messages', '/messages/:user']}>
    <h2>Messages</h2>
    <Fragment forRoute='/messages/:user'>
      <h3>Message History</h3>
    </Fragment>
  </Fragment>
</Fragment>

That’s a lot of work and repetition for a simple nested UI!

v9.0.0 introduces <RelativeFragment>, backporting the old <Fragment> behavior as <AbsoluteFragment>. If you’re importing Fragment in your current project, your behavior won’t change! We’ll make <RelativeFragment> the default in the next major version.

<RelativeFragment> lets you nest fragments to match your UI hierarchy to your route hierarchy, much like the <Route> component does in react-router. Child fragments derive their parent route from their parent fragment. Given a URL of /home/bio/dat-boi, and the following elements:

<RelativeFragment forRoute='/home'>
  <h1>Home</h1>
  <RelativeFragment forRoute='/bio'>
    <h2>Bios</h2>
    <RelativeFragment forRoute='/dat-boi'>
      <h3>Dat Boi</h3>
      <p>Something something whaddup</p>
    </RelativeFragment>
  </RelativeFragment>
</RelativeFragment>

…React will render:

<div>
  <h1>Home</h1>
    <div>
      <h2>Bios</h2>
        <div>
          <h3>Dat Boi</h3>
          <p>Something something whaddup<p>
        </div>
    </div>
</div>

If you’re using one Fragment type exclusively, you can take advantage of ES6 module syntax to reduce verbosity:

import { RelativeFragment as Fragment } from 'redux-little-router';
// or
import { AbsoluteFragment as Fragment } from 'redux-little-router';

We believe that embracing the hierarchy of routes empowers the URL to make smarter decisions about application state. Try out the new version of Redux Little Router today! We’d love feedback on the new APIs.

There’s more to come! We plan on making the store enhancer initialization less ambiguous between client and server renders by integrating into the node server ecosystem. Stay tuned!