Skip to content

Commit 141c045

Browse files
arunodarauchg
authored andcommittedDec 20, 2016
Make next/router a client only API. (#443)
* Prevent using 'next/router' APIs inside 'getInitialProps' * Remove incorrect documentation. * Make next/router a client only API.
1 parent 660147f commit 141c045

File tree

4 files changed

+42
-23
lines changed

4 files changed

+42
-23
lines changed
 

‎examples/using-router/components/Header.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ export default () => (
2424
<div>
2525
<Link href='/'>Home</Link>
2626
<Link href='/about'>About</Link>
27-
<div>
28-
<small>Now you are in the route: {Router.route} </small>
29-
</div>
27+
<Link href='/error'>Error</Link>
3028
</div>
3129
)

‎examples/using-router/pages/error.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react'
2+
import Header from '../components/Header'
3+
import Router from 'next/router'
4+
5+
const ErrorPage = ({ aa }) => (
6+
<div>
7+
<Header />
8+
<p>This should not be rendered via SSR</p>
9+
</div>
10+
)
11+
12+
ErrorPage.getInitialProps = () => {
13+
console.log(Router.pathname)
14+
}
15+
16+
export default ErrorPage

‎lib/router/index.js

+22-17
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ let router = null
66
const SingletonRouter = {}
77

88
// Create public properties and methods of the router in the SingletonRouter
9-
const propertyFields = ['route', 'components', 'pathname', 'query']
9+
const propertyFields = ['components', 'pathname', 'route', 'query']
1010
const methodFields = ['push', 'replace', 'reload', 'back']
1111

1212
propertyFields.forEach((field) => {
@@ -16,36 +16,41 @@ propertyFields.forEach((field) => {
1616
// proper way to access it
1717
Object.defineProperty(SingletonRouter, field, {
1818
get () {
19+
throwIfNoRouter()
1920
return router[field]
2021
}
2122
})
2223
})
2324

2425
methodFields.forEach((field) => {
2526
SingletonRouter[field] = (...args) => {
27+
throwIfNoRouter()
2628
return router[field](...args)
2729
}
2830
})
2931

30-
// This is an internal method and it should not be called directly.
31-
//
32-
// ## Client Side Usage
33-
// We create the router in the client side only for a single time when we are
34-
// booting the app. It happens before rendering any components.
35-
// At the time of the component rendering, there'll be a router instance
36-
//
37-
// ## Server Side Usage
38-
// We create router for every SSR page render.
39-
// Since rendering happens in the same eventloop this works properly.
32+
function throwIfNoRouter () {
33+
if (!router) {
34+
const message = 'No router instance found.\n' +
35+
'You should only use "next/router" inside the client side of your app.\n'
36+
throw new Error(message)
37+
}
38+
}
39+
40+
// Export the SingletonRouter and this is the public API.
41+
export default SingletonRouter
42+
43+
// INTERNAL APIS
44+
// -------------
45+
// (do not use following exports inside the app)
46+
47+
// Create a router and assign it as the singleton instance.
48+
// This is used in client side when we are initilizing the app.
49+
// This should **not** use inside the server.
4050
export const createRouter = function (...args) {
4151
router = new _Router(...args)
4252
return router
4353
}
4454

45-
// Export the actual Router class, which is also use internally
46-
// You'll ever need to access this directly
55+
// Export the actual Router class, which is usually used inside the server
4756
export const Router = _Router
48-
49-
// Export the SingletonRouter and this is the public API.
50-
// This is an client side API and doesn't available on the server
51-
export default SingletonRouter

‎server/render.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { createElement } from 'react'
33
import { renderToString, renderToStaticMarkup } from 'react-dom/server'
44
import requireModule from './require'
55
import read from './read'
6-
import { createRouter } from '../lib/router'
6+
import { Router } from '../lib/router'
77
import Head, { defaultHead } from '../lib/head'
88
import App from '../lib/app'
99

@@ -56,12 +56,12 @@ async function doRender (req, res, pathname, query, {
5656
if (res.finished) return
5757

5858
const renderPage = () => {
59-
const router = createRouter(pathname, query)
6059
const app = createElement(App, {
6160
Component,
6261
props,
63-
router
62+
router: new Router(pathname, query)
6463
})
64+
6565
const html = (staticMarkup ? renderToStaticMarkup : renderToString)(app)
6666
const head = Head.rewind() || defaultHead()
6767
return { html, head }

0 commit comments

Comments
 (0)
Please sign in to comment.