Browse code
Update documentation, make it actually useful
Max Summe authored on 14/06/2017 17:18:41
Showing 2 changed files
Showing 2 changed files
... | ... |
@@ -1,25 +1,29 @@ |
1 | 1 |
# Routux — Routes the Redux Way |
2 | 2 |
|
3 |
-Routux is a little router that removes the idea of routes from your react application and instead makes them actions |
|
4 |
-that you can handle in redux, allowing a complete separation of the url state from your application state. |
|
3 |
+Routux routes URLs to Redux actions and vice versa. |
|
4 |
+ |
|
5 |
+Your application doesn't need to know it lives in a browser, but your users want pretty urls and deep links. |
|
5 | 6 |
|
6 | 7 |
## Wait, why would you want to do that? Aren't URLs pretty essential for web applications? |
7 | 8 |
|
8 |
-TODO - rewrite this so it sucks less. Main points - maintainability, proper separation of conerns, redux-paradigm purity |
|
9 |
+React Router is the currently-accepted way to do routing in React applications. We found some issues with that, and |
|
10 |
+we basically agree with Formidable Labs that [React Router is the wrong way to route in Redux apps.](http://formidable.com/blog/2016/07/11/let-the-url-do-the-talking-part-1-the-pain-of-react-router-in-redux/) |
|
11 |
+ |
|
12 |
+However, we don't think their solution ([redux-little-router](https://github.com/FormidableLabs/redux-little-router)) |
|
13 |
+goes far enough, as it still embeds the idea of routes throughout your React component structure. |
|
9 | 14 |
|
10 |
-TODO - reference redux-little-router and the articles from there and why they don't go far enough. |
|
15 |
+We think a cleaner separation would be to think of UI state as another part of the state tree, along with the data model. |
|
11 | 16 |
|
12 |
-Yes, URLs are one of the main interfaces for the web. But they are not the main interface for single-page applications. |
|
17 |
+This allows your application to determine how to display itself without reference to being on the world-wide web. |
|
13 | 18 |
|
14 |
-They're a tacked-on addition inside your javascript. |
|
19 |
+It also means that you can express all UI transitions as actions instead of URL changes, making your application portable |
|
20 |
+to non-web environments without requiring some other routing technology. |
|
15 | 21 |
|
16 |
-Basically, we want to express that while a user may want to interact with, or copy/paste a url, it is not an intrinsic |
|
17 |
-restriction of user interface that deserves to be littering your code with path-based restrictions. |
|
22 |
+If you'd like to make it a mobile app, just remove the routes, and as long as you're not relying on links and urls, everything |
|
23 |
+works just as before. |
|
18 | 24 |
|
19 |
-Additionally, by removing this, we reduce the amount of UI testing that needs to be done by making the entire user |
|
20 |
-interface a pure function of your redux state. Woot! That's great. In MVC terms, React components are "view" level |
|
21 |
-while routes are a model or controller concern. They should express either a resource to load, or a particular state |
|
22 |
-of the application. |
|
25 |
+As an added (and we think absolutely essential) benefit, your entire application becomes easier to test, as rendering |
|
26 |
+is a pure function of Redux state, and model logic is entirely encapsulated in Redux outside of the app. |
|
23 | 27 |
|
24 | 28 |
## Routing in 25 lines |
25 | 29 |
|
... | ... |
@@ -59,11 +63,79 @@ the corresponding action will fire (unless the action was initiated by a url cha |
59 | 63 |
|
60 | 64 |
## Route precedence examples (how we resolve seeming ambiguity) |
61 | 65 |
|
66 |
+Route precedence is a function of the type of matching done in each segment and the order in which the wildcard segments |
|
67 |
+match. Exact matches are always preferred to wildcards moving from left to right. |
|
68 |
+ |
|
69 |
+```javascript |
|
70 |
+ |
|
71 |
+ const routesInOrderOfPrecedence = [ |
|
72 |
+ |
|
73 |
+ ['/user/me/update', '/user/me'], // both perfectly specific - will match above any wildcard route |
|
74 |
+ '/user/me/:view', |
|
75 |
+ '/user/:id/update', // less specific because 'me' is exact match, while :id is a wildcard |
|
76 |
+ '/user/:id/:view' |
|
77 |
+ ]; |
|
78 |
+ |
|
79 |
+``` |
|
80 |
+ |
|
62 | 81 |
## Usage with fragment |
63 | 82 |
|
64 |
-see our demo app |
|
83 |
+```javascript |
|
84 |
+ |
|
85 |
+const state = { |
|
86 |
+ menu: ... |
|
87 |
+} |
|
88 |
+ |
|
89 |
+const view = ( |
|
90 |
+ <PageFrame> |
|
91 |
+ <Fragment state={state} filterOn="menu"> |
|
92 |
+ <Menu /> |
|
93 |
+ </Fragment> |
|
94 |
+ </PageFrame> |
|
95 |
+) |
|
96 |
+ |
|
97 |
+// If menu is truthy, this renders as: |
|
98 |
+ |
|
99 |
+( |
|
100 |
+ <PageFrame> |
|
101 |
+ <Menu /> |
|
102 |
+ </PageFrame> |
|
103 |
+) |
|
104 |
+ |
|
105 |
+// If menu is falsy, this renders as: |
|
106 |
+( |
|
107 |
+ <PageFrame> |
|
108 |
+ </PageFrame> |
|
109 |
+) |
|
110 |
+ |
|
111 |
+/////// |
|
112 |
+ |
|
113 |
+const state = { |
|
114 |
+ menu: { |
|
115 |
+ prop: true |
|
116 |
+ } |
|
117 |
+} |
|
118 |
+ |
|
119 |
+// If property is missing in path, it's falsy. |
|
120 |
+ |
|
121 |
+const view = ( |
|
122 |
+ <PageFrame> |
|
123 |
+ <Fragment state={state} filterOn="menu.missingProp.something"> |
|
124 |
+ <Menu /> |
|
125 |
+ </Fragment> |
|
126 |
+ </PageFrame> |
|
127 |
+) |
|
128 |
+ |
|
129 |
+// Renders as: |
|
130 |
+( |
|
131 |
+ <PageFrame> |
|
132 |
+ </PageFrame> |
|
133 |
+) |
|
134 |
+ |
|
135 |
+``` |
|
136 |
+ |
|
137 |
+ |
|
65 | 138 |
|
66 |
-## |
|
67 | 139 |
|
68 | 140 |
|
69 | 141 |
|