Skip to content
This repository has been archived by the owner on Dec 15, 2018. It is now read-only.

Nested Routing #47

Closed
wants to merge 6 commits into from
Closed

Nested Routing #47

wants to merge 6 commits into from

Conversation

dpwrussell
Copy link

@dpwrussell dpwrussell commented Aug 27, 2016

I am opening this PR to add nested route support within the route configuration and matcher. It is not complete and certainly requires some discussion as currently it's a breaking change in as far as what the route configuration object must look like. There would definitely be ways to make it compatible though. It also differs in what is delivered to the Fragment as the result. Instead of the single matching routes details, it's an array of all the details from the route components that constitute the current route.

I added some test cases to demonstrate.

Basically it works like this though:

  • Define routes from nested route components. I am hoping to improve on the readability of this:
const root = { routeComponent: '/', name:'root' };
const home = { routeComponent:'home', name:'home' };
const messages = { routeComponent:'messages', name:'messages' };
const team = { routeComponent:':team', name:'team' };
const channel = { routeComponent:':channel', name:'channel' };
const spookyparam = { routeComponent:':spookyparam', name:'3spooky5me' };

const routes = Object.assign(root, {
  children: [Object.assign(home, {
    children: [Object.assign(messages, {
      children: [Object.assign(team, {
        children: [Object.assign(channel, {})]
      })]
    }), Object.assign(spookyparam, {})]
  })]
});
  • When matching a route. This route component tree is traversed as a depth first search. There are other ways to do this, but this was the simplest to implement as a first pass. When a route is matched, it returns the standard structure of:
{
  route: The route which has actually been matched,
  params: Any parameters (or empty object) that have been matched,
  result: The tree components involved in this route
}

but where the result is now an array of the route components in order, so metadata supplied in any of them could be used in the Fragment.

  • The Fragment now has a new property inRoute that matches any of the route components in the result (potentially this should not be in result). This can be ambiguous (if two route components had the same pattern), so it could be switched to use the route component names instead.

There's still work to be done, but it doesn't seem too difficult and I really think that nested routes are an essential feature.

Routes built from nested route components
Working inRoute Fragment property to make use of route components
This demonstrates the capability to have the same route component at multiple
locations in the route

Also, promoted route design attempt 7 to the top of the file and is
updated going forward
@dpwrussell
Copy link
Author

dpwrussell commented Aug 29, 2016

I have made the route composition a bit tidier:

const root = { routeComponent: '/', name:'root' };
const home = { routeComponent:'home', name:'home' };
const messages = { routeComponent:'messages', name:'messages' };
const team = { routeComponent:':team', name:'team' };
const channel = { routeComponent:':channel', name:'channel' };
const spookyparam = { routeComponent:':spookyparam', name:'3spooky5me' };
const global = { routeComponent:'global', name:'global' };

// Attmempt 7 (Improvement on attempt 6. Seems the simplest)
function makeRoute(details, ...children) {
  return Object.assign({}, details, children ? { children } : {});
}

const routes =
makeRoute(root,
  makeRoute(home,
    makeRoute(messages,
      makeRoute(team,
        makeRoute(channel)
      )
    ),
    makeRoute(global,
      makeRoute(channel)
    ),
    makeRoute(spookyparam)
  )
);

It is also possible to specify the individual route component details inline, but I prefer this as it allows me to reuse components (In this example channel is reused under a global path. Ultimately that's upto the individual developer though, but the makeRoute could be provided as a utility.

Add a test to show absolute (minus '/' only) paths as a single route
component.
@dpwrussell
Copy link
Author

I have also added a test case with absolute routing to demonstrate that the existing system of providing full paths to routes needn't go away.

const root = { routeComponent: '/', name:'root' };
const home = { routeComponent:'home', name:'home' };
const messages = { routeComponent:'messages', name:'messages' };
const team = { routeComponent:':team', name:'team' };
const channel = { routeComponent:':channel', name:'channel' };
const spookyparam = { routeComponent:':spookyparam', name:'3spooky5me' };
const global = { routeComponent:'global', name:'global' };
const absolute = { routeComponent:'a/b/c/:d', name:'absolute' }

const routes =
makeRoute(root,
  makeRoute(home,
    makeRoute(messages,
      makeRoute(team,
        makeRoute(channel)
      )
    ),
    makeRoute(global,
      makeRoute(channel)
    ),
    makeRoute(spookyparam)
  ),
  makeRoute(absolute)
);

This will match /a/b/c/whatever and return an array of two items as the results, root (as there can only be one) and the absolute component.

@tptee
Copy link
Contributor

tptee commented Aug 30, 2016

Hey @dpwrussell,

Sorry I didn't get to this sooner, and thanks for all the work you've put into this PR! However, I think it's important that the nested route API remains backwards-compatible for at least a few major releases, given that this library's been though significant churn. I have some ideas on how to make that happen that I'll outline in #53 today.

@tptee tptee closed this Aug 30, 2016
@tptee tptee mentioned this pull request Sep 9, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants