forked from vercel/next.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.js
129 lines (111 loc) · 3 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import shallowEquals from './shallow-equals'
import { execOnce, warn, loadGetInitialProps } from './utils'
import { makePublicRouterInstance } from './router'
export default class App extends Component {
static childContextTypes = {
_containerProps: PropTypes.any,
headManager: PropTypes.object,
router: PropTypes.object
}
static displayName = 'App'
static async getInitialProps ({ Component, router, ctx }) {
const pageProps = await loadGetInitialProps(Component, ctx)
return {pageProps}
}
getChildContext () {
const { headManager } = this.props
return {
headManager,
router: makePublicRouterInstance(this.props.router),
_containerProps: {...this.props}
}
}
// Kept here for backwards compatibility.
// When someone ended App they could call `super.componentDidCatch`. This is now deprecated.
componentDidCatch (err) {
throw err
}
render () {
const {router, Component, pageProps} = this.props
const url = createUrl(router)
return <Container>
<Component {...pageProps} url={url} />
</Container>
}
}
export class Container extends Component {
static contextTypes = {
_containerProps: PropTypes.any
}
componentDidMount () {
this.scrollToHash()
}
shouldComponentUpdate (nextProps) {
// need this check not to rerender component which has already thrown an error
return !shallowEquals(this.props, nextProps)
}
componentDidUpdate () {
this.scrollToHash()
}
scrollToHash () {
const { hash } = this.context._containerProps
if (!hash) return
const el = document.getElementById(hash)
if (!el) return
// If we call scrollIntoView() in here without a setTimeout
// it won't scroll properly.
setTimeout(() => el.scrollIntoView(), 0)
}
render () {
return this.props.children
}
}
const warnUrl = execOnce(() => {
if (process.env.NODE_ENV !== 'production') {
warn(`Warning: the 'url' property is deprecated. https://err.sh/zeit/next.js/url-deprecated`)
}
})
export function createUrl (router) {
// This is to make sure we don't references the router object at call time
const {pathname, asPath, query} = router
return {
get query () {
warnUrl()
return query
},
get pathname () {
warnUrl()
return pathname
},
get asPath () {
warnUrl()
return asPath
},
back: () => {
warnUrl()
router.back()
},
push: (url, as) => {
warnUrl()
return router.push(url, as)
},
pushTo: (href, as) => {
warnUrl()
const pushRoute = as ? href : null
const pushUrl = as || href
return router.push(pushRoute, pushUrl)
},
replace: (url, as) => {
warnUrl()
return router.replace(url, as)
},
replaceTo: (href, as) => {
warnUrl()
const replaceRoute = as ? href : null
const replaceUrl = as || href
return router.replace(replaceRoute, replaceUrl)
}
}
}