Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
React Redirect
React Redirect Side Effect
====================

Fork of react-redirect working with last React version (>=15.4.0).

Provides a declarative way to specify `window.location` in a single-page app.
This component can be used on server side as well.

Expand All @@ -14,7 +16,7 @@ Built with [React Side Effect](https://github.com/gaearon/react-side-effect).
npm install --save react-redirect
```

Dependencies: React >= 0.11.0
Dependencies: React >= 15.5.0

## Features

Expand Down
68 changes: 29 additions & 39 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,34 @@
'use strict';

var React = require('react'),
createSideEffect = require('react-side-effect');

var _serverRedirect = null;

function getRedirectFromPropsList(propsList) {
var innermostProps = propsList[propsList.length - 1];
if (innermostProps) {
return innermostProps.location;
}
PropTypes = require('prop-types'),
withSideEffect = require('react-side-effect');

function reducePropsToState(propsList) {
var innermostProps = propsList[propsList.length - 1];
if (innermostProps) {
return innermostProps.location;
}
}

var WindowRedirect = createSideEffect(function handleChange(propsList) {
var location = getRedirectFromPropsList(propsList);

if (typeof document !== 'undefined') {
if (location)
window.location = location;
} else {
_serverRedirect = location || null;
}
}, {
displayName: 'WindowRedirect',

propTypes: {
location: React.PropTypes.string.isRequired
},

statics: {
peek: function () {
return _serverRedirect;
},

rewind: function () {
var location = _serverRedirect;
this.dispose();
return location;
}
}
});

module.exports = WindowRedirect;
function handleStateChangeOnClient(location) {
if (location) { window.location = location };
};

function ReactRedirect() {}
ReactRedirect.prototype = Object.create(React.Component.prototype);
ReactRedirect.displayName = 'ReactRedirect';
ReactRedirect.propTypes = { location: PropTypes.string.isRequired };

ReactRedirect.prototype.render = function() {
if (this.props.children) {
return React.Children.only(this.props.children);
} else {
return null;
}
};

module.exports = withSideEffect(
reducePropsToState,
handleStateChangeOnClient
)(ReactRedirect);
21 changes: 12 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"name": "react-redirect",
"version": "1.0.0",
"name": "react-redirect-side-effect",
"version": "2.0.2",
"description": "A declarative, nested, stateful window.location for React",
"main": "index.js",
"peerDependencies": {
"react": ">=0.11.0 || >=0.13.0-beta.1"
"react": ">=15.4.0"
},
"scripts": {
"test": "mocha",
"lint": "jshint index.js test"
},
"repository": {
"type": "git",
"url": "https://github.com/Driftt/react-redirect.git"
"url": "https://github.com/avanes/react-redirect-side-effect.git"
},
"keywords": [
"react",
Expand All @@ -24,17 +24,20 @@
"author": "Sitian Liu <goldensunliu@gmail.com> (http://github.com/goldensunliu)",
"license": "MIT",
"bugs": {
"url": "https://github.com/Driftt/react-redirect/issues"
"url": "https://github.com/avanes/react-redirect-side-effect/issues"
},
"homepage": "https://github.com/Driftt/react-redirect",
"homepage": "https://github.com/avanes/react-redirect-side-effect",
"devDependencies": {
"create-react-class": "^15.5.0",
"expect.js": "^0.3.1",
"global": "^4.3.0",
"jshint": "^2.5.6",
"mocha": "^2.0.1",
"react": "^0.13.0-beta.1"
"mocha": "^3.2.0",
"react": "^15.5.0",
"react-dom": "^15.5.0"
},
"dependencies": {
"react-side-effect": "~0.3.0"
"prop-types": "^15.5.0",
"react-side-effect": "~1.1.0"
}
}
59 changes: 31 additions & 28 deletions test/browser.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
/*jshint newcap: false */
/*global global, describe, it, afterEach, before, after */
/*global global, describe, it, afterEach, before, after, beforeEach */
'use strict';
var expect = require('expect.js'),
React = require('react'),
ReactRedirect = require('../');
React = require('react'),
ReactDOM = require('react-dom'),
createReactClass = require('create-react-class'),
ReactRedirect = require('../');

describe('DocumentTitle (in a browser)', function () {
afterEach(function () {
React.unmountComponentAtNode(global.document.body);
delete global.document.title;
});
before(function () {
// Prepare the globals React expects in a browser
describe('ReactRedirect (in a browser)', function () {
var container;
beforeEach(function () {
global.document = require('global/document')
global.window = require('global/window');
global.document = require('global/document');
global.window.document = document;
global.window.location = {};
global.window.navigator = {userAgent: 'Chrome'};
console.debug = console.log;
global.window.location = {}
container = document.createElement('div');
});
after(function () {
afterEach(function () {
ReactDOM.unmountComponentAtNode(container);
delete global.window;
delete global.document;
delete console.debug;
});
it('changes the document title on mount', function (done) {
before(function() {
ReactRedirect.canUseDOM = true;
})

it('changes the location on mount', function (done) {
var location = 'www.driftt.com';
var Component = React.createClass({
var Component = createReactClass({
componentDidMount: function () {
expect(global.window.location).to.equal(location);
done();
Expand All @@ -35,33 +35,36 @@ describe('DocumentTitle (in a browser)', function () {
return React.createElement(ReactRedirect, {location: location});
}
});
React.render(React.createElement(Component), global.document.body);
ReactDOM.render(React.createElement(Component), container);
});

it('supports nesting', function (done) {
var component2Called = false;
var called = false;
var location = 'www.driftt.com';
var Component1 = React.createClass({
var Component1 = createReactClass({
componentDidMount: function () {
setTimeout(function () {
expect(component2Called).to.be(true);
expect(global.window.location).to.equal(location);
expect(called).to.be(true);
expect(global.window.location).to.equal('location');
done();
});
},
render: function () {
console.log('render1')
return React.createElement(ReactRedirect, {location: location});
}
});
var Component2 = React.createClass({
var Component2 = createReactClass({
componentDidMount: function () {
component2Called = true;
called = true;
},
render: function () {
console.log('render2')
return React.createElement(ReactRedirect, {location: 'hell nah'},
React.DOM.div(null, React.createElement(Component1))
);
}
});
React.render(React.createElement(Component2), global.document.body);
ReactDOM.render(React.createElement(Component2), container);
});
});
});
37 changes: 21 additions & 16 deletions test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,31 @@
/*global describe, it */
'use strict';
var expect = require('expect.js'),
React = require('react'),
ReactRedirect = require('../');
React = require('react'),
ReactDOMServer = require('react-dom/server'),
createReactClass = require('create-react-class'),
ReactRedirect = require('../');

describe('ReactRedirect', function () {
before(function() {
ReactRedirect.canUseDOM = false;
})
it('has a displayName', function () {
var el = React.createElement(ReactRedirect, {location: 'irrelevant'});
expect(el.type.displayName).to.be.a('string');
expect(el.type.displayName).not.to.be.empty();
});
it('hides itself from the DOM', function () {
var Component = React.createClass({
var Component = createReactClass({
render: function () {
return React.createElement(ReactRedirect, {location: 'irrelevant'}, React.createElement('div', null, 'hello'));
}
});
var markup = React.renderToStaticMarkup(React.createElement(Component));
var markup = ReactDOMServer.renderToStaticMarkup(React.createElement(Component));
expect(markup).to.equal('<div>hello</div>');
});
it('throws an error if it has multiple children', function (done) {
var Component = React.createClass({
var Component = createReactClass({
render: function () {
return React.createElement(ReactRedirect, {location: 'irrelevant'},
React.createElement('div', null, 'hello'),
Expand All @@ -30,22 +35,22 @@ describe('ReactRedirect', function () {
}
});
expect(function () {
React.renderToStaticMarkup(React.createElement(Component));
ReactDOMServer.renderToStaticMarkup(React.createElement(Component));
}).to.throwException(function (e) {
expect(e.message).to.match(/^Invariant Violation:/);
expect(e.message).to.match(/^React.Children.only expected to receive a single React element child/);
done();
});
});
it('works with complex children', function () {
var Component1 = React.createClass({
var Component1 = createReactClass({
render: function() {
return React.createElement('p', null,
React.createElement('span', null, 'c'),
React.createElement('span', null, 'd')
);
}
});
var Component2 = React.createClass({
var Component2 = createReactClass({
render: function () {
return React.createElement(ReactRedirect, {location: 'irrelevant'},
React.createElement('div', null,
Expand All @@ -56,7 +61,7 @@ describe('ReactRedirect', function () {
);
}
});
var markup = React.renderToStaticMarkup(React.createElement(Component2));
var markup = ReactDOMServer.renderToStaticMarkup(React.createElement(Component2));
expect(markup).to.equal(
'<div>' +
'<div>a</div>' +
Expand All @@ -74,31 +79,31 @@ describe('ReactRedirect', function () {

describe('ReactRedirect.rewind', function () {
it('clears the mounted instances', function () {
React.renderToStaticMarkup(
ReactDOMServer.renderToStaticMarkup(
React.createElement(ReactRedirect, {location: 'a'},
React.createElement(ReactRedirect, {location: 'b'}, React.createElement(ReactRedirect, {location: 'c'}))
)
);
expect(ReactRedirect.peek()).to.equal('c');
ReactRedirect.rewind();
expect(ReactRedirect.peek()).to.equal(null);
expect(ReactRedirect.peek()).to.equal(undefined);
});
it('returns the latest document title', function () {
var location = 'www.driftt.com';
React.renderToStaticMarkup(
ReactDOMServer.renderToStaticMarkup(
React.createElement(ReactRedirect, {location: 'a'},
React.createElement(ReactRedirect, {location: 'b'}, React.createElement(ReactRedirect, {location: location}))
)
);
expect(ReactRedirect.rewind()).to.equal(location);
});
it('returns nothing if no mounted instances exist', function () {
React.renderToStaticMarkup(
ReactDOMServer.renderToStaticMarkup(
React.createElement(ReactRedirect, {location: 'a'},
React.createElement(ReactRedirect, {location: 'b'}, React.createElement(ReactRedirect, {location: 'c'}))
)
);
ReactRedirect.rewind();
expect(ReactRedirect.peek()).to.equal(null);
expect(ReactRedirect.peek()).to.equal(undefined);
});
});
});
Loading