I posted idea at discuss.reactjs.org seems no one is very interested. Maybe I should post one here. I say react-router
is doing routing wrong since it's way to hold private state, which might be fixed in redux-router
. But still, I suppose my idea is valuable.
And I way, router is a View, so it's a component in React. Nothing more than that.
Before digging into that router I want to explain how to create a view like that. Now I'm going to create a own router, it's address bar actually, here's what it look like:
We have a "go back" button, a "forward" button, a "reload" button, and an address bar. Since it's a component, we need to represent that with data. And here's an example of the data in CoffeeScript:
schema.routeTemplate = Immutable.fromJS
name: 'demo' # give each pattern a name
data: {} # for path params
query: {} # for query params
# I left the X, Y, and Z to you to fill
schema.historyList = Immutable.fromJS [
schema.routeTemplate.set('name', X).set('data', X).set('query', X)
schema.routeTemplate.set('name', Y).set('data', Y).set('query', Y)
schema.routeTemplate.set('name', Z).set('data', Z).set('query', Z)
]
In my demo the address is:
http://frp.im/team/a14bb3a?title=hard
I suppose you are familiar with that, it's parsed in Express.js and react-router
:
Immutable.fromJS
name: 'team' # a name, actually with a pattern for it like `/team/:id`
data:
id: 'a14bb3a'
query:
title: 'hard'
The rest part is now simple since it's React we work with. There's a pointer
field somewhere in the store that is pointing to a record in historyList
. As someone clicks on go back
or forward
the pointer updates. Then we get another piece of data to render in the address bar. This step is to render an object into a string. It's easy.
What else I need to implement is the update events, like typing in address directly, like triggering navigation from a click event. The first one is tricky, I have to parse the string by myself and update historyList
and my pointer
. The second one is easy, just create a object that represents the router and putting it there and it's OK.
So, whether or router is a view, we can implement router with a view in React, or more specifically "implement a address bar in a React component". That's my point!
Now let's go back to browsers. Sad that we have some problems: 1) historyList
is put inside the browser we can hardly make it by ourselves, 2) "go back" and "forward" icons are controlled by browser itself, no event.preventDefault
is provided. It's actually tricky if I want to turn that into a normal React component like we do with input
element.
At last I managed to create something called router-view
and it worked well in the past months in production. It's not perfect, but very useful:
http://router-view.mvc-works.org/
https://github.com/jianliaoim/router-view
Just like Draft.js recreated rich text editor based on immutable data and unidirectional data flow, I think router should also be recreated based on the principles we recovered along with React. I mean router is a component, it renders the its props like routerTemplate
, and callbacks events like onPopstate
, and can be used just like normal React components.
As I found in this solution, you don't need to learn new terms like <Route>
and <Link>
, it's basically emit new data to historyList
and can be done with basic React techniques. And nesting router is easy, passing the routerTemplate
down to a child component and do routing with a big switch
block(in CoffeeScript, might be tricky in JSX without support of everything is an expression).
So that's my idea about router. It's better designed in React's way.
And at last, there are some drawbacks using this router. react-router
is tricky but in the meanwhile looks very elegant. It's not elegant anymore using switch
block in both parent element and child element. What's more, since state is put in store, which is outside the router component, code like dispatch
is required. That means much more code to write. Well, nothing can be perfect.