2017-04-10 18:35:26 +00:00
|
|
|
import React, { Component } from 'react'
|
|
|
|
import PropTypes from 'prop-types'
|
2017-01-12 01:58:20 +00:00
|
|
|
import shallowEquals from './shallow-equals'
|
2017-03-06 18:14:10 +00:00
|
|
|
import { warn } from './utils'
|
2016-10-05 23:52:50 +00:00
|
|
|
|
|
|
|
export default class App extends Component {
|
|
|
|
static childContextTypes = {
|
|
|
|
headManager: PropTypes.object
|
|
|
|
}
|
|
|
|
|
2017-01-12 01:58:20 +00:00
|
|
|
getChildContext () {
|
|
|
|
const { headManager } = this.props
|
|
|
|
return { headManager }
|
2016-10-05 23:52:50 +00:00
|
|
|
}
|
|
|
|
|
2017-01-12 01:58:20 +00:00
|
|
|
render () {
|
2017-04-01 21:03:40 +00:00
|
|
|
const { Component, props, hash, router } = this.props
|
2017-03-06 16:48:35 +00:00
|
|
|
const url = createUrl(router)
|
2017-03-23 04:10:22 +00:00
|
|
|
// 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}"`)
|
|
|
|
}
|
2017-03-06 16:48:35 +00:00
|
|
|
const containerProps = { Component, props, hash, router, url }
|
2016-10-05 23:52:50 +00:00
|
|
|
|
2017-01-12 01:58:20 +00:00
|
|
|
return <div>
|
|
|
|
<Container {...containerProps} />
|
|
|
|
</div>
|
2016-10-05 23:52:50 +00:00
|
|
|
}
|
2017-01-12 01:58:20 +00:00
|
|
|
}
|
2016-10-05 23:52:50 +00:00
|
|
|
|
2017-01-12 01:58:20 +00:00
|
|
|
class Container extends Component {
|
2017-02-28 17:31:17 +00:00
|
|
|
componentDidMount () {
|
|
|
|
this.scrollToHash()
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate () {
|
|
|
|
this.scrollToHash()
|
|
|
|
}
|
|
|
|
|
|
|
|
scrollToHash () {
|
|
|
|
const { hash } = this.props
|
2017-06-09 21:45:37 +00:00
|
|
|
if (!hash) return
|
|
|
|
|
2017-02-28 17:31:17 +00:00
|
|
|
const el = document.getElementById(hash)
|
2017-06-09 21:45:37 +00:00
|
|
|
if (!el) return
|
|
|
|
|
|
|
|
// If we call scrollIntoView() in here without a setTimeout
|
|
|
|
// it won't scroll properly.
|
|
|
|
setTimeout(() => el.scrollIntoView(), 0)
|
2017-02-28 17:31:17 +00:00
|
|
|
}
|
|
|
|
|
2017-01-12 01:58:20 +00:00
|
|
|
shouldComponentUpdate (nextProps) {
|
|
|
|
// need this check not to rerender component which has already thrown an error
|
|
|
|
return !shallowEquals(this.props, nextProps)
|
2016-10-05 23:52:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
2017-03-06 16:48:35 +00:00
|
|
|
const { Component, props, url } = this.props
|
2016-10-14 15:05:08 +00:00
|
|
|
|
2017-07-01 07:24:16 +00:00
|
|
|
if (process.env.NODE_ENV === 'production') {
|
|
|
|
return (<Component {...props} url={url} />)
|
|
|
|
} else {
|
|
|
|
const ErrorDebug = require('./error-debug').default
|
|
|
|
const { AppContainer } = require('react-hot-loader')
|
|
|
|
|
|
|
|
// includes AppContainer which bypasses shouldComponentUpdate method
|
|
|
|
// https://github.com/gaearon/react-hot-loader/issues/442
|
|
|
|
return (
|
|
|
|
<AppContainer errorReporter={ErrorDebug}>
|
|
|
|
<Component {...props} url={url} />
|
|
|
|
</AppContainer>
|
|
|
|
)
|
|
|
|
}
|
2016-10-05 23:52:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-12 01:58:20 +00:00
|
|
|
function createUrl (router) {
|
|
|
|
return {
|
2016-10-05 23:52:50 +00:00
|
|
|
query: router.query,
|
2017-03-06 18:14:10 +00:00
|
|
|
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)
|
|
|
|
}
|
2016-10-05 23:52:50 +00:00
|
|
|
}
|
|
|
|
}
|