mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
5fcb49632e
* Introduce better debug error handling With this we are rendering runtime and debug errors inside a it's own error root. That gives us better error handling and control. Also, now we are patching React core to capture runtime errors. * Render the initial error on the server.
102 lines
2.8 KiB
JavaScript
102 lines
2.8 KiB
JavaScript
import React, { Component, PropTypes } from 'react'
|
|
import { AppContainer } from 'react-hot-loader'
|
|
import shallowEquals from './shallow-equals'
|
|
import { warn } from './utils'
|
|
|
|
const ErrorDebug = process.env.NODE_ENV === 'production'
|
|
? null : require('./error-debug').default
|
|
|
|
export default class App extends Component {
|
|
static childContextTypes = {
|
|
headManager: PropTypes.object
|
|
}
|
|
|
|
getChildContext () {
|
|
const { headManager } = this.props
|
|
return { headManager }
|
|
}
|
|
|
|
render () {
|
|
const { Component, props, hash, router } = this.props
|
|
const url = createUrl(router)
|
|
// If there no component exported we can't proceed.
|
|
// We'll tackle that here.
|
|
if (typeof Component !== 'function') {
|
|
throw new Error(`The default export is not a React Component in page: "${url.pathname}"`)
|
|
}
|
|
const containerProps = { Component, props, hash, router, url }
|
|
|
|
return <div>
|
|
<Container {...containerProps} />
|
|
</div>
|
|
}
|
|
}
|
|
|
|
class Container extends Component {
|
|
componentDidMount () {
|
|
this.scrollToHash()
|
|
}
|
|
|
|
componentDidUpdate () {
|
|
this.scrollToHash()
|
|
}
|
|
|
|
scrollToHash () {
|
|
const { hash } = this.props
|
|
const el = document.getElementById(hash)
|
|
if (el) {
|
|
// If we call scrollIntoView() in here without a setTimeout
|
|
// it won't scroll properly.
|
|
setTimeout(() => el.scrollIntoView(), 0)
|
|
}
|
|
}
|
|
|
|
shouldComponentUpdate (nextProps) {
|
|
// need this check not to rerender component which has already thrown an error
|
|
return !shallowEquals(this.props, nextProps)
|
|
}
|
|
|
|
render () {
|
|
const { Component, props, url } = this.props
|
|
|
|
// includes AppContainer which bypasses shouldComponentUpdate method
|
|
// https://github.com/gaearon/react-hot-loader/issues/442
|
|
return <AppContainer errorReporter={ErrorDebug}>
|
|
<Component {...props} url={url} />
|
|
</AppContainer>
|
|
}
|
|
}
|
|
|
|
function createUrl (router) {
|
|
return {
|
|
query: router.query,
|
|
pathname: router.pathname,
|
|
back: () => {
|
|
warn(`Warning: 'url.back()' is deprecated. Use "window.history.back()"`)
|
|
router.back()
|
|
},
|
|
push: (url, as) => {
|
|
warn(`Warning: 'url.push()' is deprecated. Use "next/router" APIs.`)
|
|
return router.push(url, as)
|
|
},
|
|
pushTo: (href, as) => {
|
|
warn(`Warning: 'url.pushTo()' is deprecated. Use "next/router" APIs.`)
|
|
const pushRoute = as ? href : null
|
|
const pushUrl = as || href
|
|
|
|
return router.push(pushRoute, pushUrl)
|
|
},
|
|
replace: (url, as) => {
|
|
warn(`Warning: 'url.replace()' is deprecated. Use "next/router" APIs.`)
|
|
return router.replace(url, as)
|
|
},
|
|
replaceTo: (href, as) => {
|
|
warn(`Warning: 'url.replaceTo()' is deprecated. Use "next/router" APIs.`)
|
|
const replaceRoute = as ? href : null
|
|
const replaceUrl = as || href
|
|
|
|
return router.replace(replaceRoute, replaceUrl)
|
|
}
|
|
}
|
|
}
|