这是一份快速参考备忘单,包含 Next.js 的 API 参考列表和一些示例
npx create-next-app@latest
# or
yarn create next-app
# or
pnpm create next-app
或者创建 TypeScript 项目
npx create-next-app@latest --typescript
# or
yarn create next-app --typescript
# or
pnpm create next-app --typescript
运行 npm run dev
或 yarn dev
或 pnpm dev
以在 http://localhost:3000 上启动开发服务器
使用以下内容填充 pages/index.js
:
function HomePage() {
return <div>Welcome to Next.js!</div>
}
export default HomePage
Next.js
是围绕页面的概念构建的。 页面是从 pages
目录中的 .js
、.jsx
、.ts
或 .tsx
文件导出的 React
组件
function Page({ data }) {
// 渲染数据...
}
// 每个请求都会调用它
export async function getServerSideProps() {
// 从外部 API 获取数据
const res = await fetch(`https://.../data`)
const data = await res.json()
// 通过 props 向页面传递数据
return { props: { data } }
}
export default Page
如果您从页面导出一个名为 getServerSideProps
(服务器端渲染)的函数,Next.js
将使用 getServerSideProps
返回的数据在每个请求上预渲染该页面
getServerSideProps
在请求时运行,此页面将使用返回的 props 进行预渲染next/link
或 next/router
在客户端页面转换上请求此页面时,Next.js
会向服务器发送 API 请求,服务器运行 getServerSideProps
// pages/posts/[id].js
export async function getStaticPaths() {
// 当这是真的时(在预览环境中)不要预呈现任何静态页面(更快的构建,但更慢的初始页面加载)
if (process.env.SKIP_BUILD_STATIC_GENERATION) {
return {
paths: [],
fallback: 'blocking',
}
}
// 调用外部 API 端点以获取帖子
const res = await fetch('https://.../posts')
const posts = await res.json()
// 根据帖子获取我们要预渲染的路径 在生产环境中,预渲染所有页面
// (构建速度较慢,但初始页面加载速度较快)
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// { fallback: false } 表示其他路由应该 404
return { paths, fallback: false }
}
如果页面具有动态路由并使用 getStaticProps
,则需要定义要静态生成的路径列表
getStaticProps
生成 HTML 和 JSON 文件,这两种文件都可以由 CDN 缓存以提高性能// 帖子将在构建时由 getStaticProps() 填充
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
// 这个函数在服务器端的构建时被调用。
// 它不会在客户端调用,因此您甚至可以直接进行数据库查询。
export async function getStaticProps() {
// 调用外部 API 端点以获取帖子。 您可以使用任何数据获取库
const res = await fetch('https://.../posts')
const posts = await res.json()
// 通过返回 { props: { posts } },Blog 组件将在构建时接收 `posts` 作为 prop
return {
props: {
posts,
},
}
}
export default Blog
在服务器端的构建时被调用
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
// 这个函数在服务器端的构建时被调用
// 如果启用了重新验证并且有新请求进入,它可能会在无服务器功能上再次调用
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
// Next.js 将尝试重新生成页面:
// - 当请求进来时
// - 最多每 10 秒一次
revalidate: 10, // 片刻之间
}
}
// 这个函数在服务器端的构建时被调用
// 如果尚未生成路径,则可能会在无服务器函数上再次调用它
export async function getStaticPaths() {
const res = await fetch('https://.../posts')
const posts = await res.json()
// 根据帖子获取我们要预渲染的路径
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// 我们将在构建时仅预渲染这些路径
// { fallback: blocking } 如果路径不存在,服务器将按需呈现页面
return { paths, fallback: 'blocking' }
}
export default Blog
import { useState, useEffect } from 'react'
function Profile() {
const [data, setData] = useState(null)
const [isLoading, setLoading] = useState(false)
useEffect(() => {
setLoading(true)
fetch('/api/profile-data')
.then((res) => res.json())
.then((data) => {
setData(data)
setLoading(false)
})
}, [])
if (isLoading) return <p>Loading...</p>
if (!data) return <p>No profile data</p>
return (
<div>
<h1>{data.name}</h1>
<p>{data.bio}</p>
</div>
)
}
import useSWR from 'swr'
const fetcher = (...args) => fetch(...args).then((res) => res.json())
function Profile() {
const { data, error } = useSWR('/api/profile-data', fetcher)
if (error) return <div>Failed to load</div>
if (!data) return <div>Loading...</div>
return (
<div>
<h1>{data.name}</h1>
<p>{data.bio}</p>
</div>
)
}
Next.js 可以在根目录中名为 public
的文件夹下提供静态文件,如图像。 然后,您的代码可以从基本 URL (/
) 开始引用 public
中的文件
import Image from 'next/image'
function Avatar() {
return (
<Image
src="/me.png"
alt="me"
width="64"
height="64"
/>
)
}
export default Avatar
Next.js 支持零配置的现代浏览器
Next.js 支持在 package.json
文件中配置 Browserslist
{
"browserslist": [
"chrome 64",
"edge 79",
"firefox 67",
"opera 51",
"safari 12"
]
}
如果不存在,请创建一个 pages/_app.js
文件。 然后,导入 styles.css
文件
import '../styles.css';
// 在新的“pages/_app.js”文件中需要此默认导出
export default function MyApp({
Component, pageProps
}) {
return <Component {...pageProps} />
}
例如,考虑以下名为 styles.css
的样式表
body {
font-family:
'SF Pro Text', 'SF Pro Icons',
'Helvetica Neue', 'Helvetica',
'Arial', sans-serif;
margin: 0 auto;
}
对于全局样式表,如 bootstrap
或 nprogress
,您应该在 pages/_app.js
中导入文件
// pages/_app.js
import 'bootstrap/dist/css/bootstrap.css'
export default function MyApp({
Component, pageProps
}) {
return <Component {...pageProps} />
}
从 node_modules
导入 CSS 文件
您无需担心 .error {} 与任何其他 .css
或 .module.css
文件!他将被生成 hash
名称
.error {
color: white;
background-color: red;
}
然后,创建 components/Button.js
,导入并使用上面的 CSS 文件:
import styles from './Button.module.css'
export function Button() {
return (
<button
type="button"
// 请注意“error”类
// 是如何作为导入的“styles”对象的属性访问的
className={styles.error}
>
Destroy
</button>
)
}
Next.js 允许您使用 .scss
和 .sass
扩展名导入 Sass,可以通过 CSS 模块和 .module.scss
或 .module.sass
扩展名使用组件级 Sass
$ npm install --save-dev sass
在使用 Next.js 的内置 Sass
支持之前,请务必sass
通过在 next.config.js
中使用 sassOptions
来实现配置 Sass
编译器。例如添加 includePaths
:
const path = require('path')
module.exports = {
sassOptions: {
includePaths:
[path.join(__dirname, 'styles')],
},
}
/* variables.module.scss */
$primary-color: #64ff00;
:export {
primaryColor: $primary-color;
}
在 pages/_app.js
中导入 variables.module.scss
import variables from '../styles/variables.module.scss'
export default function MyApp({ Component, pageProps }) {
return (
<Layout color={variables.primaryColor}>
<Component {...pageProps} />
</Layout>
)
}
最简单的一种是内联样式:
function HiThere() {
return (
<p style={{ color: 'red' }}>hi 这里</p>
)
}
export default HiThere
使用 styled-jsx 的组件如下所示:
function HelloWorld() {
return (
<div>
Hello world
<p>scoped!</p>
<style jsx>{`
p { color: blue; }
div { background: red; }
@media (max-width: 600px) {
div { background: blue; }
}
`}</style>
<style global jsx>{`
body { background: black; }
`}</style>
</div>
)
}
export default HelloWorld
当然,你也可以使用 styled-components
// components/layout.js
import Navbar from './navbar'
import Footer from './footer'
export default function Layout({ children }) {
return (
<>
<Navbar />
<main>{children}</main>
<Footer />
</>
)
}
// pages/_app.js
import Layout from '../components/layout'
export default function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
// pages/index.tsx
import type { ReactElement } from 'react'
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
import type { NextPageWithLayout } from './_app'
const Page: NextPageWithLayout = () => {
return <p>hello world</p>
}
Page.getLayout = function getLayout(page: ReactElement) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
export default Page
// pages/_app.tsx
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: ReactElement) => ReactNode
}
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout
}
export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
// 使用在页面级别定义的布局(如果可用)
const getLayout = Component.getLayout ?? ((page) => page)
return getLayout(<Component {...pageProps} />)
}
// pages/index.js
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
export default function Page() {
return (
/** Your content */
)
}
Page.getLayout = function getLayout(page) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
// pages/_app.js
export default function MyApp({ Component, pageProps }) {
// 使用在页面级别定义的布局(如果可用)
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
// components/layout.js
import useSWR from 'swr'
import Navbar from './navbar'
import Footer from './footer'
export default function Layout({ children }) {
const { data, error } = useSWR('/api/navigation', fetcher)
if (error) return <div>Failed to load</div>
if (!data) return <div>Loading...</div>
return (
<>
<Navbar links={data.links} />
<main>{children}</main>
<Footer />
</>
)
}
import Image from 'next/image'
import profilePic from '../public/me.png'
function Home() {
return (
<>
<h1>My Homepage</h1>
<Image
src={profilePic}
alt="Picture of the author"
// width={500} 自动提供
// height={500} 自动提供
// blurDataURL="data:..." 自动提供
// placeholder="blur" // 加载时可选的模糊处理
/>
<p>Welcome to my homepage!</p>
</>
)
}
import Image from 'next/image'