1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

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.
This commit is contained in:
Arunoda Susiripala 2016-12-20 22:57:43 +05:30 committed by Guillermo Rauch
parent 660147f661
commit 141c045c68
4 changed files with 42 additions and 23 deletions

View file

@ -24,8 +24,6 @@ export default () => (
<div>
<Link href='/'>Home</Link>
<Link href='/about'>About</Link>
<div>
<small>Now you are in the route: {Router.route} </small>
</div>
<Link href='/error'>Error</Link>
</div>
)

View file

@ -0,0 +1,16 @@
import React from 'react'
import Header from '../components/Header'
import Router from 'next/router'
const ErrorPage = ({ aa }) => (
<div>
<Header />
<p>This should not be rendered via SSR</p>
</div>
)
ErrorPage.getInitialProps = () => {
console.log(Router.pathname)
}
export default ErrorPage

View file

@ -6,7 +6,7 @@ let router = null
const SingletonRouter = {}
// Create public properties and methods of the router in the SingletonRouter
const propertyFields = ['route', 'components', 'pathname', 'query']
const propertyFields = ['components', 'pathname', 'route', 'query']
const methodFields = ['push', 'replace', 'reload', 'back']
propertyFields.forEach((field) => {
@ -16,6 +16,7 @@ propertyFields.forEach((field) => {
// proper way to access it
Object.defineProperty(SingletonRouter, field, {
get () {
throwIfNoRouter()
return router[field]
}
})
@ -23,29 +24,33 @@ propertyFields.forEach((field) => {
methodFields.forEach((field) => {
SingletonRouter[field] = (...args) => {
throwIfNoRouter()
return router[field](...args)
}
})
// This is an internal method and it should not be called directly.
//
// ## Client Side Usage
// We create the router in the client side only for a single time when we are
// booting the app. It happens before rendering any components.
// At the time of the component rendering, there'll be a router instance
//
// ## Server Side Usage
// We create router for every SSR page render.
// Since rendering happens in the same eventloop this works properly.
function throwIfNoRouter () {
if (!router) {
const message = 'No router instance found.\n' +
'You should only use "next/router" inside the client side of your app.\n'
throw new Error(message)
}
}
// Export the SingletonRouter and this is the public API.
export default SingletonRouter
// INTERNAL APIS
// -------------
// (do not use following exports inside the app)
// Create a router and assign it as the singleton instance.
// This is used in client side when we are initilizing the app.
// This should **not** use inside the server.
export const createRouter = function (...args) {
router = new _Router(...args)
return router
}
// Export the actual Router class, which is also use internally
// You'll ever need to access this directly
// Export the actual Router class, which is usually used inside the server
export const Router = _Router
// Export the SingletonRouter and this is the public API.
// This is an client side API and doesn't available on the server
export default SingletonRouter

View file

@ -3,7 +3,7 @@ import { createElement } from 'react'
import { renderToString, renderToStaticMarkup } from 'react-dom/server'
import requireModule from './require'
import read from './read'
import { createRouter } from '../lib/router'
import { Router } from '../lib/router'
import Head, { defaultHead } from '../lib/head'
import App from '../lib/app'
@ -56,12 +56,12 @@ async function doRender (req, res, pathname, query, {
if (res.finished) return
const renderPage = () => {
const router = createRouter(pathname, query)
const app = createElement(App, {
Component,
props,
router
router: new Router(pathname, query)
})
const html = (staticMarkup ? renderToStaticMarkup : renderToString)(app)
const head = Head.rewind() || defaultHead()
return { html, head }