diff --git a/src/index.js b/src/index.js index c50e6068..9128f06c 100644 --- a/src/index.js +++ b/src/index.js @@ -151,7 +151,7 @@ class Router extends Component { this.state = { url: props.url || getCurrentUrl() }; - + initEventListeners(); } @@ -179,7 +179,12 @@ class Router extends Component { } componentWillMount() { - ROUTERS.push(this); + // preact-render-to-string does not initialize the "next state" field for components. + // We can use this to detect a static rendering environment and disable subscriptions. + this._ssr = !('_nextState' in this || '__s' in this); + if (!this._ssr) { + ROUTERS.push(this); + } this.updating = true; } @@ -194,7 +199,7 @@ class Router extends Component { componentWillUnmount() { if (typeof this.unlisten==='function') this.unlisten(); - ROUTERS.splice(ROUTERS.indexOf(this), 1); + ROUTERS.splice(ROUTERS.indexOf(this) >>> 0, 1); } componentWillUpdate() { @@ -230,7 +235,7 @@ class Router extends Component { let current = active[0] || null; let previous = this.previousUrl; - if (url!==previous) { + if (!this._ssr && url!==previous) { this.previousUrl = url; if (typeof onChange==='function') { onChange({ diff --git a/test/index.js b/test/index.js index a63492be..319ccb71 100644 --- a/test/index.js +++ b/test/index.js @@ -4,6 +4,14 @@ import assertCloneOf from '../test_helpers/assert-clone-of'; chai.use(assertCloneOf); +function createBrowserRouter(props) { + const router = new Router(props); + router.__s = router.state || {}; // _nextState + router.__d = true; // _dirty + router.componentWillMount(); + return router; +} + describe('preact-router', () => { it('should export Router, Link and route', () => { expect(Router).to.be.a('function'); @@ -13,7 +21,7 @@ describe('preact-router', () => { describe('Router', () => { it('should filter children based on URL', () => { - let router = new Router({}); + let router = createBrowserRouter({}); let children = [ , , @@ -34,7 +42,7 @@ describe('preact-router', () => { }); it('should support nested parameterized routes', () => { - let router = new Router({}); + let router = createBrowserRouter({}); let children = [ , , @@ -55,7 +63,7 @@ describe('preact-router', () => { }); it('should support default routes', () => { - let router = new Router({}); + let router = createBrowserRouter({}); let children = [ , , @@ -76,7 +84,7 @@ describe('preact-router', () => { }); it('should support initial route prop', () => { - let router = new Router({ url:'/foo' }); + let router = createBrowserRouter({ url:'/foo' }); let children = [ , , @@ -87,14 +95,14 @@ describe('preact-router', () => { router.render({ children }, router.state) ).to.be.cloneOf(children[2]); - expect(new Router({})).to.have.deep.property('state.url', location.pathname + (location.search || '')); + expect(createBrowserRouter({})).to.have.deep.property('state.url', location.pathname + (location.search || '')); }); it('should support custom history', () => { let push = sinon.spy(); let replace = sinon.spy(); let getCurrentLocation = sinon.spy(() => ({pathname: '/initial'})); - let router = new Router({ + let router = createBrowserRouter({ history: { push, replace, getCurrentLocation }, children: [ , @@ -123,7 +131,7 @@ describe('preact-router', () => { let router; before( () => { - router = new Router({ + router = createBrowserRouter({ url: '/foo', children: [ ,