b274fe39d3
* Update to use separate export instead of attaching to Component to identify GS(S)P pages * Handle initialProps being undefined
126 lines
3.6 KiB
TypeScript
126 lines
3.6 KiB
TypeScript
import React, { ErrorInfo } from 'react'
|
|
import {
|
|
execOnce,
|
|
loadGetInitialProps,
|
|
AppContextType,
|
|
AppInitialProps,
|
|
AppPropsType,
|
|
} from '../next-server/lib/utils'
|
|
import { Router } from '../client/router'
|
|
|
|
export { AppInitialProps }
|
|
|
|
export type AppContext = AppContextType<Router>
|
|
|
|
export type AppProps<P = {}> = AppPropsType<Router, P>
|
|
|
|
/**
|
|
* `App` component is used for initialize of pages. It allows for overwriting and full control of the `page` initialization.
|
|
* This allows for keeping state between navigation, custom error handling, injecting additional data.
|
|
*/
|
|
async function appGetInitialProps({
|
|
Component,
|
|
ctx,
|
|
}: AppContext): Promise<AppInitialProps> {
|
|
const pageProps = await loadGetInitialProps(Component, ctx)
|
|
return { pageProps }
|
|
}
|
|
|
|
export default class App<P = {}, CP = {}, S = {}> extends React.Component<
|
|
P & AppProps<CP>,
|
|
S
|
|
> {
|
|
static origGetInitialProps = appGetInitialProps
|
|
static getInitialProps = appGetInitialProps
|
|
|
|
// Kept here for backwards compatibility.
|
|
// When someone ended App they could call `super.componentDidCatch`.
|
|
// @deprecated This method is no longer needed. Errors are caught at the top level
|
|
componentDidCatch(error: Error, _errorInfo: ErrorInfo): void {
|
|
throw error
|
|
}
|
|
|
|
render() {
|
|
const { router, Component, pageProps, __N_SSG, __N_SSP } = this
|
|
.props as AppProps<CP>
|
|
|
|
return (
|
|
<Component
|
|
{...pageProps}
|
|
{
|
|
// we don't add the legacy URL prop if it's using non-legacy
|
|
// methods like getStaticProps and getServerSideProps
|
|
...(!(__N_SSG || __N_SSP) ? { url: createUrl(router) } : {})
|
|
}
|
|
/>
|
|
)
|
|
}
|
|
}
|
|
|
|
let warnContainer: () => void
|
|
let warnUrl: () => void
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
warnContainer = execOnce(() => {
|
|
console.warn(
|
|
`Warning: the \`Container\` in \`_app\` has been deprecated and should be removed. https://err.sh/zeit/next.js/app-container-deprecated`
|
|
)
|
|
})
|
|
|
|
warnUrl = execOnce(() => {
|
|
console.error(
|
|
`Warning: the 'url' property is deprecated. https://err.sh/zeit/next.js/url-deprecated`
|
|
)
|
|
})
|
|
}
|
|
|
|
// @deprecated noop for now until removal
|
|
export function Container(p: any) {
|
|
if (process.env.NODE_ENV !== 'production') warnContainer()
|
|
return p.children
|
|
}
|
|
|
|
export function createUrl(router: Router) {
|
|
// This is to make sure we don't references the router object at call time
|
|
const { pathname, asPath, query } = router
|
|
return {
|
|
get query() {
|
|
if (process.env.NODE_ENV !== 'production') warnUrl()
|
|
return query
|
|
},
|
|
get pathname() {
|
|
if (process.env.NODE_ENV !== 'production') warnUrl()
|
|
return pathname
|
|
},
|
|
get asPath() {
|
|
if (process.env.NODE_ENV !== 'production') warnUrl()
|
|
return asPath
|
|
},
|
|
back: () => {
|
|
if (process.env.NODE_ENV !== 'production') warnUrl()
|
|
router.back()
|
|
},
|
|
push: (url: string, as?: string) => {
|
|
if (process.env.NODE_ENV !== 'production') warnUrl()
|
|
return router.push(url, as)
|
|
},
|
|
pushTo: (href: string, as?: string) => {
|
|
if (process.env.NODE_ENV !== 'production') warnUrl()
|
|
const pushRoute = as ? href : ''
|
|
const pushUrl = as || href
|
|
|
|
return router.push(pushRoute, pushUrl)
|
|
},
|
|
replace: (url: string, as?: string) => {
|
|
if (process.env.NODE_ENV !== 'production') warnUrl()
|
|
return router.replace(url, as)
|
|
},
|
|
replaceTo: (href: string, as?: string) => {
|
|
if (process.env.NODE_ENV !== 'production') warnUrl()
|
|
const replaceRoute = as ? href : ''
|
|
const replaceUrl = as || href
|
|
|
|
return router.replace(replaceRoute, replaceUrl)
|
|
},
|
|
}
|
|
}
|