Skip to content

Commit 3d3d4dc

Browse files
committed
React 0.12 compatibility.
See #97.
1 parent c576daf commit 3d3d4dc

16 files changed

+346
-230
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.idea
22
node_modules/
33
bundle.js
4+
tests/*.jsx

Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ test-server:
1919
@./node_modules/.bin/mocha -R spec -b tests/server.js
2020

2121
test-local:
22-
@./node_modules/.bin/zuul --local 3000 -- tests/browser.js
22+
@./node_modules/.bin/jsx tests/browser-jsx.jsx > tests/browser-jsx.js
23+
@./node_modules/.bin/zuul --local 3000 -- tests/browser.js tests/browser-jsx.js
2324

2425
test-cloud:
2526
@./node_modules/.bin/zuul -- tests/browser.js

docs/index.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ component's `render()` method:
1515

1616
Alternatively, if you don't prefer JSX:
1717

18+
var Locations = React.createFactory(Router.Locations);
19+
var Location = React.createFactory(Router.Location);
1820
Locations(null,
1921
Location({path: "/", handler: MainPage}),
2022
Location({path: "/users/:username", handler: UserPage}))
@@ -59,6 +61,11 @@ scope, cause JSX doesn't support namespaces yet:
5961
var Locations = Router.Locations
6062
var Location = Router.Location
6163

64+
Otherwise, as of React 0.12, you must create factories:
65+
66+
var Locations = React.createFactory(Router.Locations)
67+
var Location = React.createFactory(Router.Location)
68+
6269
Now you can define your application as a regular React component which renders
6370
into `Locations` router:
6471

@@ -90,7 +97,7 @@ successful location match.
9097

9198
The final part is to render your `App` component which activates your router:
9299

93-
React.renderComponent(App(), document.body)
100+
React.renderComponent(React.createElement(App), document.body)
94101

95102
In case no location is matched router would render into an empty set of
96103
elements.

lib/AsyncRouteRenderingMixin.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use strict";
22

3-
var merge = require('react/lib/merge');
3+
var assign = Object.assign || require('object.assign');
44
var prefetchAsyncState = require('react-async/lib/prefetchAsyncState');
55
var isAsyncComponent = require('react-async/lib/isAsyncComponent');
66
var RouteRenderingMixin = require('./RouteRenderingMixin');
@@ -16,7 +16,7 @@ var AsyncRouteRenderingMixin = {
1616
var currentHandler = this.state && this.state.handler;
1717
var nextHandler = state && state.handler;
1818

19-
if (nextHandler &&
19+
if (nextHandler && nextHandler.type &&
2020
isAsyncComponent(nextHandler) &&
2121
// if component's type is the same we would need to skip async state
2222
// update
@@ -42,8 +42,7 @@ var AsyncRouteRenderingMixin = {
4242
if (this.isMounted() &&
4343
this.state.pendingState &&
4444
this.state.pendingState.match === state.match) {
45-
46-
var nextState = merge(this.state.pendingState, {handler: handler});
45+
var nextState = assign({}, this.state.pendingState, {handler: handler});
4746
this.replaceState(nextState, cb);
4847

4948
}

lib/CaptureClicks.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var React = require('react');
44
var urllite = require('urllite/lib/core');
55
var Environment = require('./environment');
6+
var assign = Object.assign || require('object.assign');
67

78
/**
89
* A container component which captures <a> clicks and, if there's a matching
@@ -109,11 +110,10 @@ var CaptureClicks = React.createClass({
109110
},
110111

111112
render: function() {
112-
var props = {
113+
var props = assign({}, this.props, {
113114
onClick: this.onClick
114-
};
115-
return this.transferPropsTo(
116-
this.props.component(props, this.props.children));
115+
});
116+
return this.props.component(props, this.props.children);
117117
}
118118

119119
});

lib/Link.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var React = require('react');
44
var NavigatableMixin = require('./NavigatableMixin');
55
var Environment = require('./environment');
6+
var assign = Object.assign || require('object.assign');
67

78
/**
89
* Link.
@@ -70,11 +71,11 @@ var Link = React.createClass({
7071
},
7172

7273
render: function() {
73-
var props = {
74+
var props = assign({}, this.props, {
7475
onClick: this.onClick,
7576
href: this._createHref()
76-
};
77-
return this.transferPropsTo(React.DOM.a(props, this.props.children));
77+
});
78+
return React.DOM.a(props, this.props.children);
7879
}
7980
});
8081

lib/Route.js

+37-66
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,43 @@
11
"use strict";
22

3-
var invariant = require('react/lib/invariant');
4-
var merge = require('react/lib/merge');
5-
var mergeInto = require('react/lib/mergeInto');
6-
7-
/**
8-
* Create a new route descriptor from a specification.
9-
*
10-
* @param {Object} spec
11-
* @param {?Object} defaults
12-
*/
13-
function createRoute(spec, defaults) {
14-
15-
var handler = spec.handler;
16-
var path = spec.path;
17-
var ref = spec.ref;
18-
var matchKeys = spec.matchKeys;
19-
var props = merge({}, spec);
20-
21-
delete props.path;
22-
delete props.handler;
23-
delete props.ref;
24-
delete props.matchKeys;
25-
26-
var route = {
27-
path: path,
28-
handler: handler,
29-
props: props,
30-
matchKeys: matchKeys,
31-
ref: ref
32-
};
33-
34-
if (defaults) {
35-
mergeInto(route, defaults);
36-
}
37-
38-
invariant(
39-
typeof route.handler === 'function',
40-
"Route handler should be a component or a function but got: %s", handler
41-
);
42-
43-
invariant(
44-
route.path !== undefined,
45-
"Route should have an URL pattern specified: %s", handler
46-
);
47-
48-
return route;
49-
}
50-
51-
/**
52-
* Regular route descriptor.
53-
*
54-
* @param {Object} spec
55-
*/
56-
function Route(spec) {
57-
return createRoute(spec);
58-
}
59-
60-
/**
61-
* Catch all route descriptor.
62-
*
63-
* @param {Object} spec
64-
*/
65-
function NotFound(spec) {
66-
return createRoute(spec, {path: null});
3+
var React = require('react');
4+
5+
function createClass(name) {
6+
return React.createClass({
7+
propTypes: {
8+
handler: React.PropTypes.oneOfType([
9+
React.PropTypes.node,
10+
React.PropTypes.func
11+
]).isRequired,
12+
path: name === 'NotFound' ?
13+
function(props, propName) {
14+
if (props[propName]) throw new Error("Don't pass a `path` to NotFound.");
15+
}
16+
: React.PropTypes.string.isRequired
17+
},
18+
getDefaultProps: function() {
19+
if (name === 'NotFound') {
20+
return {path: null};
21+
}
22+
return {};
23+
},
24+
render: function() {
25+
throw new Error(name + " is not meant to be directly rendered.");
26+
}
27+
});
6728
}
6829

6930
module.exports = {
70-
Route: Route,
71-
NotFound: NotFound
31+
/**
32+
* Regular route descriptor.
33+
*
34+
* @param {Object} spec
35+
*/
36+
Route: createClass('Route'),
37+
/**
38+
* Catch all route descriptor.
39+
*
40+
* @param {Object} spec
41+
*/
42+
NotFound: createClass('NotFound')
7243
};

lib/RouteRenderingMixin.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
"use strict";
22

3-
var cloneWithProps = require('react/lib/cloneWithProps');
3+
var cloneWithProps = require('react/lib/cloneWithProps');
44

55
/**
66
* Mixin for routers which implements the simplest rendering strategy.
77
*/
88
var RouteRenderingMixin = {
99

1010
renderRouteHandler: function() {
11-
var ref = this.state.match.route && this.state.match.route.ref;
12-
return cloneWithProps(this.state.handler, {ref: ref});
11+
var handler = this.state.handler;
12+
return cloneWithProps(handler, {ref: this.state.match.route.ref});
1313
}
1414

1515
};

lib/Router.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var React = require('react');
44
var RouterMixin = require('./RouterMixin');
55
var AsyncRouteRenderingMixin = require('./AsyncRouteRenderingMixin');
6+
var assign = Object.assign || require('object.assign');
67

78
/**
89
* Create a new router class
@@ -29,8 +30,12 @@ function createRouter(name, component) {
2930
},
3031

3132
render: function() {
33+
// Render the Route's handler.
3234
var handler = this.renderRouteHandler();
33-
return this.transferPropsTo(this.props.component(null, handler));
35+
// Pass all props except this component to the Router (containing div/body).
36+
var props = assign({}, this.props);
37+
delete props.component;
38+
return this.props.component(props, handler);
3439
}
3540
});
3641
}

lib/RouterMixin.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
var React = require('react');
44
var invariant = require('react/lib/invariant');
5-
var merge = require('react/lib/merge');
5+
var assign = Object.assign || require('object.assign');
66
var matchRoutes = require('./matchRoutes');
77
var Environment = require('./environment');
88

@@ -161,7 +161,7 @@ var RouterMixin = {
161161
navigation: navigation
162162
};
163163

164-
navigation = merge(navigation, {match: match});
164+
assign(navigation, {match: match});
165165

166166
if (this.props.onBeforeNavigation &&
167167
this.props.onBeforeNavigation(path, navigation) === false) {

lib/matchRoutes.js

+19-16
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"use strict";
22

33
var pattern = require('url-pattern');
4-
var mergeInto = require('react/lib/mergeInto');
4+
var assign = Object.assign || require('object.assign');
55
var invariant = require('react/lib/invariant');
6+
var React = require('react');
67

78
/**
89
* Match routes against a path
@@ -22,17 +23,23 @@ function matchRoutes(routes, path) {
2223
// Simply skip null or undefined to allow ternaries in route definitions
2324
if (!current) continue;
2425

26+
// We expect to be passed an Element. If we weren't, and were just passed props,
27+
// mock an Element's structure.
28+
if (!React.isValidElement(current)) {
29+
current = {props: current, ref: current.ref};
30+
}
31+
2532
if (process.env.NODE_ENV !== "production") {
2633
invariant(
27-
current.handler !== undefined && current.path !== undefined,
34+
current.props.handler !== undefined && current.props.path !== undefined,
2835
"Router should contain either Route or NotFound components " +
2936
"as routes")
3037
}
3138

32-
if (current.path) {
33-
current.pattern = current.pattern || pattern.newPattern(current.path);
39+
if (current.props.path) {
40+
current.props.pattern = current.props.pattern || pattern.newPattern(current.props.path);
3441
if (!page) {
35-
match = current.pattern.match(path);
42+
match = current.props.pattern.match(path);
3643
if (match) {
3744
page = current;
3845
}
@@ -42,7 +49,7 @@ function matchRoutes(routes, path) {
4249
}
4350
}
4451
}
45-
if (!notFound && current.path === null) {
52+
if (!notFound && current.props.path === null) {
4653
notFound = current;
4754
}
4855
}
@@ -91,16 +98,12 @@ function Match(path, route, match) {
9198
}
9299

93100
Match.prototype.getHandler = function() {
94-
var props = {};
95-
if (this.match) {
96-
mergeInto(props, this.match);
97-
}
98-
if (this.route && this.route.props) {
99-
mergeInto(props, this.route.props);
100-
}
101-
// we will set ref later during a render call
102-
delete props.ref;
103-
return this.route ? this.route.handler(props) : undefined;
101+
if (!this.route) return undefined;
102+
var props = assign({}, this.route.props, this.match);
103+
delete props.pattern;
104+
delete props.path;
105+
delete props.handler;
106+
return this.route.props.handler(props);
104107
}
105108

106109
module.exports = matchRoutes;

package.json

+10-13
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,22 @@
55
"main": "index.js",
66
"dependencies": {
77
"envify": "^1.2.1",
8-
"react": "^0.11.1",
8+
"object.assign": "^1.0.1",
9+
"react": "^0.12.0",
10+
"react-async": "~2.0.0",
911
"url-pattern": "~0.6.0",
1012
"urllite": "~0.4.0"
1113
},
12-
"peerDependencies": {
13-
"react": "~0.11.0",
14-
"react-async": "~1.0.1"
15-
},
1614
"devDependencies": {
17-
"react": "~0.11.0",
18-
"react-async": "~1.0.1",
19-
"semver": "~2.2.1",
20-
"mocha": "~1.17.1",
21-
"jshint": "~2.4.3",
22-
"zuul": "~1.5.2",
15+
"browserify": "^3.32.1",
2316
"browserify-shim": "^3.3.1",
17+
"jshint": "~2.4.3",
18+
"mocha": "~1.17.1",
19+
"react-tools": "^0.12.0",
20+
"reactify": "^0.15.1",
21+
"semver": "~2.2.1",
2422
"uglify-js": "^2.4.13",
25-
"browserify": "^3.32.1",
26-
"reactify": "^0.14.0"
23+
"zuul": "~1.5.2"
2724
},
2825
"browserify": {
2926
"transform": [

0 commit comments

Comments
 (0)