2016-10-05 23:52:50 +00:00
|
|
|
import React, { Component, PropTypes } from 'react'
|
2016-10-14 15:05:08 +00:00
|
|
|
import { AppContainer } from 'react-hot-loader'
|
2016-12-19 21:04:38 +00:00
|
|
|
import { warn } from './utils'
|
2016-10-05 23:52:50 +00:00
|
|
|
|
|
|
|
export default class App extends Component {
|
|
|
|
static childContextTypes = {
|
|
|
|
router: PropTypes.object,
|
|
|
|
headManager: PropTypes.object
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor (props) {
|
|
|
|
super(props)
|
|
|
|
this.state = propsToState(props)
|
|
|
|
this.close = null
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillReceiveProps (nextProps) {
|
|
|
|
const state = propsToState(nextProps)
|
|
|
|
try {
|
|
|
|
this.setState(state)
|
|
|
|
} catch (err) {
|
2017-01-05 17:27:39 +00:00
|
|
|
this.handleError(err)
|
2016-10-05 23:52:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount () {
|
|
|
|
const { router } = this.props
|
|
|
|
|
2016-10-08 05:12:51 +00:00
|
|
|
this.close = router.subscribe((data) => {
|
|
|
|
const props = data.props || this.state.props
|
2016-10-05 23:52:50 +00:00
|
|
|
const state = propsToState({
|
2016-10-08 05:12:51 +00:00
|
|
|
...data,
|
2016-10-14 15:05:08 +00:00
|
|
|
props,
|
2016-10-06 07:08:23 +00:00
|
|
|
router
|
2016-10-05 23:52:50 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.setState(state)
|
|
|
|
} catch (err) {
|
2017-01-05 17:27:39 +00:00
|
|
|
this.handleError(err)
|
2016-10-05 23:52:50 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount () {
|
|
|
|
if (this.close) this.close()
|
|
|
|
}
|
|
|
|
|
|
|
|
getChildContext () {
|
|
|
|
const { router, headManager } = this.props
|
|
|
|
return { router, headManager }
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
|
|
|
const { Component, props } = this.state
|
2016-10-14 15:05:08 +00:00
|
|
|
|
|
|
|
return <AppContainer>
|
2016-10-17 02:10:16 +00:00
|
|
|
<Component {...props} />
|
2016-10-14 15:05:08 +00:00
|
|
|
</AppContainer>
|
2016-10-05 23:52:50 +00:00
|
|
|
}
|
2017-01-05 17:27:39 +00:00
|
|
|
|
|
|
|
async handleError (err) {
|
|
|
|
console.error(err)
|
|
|
|
|
|
|
|
const { router, ErrorComponent } = this.props
|
|
|
|
const { pathname, query } = router
|
|
|
|
const props = await ErrorComponent.getInitialProps({ err, pathname, query })
|
|
|
|
const state = propsToState({ Component: ErrorComponent, props, router })
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.setState(state)
|
|
|
|
} catch (err2) {
|
|
|
|
console.error(err2)
|
|
|
|
}
|
|
|
|
}
|
2016-10-05 23:52:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function propsToState (props) {
|
|
|
|
const { Component, router } = props
|
|
|
|
const url = {
|
|
|
|
query: router.query,
|
|
|
|
pathname: router.pathname,
|
|
|
|
back: () => router.back(),
|
2016-12-19 18:49:15 +00:00
|
|
|
push: (url, as) => router.push(url, as),
|
2016-12-17 20:18:50 +00:00
|
|
|
pushTo: (href, as) => {
|
2016-12-19 21:04:38 +00:00
|
|
|
warn(`Warning: 'url.pushTo()' is deprecated. Please use 'url.push()' instead.`)
|
2016-12-17 20:18:50 +00:00
|
|
|
const pushRoute = as ? href : null
|
|
|
|
const pushUrl = as || href
|
|
|
|
|
|
|
|
return router.push(pushRoute, pushUrl)
|
|
|
|
},
|
2016-12-19 18:49:15 +00:00
|
|
|
replace: (url, as) => router.replace(url, as),
|
2016-12-17 20:18:50 +00:00
|
|
|
replaceTo: (href, as) => {
|
2016-12-19 21:04:38 +00:00
|
|
|
warn(`Warning: 'url.replaceTo()' is deprecated. Please use 'url.replace()' instead.`)
|
2016-12-17 20:18:50 +00:00
|
|
|
const replaceRoute = as ? href : null
|
|
|
|
const replaceUrl = as || href
|
|
|
|
|
|
|
|
return router.replace(replaceRoute, replaceUrl)
|
|
|
|
}
|
2016-10-05 23:52:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
Component,
|
|
|
|
props: { ...props.props, url }
|
|
|
|
}
|
|
|
|
}
|