diff --git a/client/index.js b/client/index.js
index b497414d90c8a2a010a5be4645c1165354f3970e..9d13179152968770330b5ee1e6325588e0796e4f 100644
--- a/client/index.js
+++ b/client/index.js
@@ -123,9 +123,9 @@ export async function renderError (error) {
if (prod) {
const initProps = { err: error, pathname, query, asPath }
const props = await loadGetInitialProps(ErrorComponent, initProps)
- ReactDOM.render(createElement(ErrorComponent, props), errorContainer)
+ ReactDOM.hydrate(createElement(ErrorComponent, props), errorContainer)
} else {
- ReactDOM.render(createElement(ErrorDebugComponent, { error }), errorContainer)
+ ReactDOM.hydrate(createElement(ErrorDebugComponent, { error }), errorContainer)
}
}
@@ -151,7 +151,7 @@ async function doRender ({ Component, props, hash, err, emitter }) {
// We need to clear any existing runtime error messages
ReactDOM.unmountComponentAtNode(errorContainer)
- ReactDOM.render(createElement(App, appProps), appContainer)
+ ReactDOM.hydrate(createElement(App, appProps), appContainer)
if (emitter) {
emitter.emit('after-reactdom-render', { Component, ErrorComponent })
diff --git a/client/next-dev.js b/client/next-dev.js
index c5816fbd85fbc989a4eef876412dd58a3238ef92..52ba3ad07f21c4f54539d1dbce208f0ec37ec775 100644
--- a/client/next-dev.js
+++ b/client/next-dev.js
@@ -1,5 +1,4 @@
import 'react-hot-loader/patch'
-import ReactReconciler from 'react-dom/lib/ReactReconciler'
import initOnDemandEntries from './on-demand-entries-client'
import initWebpackHMR from './webpack-hot-middleware-client'
@@ -35,17 +34,3 @@ next.default()
.catch((err) => {
console.error(`${err.message}\n${err.stack}`)
})
-
-// This is a patch to catch most of the errors throw inside React components.
-const originalMountComponent = ReactReconciler.mountComponent
-ReactReconciler.mountComponent = function (...args) {
- try {
- return originalMountComponent(...args)
- } catch (err) {
- if (!err.abort) {
- next.renderError(err)
- err.abort = true
- }
- throw err
- }
-}
diff --git a/lib/app.js b/lib/app.js
index b4b8c833f2f1245784288e0260daa38d31a386e1..43660a1318f4793984de2b9e750c5ecce92f63c1 100644
--- a/lib/app.js
+++ b/lib/app.js
@@ -5,6 +5,10 @@ import { warn } from './utils'
import { makePublicRouterInstance } from './router'
export default class App extends Component {
+ state = {
+ hasError: null
+ }
+
static childContextTypes = {
headManager: PropTypes.object,
router: PropTypes.object
@@ -18,7 +22,15 @@ export default class App extends Component {
}
}
+ componentDidCatch (error, info) {
+ error.stack = `${error.stack}\n\n${info.componentStack}`
+ window.next.renderError(error)
+ this.setState({ hasError: true })
+ }
+
render () {
+ if (this.state.hasError) return null
+
const { Component, props, hash, router } = this.props
const url = createUrl(router)
// If there no component exported we can't proceed.
diff --git a/package.json b/package.json
index 092be2607fd1f315527568e60b218d9c8e038d10..3c161dc8f760ab40f10bcc2516de3609e5d5beb6 100644
--- a/package.json
+++ b/package.json
@@ -127,15 +127,15 @@
"node-notifier": "5.1.2",
"nyc": "11.2.1",
"portfinder": "1.0.13",
- "react": "15.5.4",
- "react-dom": "15.5.4",
+ "react": "16.0.0",
+ "react-dom": "16.0.0",
"standard": "9.0.2",
"taskr": "1.1.0",
"wd": "1.4.1"
},
"peerDependencies": {
- "react": "^15.5.4",
- "react-dom": "^15.5.4"
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
},
"jest": {
"testEnvironment": "node",
diff --git a/test/integration/basic/test/rendering.js b/test/integration/basic/test/rendering.js
index 695c5b807437fafce3dd83d002f2f5ccf465ab45..db824b8116c26b445d9cf67047d76ba0225bd9d0 100644
--- a/test/integration/basic/test/rendering.js
+++ b/test/integration/basic/test/rendering.js
@@ -11,7 +11,7 @@ export default function ({ app }, suiteName, render) {
describe(suiteName, () => {
test('renders a stateless component', async () => {
const html = await render('/stateless')
- expect(html.includes('')).toBeTruthy()
+ expect(html.includes('')).toBeTruthy()
expect(html.includes('My component!')).toBeTruthy()
})
@@ -23,7 +23,7 @@ export default function ({ app }, suiteName, render) {
test('header helper renders header information', async () => {
const html = await (render('/head'))
- expect(html.includes('')).toBeTruthy()
+ expect(html.includes('')).toBeTruthy()
expect(html.includes('')).toBeTruthy()
expect(html.includes('I can haz meta tags')).toBeTruthy()
})