Next.js used in this tutorial is version 13
Introduction to Next.js
- Complete React project, easy to build
- Comes with data synchronization to solve the biggest difficulty in server-side rendering
- Rich plug-ins
- Flexible configuration
Create first project
Create manually
initialization
npm init
Install required dependency packages
npm install --save react react-don next
Add shortcut commands
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "next",
"build": "next build",
"start": "next start"
},
Create test file
Create the pages folder in the root directory and create index.js under this file
The pages folder is specified by Next. For files written in this folder, Next.js will automatically create corresponding routes.
function Index() {
return (
<div>Halo Next.js</div>
)
}
export default Index
Run npm run dev
creact-next-app scaffolding to create Next.js projects
create project
npx create-next-app@latest
When creating a project for the first time, if nextjs is not installed, you will be prompted whether to install it.
What is your project named? my-app // 项目名
Would you like to use TypeScript? No / Yes // TypeScript
Would you like to use ESLint? No / Yes // ESLint
Would you like to use Tailwind CSS? No / Yes // Tailwind CSS
Would you like to use `src/` directory? No / Yes // src 作为根目录
Would you like to use App Router? (recommended) No / Yes // 路由
Would you like to customize the default import alias? No / Yes // 自定义默认导入别名
What import alias would you like configured? @/* // 配置什么导入别名
Run npm run dev
Next.js page and component
Create a new page
Create about.js in the page directory
function About () {
return (
<div>About nextjs</div>
)
}
export default About
Visit http://localhost:3000/about
In Next.js, a page (page) is a React component exported from .js
, jsx
, .ts
or files . These files are stored in the directory. Each page uses its file name as a route.tsx
pages
Create a secondary directory page
Create a home file in the page directory and create home.js under this file
function Home () {
return (
<div>home nextjs</div>
)
}
export default Home
Visit http://localhost:3000/home/home
Production of Component components
Create component
Create the components directory in the src directory and create the buttonComponent.js file in this directory
export default ({children})=><button>{children}</button>
quote
Introduced in home.js
import dynamic from 'next/dynamic'
const ButtonComponent = dynamic(
() => import('@/components/buttonComponent'),
// { ssr: false } // 是否关闭 ssr(服务端渲染) 默认是开启
)
use
<ButtonComponent>按钮</ButtonComponent>
routing
Tabbed jump
Add two new pages to the home page
homeA.js
import React from "react";
import Link from "next/link";
const HomeA = () => {
return (
<>
<div>我是HomeA 页面</div>
<div><Link href="/home/home"><div>去Home页面</div></Link></div>
</>
)
}
export default HomeA
homeB.js
import React from "react";
import Link from "next/link";
const HomeB = () => {
return (
<>
<div>我是HomeB 页面</div>
<div><Link href="/home/home"><div>去Home页面</div></Link></div>
</>
)
}
export default HomeB
Modify home page content
import React from "react"
import Link from "next/link"
function Home () {
return (
<div>
<div>home nextjs</div>
<div><Link href="/home/homeA"><div>去homeA页面</div></Link></div>
<div><Link href="/home/homeB"><div>去homeB页面</div></Link></div>
</div>
)
}
export default Home
In earlier versions, the a tag must be connected to the Link tag. In the current version (13.4.19), if you add the a tag, an error will be reported.
Router module jumps (programmatic jump)
Modify home.js page
import React from "react"
import Router from "next/router"
const goHomeA = () => {
Router.push('/home/homeA')
}
const goHomeB = () => {
Router.push('/home/homeB')
}
function Home () {
return (
<div>
<div>home nextjs</div>
<div onClick={goHomeA}>去homeA页面</div>
<div onClick={goHomeB}>去homeB页面</div>
</div>
)
}
export default Home
Send and receive
Next.js can only pass parameters through query
Labeled
Modify home.js page
import React from "react"
import Link from "next/link"
function Home () {
return (
<div>
<div>home nextjs</div>
<div><Link href="/home/homeA?name=张三&age=18"><div>张三</div></Link></div>
<div><Link href="/home/homeA?name=李四&age=20"><div>李四</div></Link></div>
</div>
)
}
export default Home
Modify homeA.js page
withRouter is an advanced component of the Next.js framework, used to handle routing
import React from "react";
import Link from "next/link";
import { withRouter } from "next/router";
function Home () {
return (
<div>
<div>home nextjs</div>
<div><Link href="/home/homeA?name=张三&age=18"><div>写法一</div></Link></div>
<div><Link href={
{
pathname: '/home/homeA',
query: {
name: '李四',
age: 20
}
}}><div>写法二</div></Link></div>
</div>
)
}
export default withRouter(HomeA)
Programmatic
import React from "react"
import Router from "next/router"
const goHomeA = () => {
Router.push('/home/homeA?name=张三&age=18')
}
const goHomeA2 = () => {
Router.push({
pathname: '/home/homeA',
query: {
name: '李四',
age: 20
}
})
}
function Home () {
return (
<div>
<div>home nextjs</div>
<div onClick={goHomeA}>写法一</div>
<div onClick={goHomeA2}>写法二</div>
</div>
)
}
export default Home
hook function
History
import React from "react"
import Router from "next/router"
Router.events.on('routeChangeStart', (...args) => {
console.log('routeChangeStart -> 路由开始变化', ...args)
})
Router.events.on('routeChangeComplete', (...args) => {
console.log('routeChangeComplete -> 路由结束变化', ...args)
})
Router.events.on("beforeHistoryChange", (...args) => {
console.log('beforeHistoryChange -> 在改变浏览器 history 之前触发', ...args)
})
Router.events.on('routeChangeError', (...args) => {
console.log('routeChangeError -> 跳转发生错误', ...args)
})
const goHomeA = () => {
Router.push('/home/homeA?name=张三&age=18')
}
const goHomeA2 = () => {
Router.push({
pathname: '/home/homeA',
query: {
name: '李四',
age: 20
}
})
}
function Home () {
return (
<div>
<div>home nextjs</div>
<div onClick={goHomeA}>写法一</div>
<div onClick={goHomeA2}>写法二</div>
</div>
)
}
export default Home
Hash
Router.events.on('hashChangeStart', (...args) => {
console.log('hashChangeStart -> 路由开始变化', ...args)
})
Router.events.on('hashChangeComplete', (...args) => {
console.log('hashChangeComplete -> 路由结束变化', ...args)
})
Get remote data in getInitialProps
getInitialProps
React
It is a static method hung on the component
If you are using Next.js 9.3 or higher, we recommend that you use getStaticProps
or getServerSideProps
instead getInitialProps
.
The official recommendation is fetch
fetch request
Create a new request.js page in the page directory
import { withRouter } from "next/router";
function Request ({router, data}) {
return (
<>
<div>{router.name}</div>
<div>请求页面 {data} </div>
</>
)
}
Request.getInitialProps = async () => {
const res = await fetch('https://api.github.com/repos/vercel/next.js')
const json = await res.json()
console.log(json)
return { stars: json.stargazers_count }
}
export default withRouter(Request)
index.js
import Router from "next/router"
const goRequest = () => {
Router.push({
pathname: '/request',
query: {
name: '李四',
age: 20
}
})
}
export default function Home() {
return (
<>
<div>首页</div>
<div onClick={goRequest}>去Request页面</div>
</>
)
}
When you run the page, you can find that getInitialProps
it will be executed during server rendering and client rendering.
- When the page is accessed directly through page refresh, etc., it will be triggered to
Nextjs
use server-side rendering to return the page data.
At this time getInitialProps
, it will be executed on the server side and will not be executed on the browser side.
- When a page is accessed through a browser-side routing jump (such as the browser going forward or backward), the rendering of the page will not trigger
Nextjs
server-side rendering.
So in fact, getInitialProps
the method will independently choose to execute on the Node side or the Client side according to the different terminals when the current page is rendered.
getStaticProps
getStaticProps
will be requested on every page visit
Modify request.js
import { withRouter } from "next/router";
function Request ({router, content}) {
return (
<>
<div>{router.name}</div>
<div>请求页面 {content} </div>
</>
)
}
export const getStaticProps = async () => {
const res = await fetch('https://api.github.com/repos/vercel/next.js')
const json = await res.json()
console.log(json)
return {
props: {
content: json.stargazers_count
}
};
};
export default withRouter(Request)
getStaticProps is an API for pre-executing the processing performed by getInitialProps at build time and pre-generating static files. Will not run on the client. Always run on the server side.
getServerSideProps
import { withRouter } from "next/router";
function Request ({router, content}) {
return (
<>
<div>{router.name}</div>
<div>请求页面 {content} </div>
</>
)
}
export const getServerSideProps = async context => {
const res = await fetch('https://api.github.com/repos/vercel/next.js')
// if (!res) {
// notFound 强制页面跳转到 404
// return {
// notFound: true
// };
// redirect 来将页面重定向
// return {
// redirect: {
// destination: '/',
// permanent: false
// }
// };
// }
const json = await res.json()
console.log(json)
return {
props: {
content: json.stargazers_count
}
};
}
export default withRouter(Request)
Through next.js
, getServerSideProps
we can coordinate the front-end and back-end data very well during development. Some page initialization data and page authentication can be getServerSideProps
processed directly in , which can greatly simplify the page logic and ensure the unity of the front-end and back-end.
JSX writes the CSS style of the page
Basic writing method
Create a new style.js page
const Style = () => {
return (
<>
<div>style 页面</div>
<div className="base">基础</div>
<style jsx>
{`
.base {
color: blue;
font-size: 16px;
margin: 40px;
display: block;
}
`}
</style>
</>
)
}
export default Style
It should be noted that if jsx is required after style, next.js will automatically add a random class name to prevent global pollution of CSS. For example, the base of the above code will become base-xxxxxx
Dynamic styles
Modify style.js page
import React, {useState} from "react"
const Style = () => {
const [color, setColor] = useState('blue')
const [fontSize, setFontSize] = useState('16')
const [margin, setMargin] = useState('40')
const changeColor = () => {
setColor(color === 'blue' ? 'red': 'blue')
}
const changeFontSize = () => {
setFontSize(fontSize === '16' ? '20': '16')
}
const changeMargin = () => {
setMargin(margin === '10' ? '40': '10')
}
return (
<>
<div>style 页面</div>
<div className="base">基础</div>
<button onClick={changeColor}>改颜色</button>
<button onClick={changeFontSize}>改字体大小</button>
<button onClick={changeMargin}>改边距</button>
<style jsx>
{`
.base {
color: ${color};
font-size: ${fontSize}px;
margin: ${margin}px;
display: block;
}
`}
</style>
</>
)
}
export default Style
Module lazy loading
Create a new import.js page
Introduce dayjs library
npm i dayjs
If we introduce it directly on the page, it will be packaged and released in the form of a public library. Even if the first page of the project is not used, it will moment
be loaded. This is a waste of resources.
Lazy loading of introduced third-party libraries
import.js
import React,{useState} from "react";
const Import = () => {
const [time, setTime] = useState()
const changeTime = async () => {
const dayjs = await import('dayjs')
setTime(dayjs.default(Date.now()).format('YYYY-MM-DD HH:mm:ss'))
}
return (
<>
<div>import 页面</div>
<div>当前时间为:{time}</div>
<button onClick={changeTime}>获取当前时间</button>
</>
)
}
export default Import
You can see that we introduced it where needed
Be careful to use default to take effect
Lazy loading of components
Use dynamic to introduce component implementation
import dynamic from 'next/dynamic'
const ButtonComponent = dynamic(() => import('@/components/buttonComponent'))
const Import = () => {
return (
<>
<div>import 页面</div>
<ButtonComponent>按钮</ButtonComponent>
</>
)
}
export default Import
Custom components are lazy loaded. They will only be loaded when they are jsx
used . If they are not used, they will not be loaded.<ButtonComponent/>
head component
In order to better perform SEO optimization, you can customize <Head>
the tags yourself.
Create header.js page
Next.js
It has been <Head>
encapsulated. It is a component in itself and can be directly
import Head from 'next/head'
const Header = ()=>{
return (
<>
<Head>
<title> 头部 </title>
</Head>
</>
)
}
export default Header
Using Ant Design UI under Next.js framework
Ant Design is an Alibaba open source front-end component library
From the perspective of React, it is a component library that encapsulates some of the most commonly used components in development, allowing us to use them through simple configuration.
Let Next.js support importing CSS files
First create pages/_app.js (if it doesn't exist). Then import the styles.css
file.
Global properties of style sheets
The old version can support css through @zeit/next-sass , this has been removed in the new version
Next.js [name].module.css
supports CSS modules through file naming conventions
CSS modules scope CSS by automatically creating unique class names. This allows you to use the same CSS class name in different files without worrying about conflicts.
This behavior makes CSS modules an ideal way to include component-level CSS. CSS module files can be imported anywhere in the application
If the module next.js framework is not added, it will be mistaken for a global style, which will cause conflicts and errors.
import styles from '@/styles/test.module.css'
const Ant = () => {
return (
<>
<div>Ant 页面</div>
<p className={styles.default}>测试</p>
</>
)
}
export default Ant
Support scss
Install scss
npm install sass
Usage is consistent with css
import styles from '@/styles/test.module.scss'
const Ant = () => {
return (
<>
<div>Ant 页面</div>
<p className={styles.default}>测试</p>
</>
)
}
export default Ant
Install ant
npm install antd --save
Introduce ant and use
Create a new react.js page
import React from 'react';
import { DatePicker } from 'antd';
const App = () => {
return <DatePicker />;
};
export default App;
babel
In order to prevent webpack
the entire Ant Design
package from being packaged into the production environment
We need you to use babel
npm install --save babel-plugin-import
.babelrc
Create a file in the project root directory
{
"presets":["next/babel"], //Next.js的总配置文件,相当于继承了它本身的所有配置
"plugins":[ //增加新的插件,这个插件就是让antd可以按需引入,包括CSS
[
"import",
{
"libraryName":"antd"
}
]
]
}
In this way, when we use that component, we package that component. Similarly, CSS is also packaged on demand.
Next.js production environment packaging
Configure package.json folder
"start": "next start -p 8088"
Run packaging
npm run build
Run the packaged file
npm run start