這篇文章將介紹Next.js中自定義App組件、Document組件以及何時須要自定義這些內容,這可能會是咱們每一個項目中都要作的事情,So,讓咱們一塊兒掌握它吧。javascript
Tips: 按照慣例聲明,筆者也是個入門級選手,文章深度沒法達到大佬級文章水平,只但願能對各位入門級的小夥伴有所幫助。css
首先說一下爲何要自定義App,這裏的App其實就是咱們平時寫react時候的根組件。 1)經過重寫
_app.js
文件,咱們能夠對App組件進行重構,在App組件中加入一些項目中不變的內容,好比頁面的佈局;java2)在App中保持公用的狀態,這裏的公用狀態也能夠是一些全局的css,好比咱們以前搭建環境的文章中加入的
antd.css
;react3)以及給頁面傳遞自定義的數據,服務器
4)使用
componentDidCatch
自定義處理錯誤;antd5)注入額外數據到頁面裏 (如 GraphQL 查詢)app
在next.js+koa2+antd環境輕鬆搭建 一文中,咱們曾經寫過一個_app.js
來引入antd的css,在這裏咱們對除了引入antd.css
其餘事情什麼都沒作,引入antd.css以後,它就會在全局生效。frontend
import App from 'next/app'
import 'antd/dist/antd.css'
export default App
複製代碼
如今就來對它進行一些改變koa
import App, { Container } from 'next/app'
import 'antd/dist/antd.css'
// 新增了這一段
class MyApp extends App {
render() {
const { Component } = this.props;
console.log(Component);
return (
<Container> <Component /> </Container>
)
}
}
export default MyApp
複製代碼
對比這一段代碼,這裏從next/app
中多引入了一個Container
組件,並在中間從新寫了一個MyApp
類,繼承自App,最後將其返回。在MyApp
中,重寫了render
方法來渲染組件,其中從props中拿到的Component
組件就是在訪問每一個pages
下的js文件時候,這些文件返回的組件。想一想也是,在寫react的時候,其餘組件要顯示也是要包裹在最外層的App組件中的,這裏是同樣的道理。 值得注意的是,這裏的MyApp組件返回Component時候最外層要使用Comtainer
組件進行包裹。咱們能夠順手打印出Component,看看究竟是不是向咱們所說的同樣。 異步
重寫getInitialProps
不過如今並不算完成,咱們連App本來的功能還沒實現完整:在當前組件中,咱們是拿不到其餘頁面getInitialProps()
方法初始話的數據的,若是對getInitialProps()
不瞭解,請翻閱很簡單的next.js數據獲取規範或者官方文檔 這裏能夠給你們看一個例子
getInitialProps()
中定義的數據並無顯示出來
class MyApp extends App {
static getInitialProps = async ({Component}) => {
let pageProps;
if(Component.getInitialProps) {
pageProps = await Component.getInitialProps()
}
return {
pageProps
}
}
render() {
const { Component, pageProps } = this.props;
console.log(Component);
return (
<Container> <Component {...pageProps} /> </Container> ) } } 複製代碼
這裏在MyApp中新增了一個getInitialProps
方法,注意他是一個靜態方法
,因爲其餘頁面可能設置了getInitialProps
也可能沒有設置,因此這裏須要判斷一下,而且這個方法爲異步方法,執行時注意加上await
並在外層方法添加async
。這樣就能夠將其餘頁面中getInitialProps
設置的屬性引入過來,而且傳遞給Component
就能夠顯示了,來看看效果吧
管理全局數據舉例
state = {
counter: 20
}
複製代碼
例如在MyApp中定義counter,就能夠傳遞給全部組件 佈局示例 在components目錄下建立Layout.jsx
import Link from 'next/link';
import { Button } from 'antd'
export default ({ children }) => {
return (
<> <div className="header"> <Link href="/a?id=1"><Button>跳轉A</Button></Link> <Link href="/test/b"><Button>跳轉B</Button></Link> </div> <div className="body"> {children} </div> </> ) } 複製代碼
而後在_app.js中引用
return (
<Container> <Layout> <Component {...pageProps} /> </Layout> </Container> ) 複製代碼
這樣每一個頁面都會顯示Layout了
只有在服務器端渲染的時候纔會被調用,主要用來修改服務端渲染的文檔內容,一般實現服務端渲染會使用一些
css-in-js
庫(styled-jsx
是 Next.js自帶默認使用的css-in-js庫) 它在_document.js中定義
import Document, {Html, Head, Main, NextScript} from 'next/document'
class MyDocument extends Document {
render() {
return (
<Html> <Head> </Head> <body> <Main /> <NextScript /> </body> </Html>
)
}
}
export default MyDocument
複製代碼
在next/document
中提供的並不只是Document組件,還有一些跟HTML標籤對應的組件,在重寫的時候要記得都要寫上。
在Head中試着添加一些內容
<Head>
<title>My Next.js</title>
<style>{`* { color: red}`}</style>
</Head>
複製代碼
設置getInitialProps
再說明一下,document只有在服務端渲染時候纔會執行。
在重寫Docuemnt的時候,咱們也能夠重寫getInitialProps
方法,這個getInitialProps來自於Document組件。
static getInitialProps = async (ctx) => {
const props = await Document.getInitialProps(ctx)
return {
...props
}
}
複製代碼
這裏的getInitialProps也是個靜態方法,而且也要加async,由於裏面使用了await,而且注意有個參數ctx
,咱們能夠不重寫它,可是若是咱們要重寫就要按照這個格式來重寫,而後在裏面再添加本身想要的東西。
本文內容是比較簡單的,可是很重要,在使用next.js開發項目中是要常用的,因此仍是掌握好它吧。在後面集成
css in js
樣式文章中可能還會再比較詳細地描述在_docuemnt.js中咱們能夠乾點什麼,但願對入門級小夥伴有所幫助。