介绍
Next.js 是 React 服务端渲染应用框架. 用于构建 SEO 友好的 SPA 应用.
代码地址:https://github.com/qifutian/learngit/tree/main/react-ssr/next-guide
创建 Next.js 项目
创建: npm init next-app next-guide
运行: npm run dev
访问: localhost:3000
临时安装 create-next-app 用于创建 Next.js 项目.
基于页面的路由系统
创建页面组件
在 Next.js 中, 页面是被放置在 pages 文件夹中的 React 组件.
组件需要被默认导出.
组件文件中不需要引入 React.
页面地址与文件地址是对应的关系.
pages/index.js /
pages/list.js /list
pages/post/first.js /post/first
页面跳转
页面与页面之间通过 Link 组件进行跳转.link里需要包裹一个a组件
Link 组件默认使用 JavaScript 进行页面跳转. 即 SPA 形式的跳转.
如果浏览器中 JavaScript 被禁用. 则使用链接跳转.
Link 组件中不应添加除 href 属性以外的属性, 其余属性添加到a标签上.
Link 组件通过预取(在生产中)功能自动优化应用程序以获得最佳性能.
import Link from "next/link";
<Link href="/list">
<a className="demo">jump to list page</a>
</Link>
静态资源的访问
在next中,存在public文件夹,放置静态资源
通过以下形式进行访问.
public/images/1.jpg -> /images/1.jpg
public/css/base.css -> /css/base.css
修改页面元数据
每一个页面都拥有自己的css,head部分,通过引用Head组件完成
import Head from 'next/head'
<Head>
<title> Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
添加样式
内置 styled-jsx
在 Next.js 中内置了 styled-jsx, 它是一个 CSS-in-JS 库, 允许在 React 组件中编写 CSS, CSS 仅作用于组件内部.
CSS 模块
通过使用 CSS 模块功能, 允许将组件的 CSS 样式编写在单独的 CSS 文件中.
CSS 模块约定样式文件的名称必须为"组件文件名称.module.css"
全局样式文件
预渲染
预渲染是指数据和HTML的拼接在服务器端提前完成.
预渲染可以使 SEO 更加友好.
预渲染会带来更好的用户体验, 可以无需运行 JavaScript 即可查看应用程序UI.
预渲染的两种形式
在 Next.js 中支持两种形式的预渲染: 静态生成和服务器端渲染.
静态生成和服务器端渲染是生成 HTML 的时机不同.
静态生成: 静态生成是在构建时生成 HTML. 以后的每个请求都共用构建时生成好的 HTML.
服务器端渲染: 服务器端渲染是在请求时生成 HTML. 每个请求都会重新生成 HTML.
两种预渲染方式的选择
Next.js 允许开发者为每个页面选择不同的预渲染方式. 不同的预渲染方式拥有不同的特点. 应根据场景进行渲染.
但建议大多数页面建议使用静态生成.
静态生成一次构建, 反复使用, 访问速度快. 因为页面都是事先生成好的.
适用场景:营销页面、博客文章、电子商务产品列表、帮助和文档
服务器端渲染访问速度不如静态生成快, 但是由于每次请求都会重新渲染, 所以适用数据频繁更新的页面或页面内容随请求变化而变化的页面.
如何实现静态生成
无数据和有数据的静态生成
如果组件不需要在其他地方获取数据, 直接进行静态生成.
如果组件需要在其他地方获取数据, 在构建时 Next.js 会预先获取组件需要的数据, 然后再对组件进行静态生成.
开发环境不会静态生成,需要npm run build 之后生成页面的静态生成,在.next下的server/static/pages下是生成的网页代码
静态生成 getStaticProps
服务器端渲染 getServerSideProps
服务端渲染构建next应用时候不去生成html,在服务端接收到请求时候在生成html
如果采用服务器端渲染, 需要在组件中导出 getServerSideProps 方法.
基于参数为页面组件生成HTML页面,有多少参数就生成多少HTML页面
在构建应用时, 先获取用户可以访问的所有路由参数, 再根据路由参数获取具体数据, 然后根据数据生成静态 HTML.
实现基于动态路由的静态生成
注: getStaticPaths 和 getStaticProps 只运行在服务器端, 永远不会运行在客户端, 甚至不会被打包到客户端 JavaScript 中, 意味着这里可以随意写服务器端代码, 比如查询数据库.
访问post/1等会触发
[id].js
import {
useRouter } from 'next/router';
export default function Post ({
data}) {
const router = useRouter();
if (router.isFallback) return <div>loading</div>;
return <div>
<span>{
data.id}</span>
<span>{
data.title}</span>
</div>
}
// 返回用户可以访问到的所有的路由参数
export async function getStaticPaths () {
return {
paths: [{
params: {
id: "1"}}, {
params: {
id: "2"}}],
fallback: true
}
}
// 返回路由参数所对应的具体的数据
export async function getStaticProps ({
params}) {
console.log('Hello');
const id = params.id;
let data;
switch (id) {
case "1":
data = {
id: "1", title: 'Hello'};
break;
case "2":
data = {
id: "2", title: 'world'};
break;
case "3":
data = {
id: "3", title: 'hello world'};
break;
default:
data = {
}
}
return {
props: {
data
}
}
}
自定义 404 页面
要创建自定义 404 页面, 需要在 pages 文件夹中创建 404.js 文件.
export default function Custom404 () {
return <div>404</div>;
}
API Routes
什么是 API Routes
API Routes 可以理解为接口, 客户端向服务器端发送请求获取数据的接口.
Next.js 应用允许 React 开发者编写服务器端代码创建数据接口.
实现 API Routes
在 pages/api 文件夹中创建 API Routes 文件. 比如 user.js
在文件中默认导出请求处理函数, 函数有两个参数, req 为请求对象, res 为响应对象.
注: 当前 API Routes 可以接收任何 Http 请求方法.
访问 API Routes: localhost:3000/api/user
不要在 getStaticPaths 或 getStaticProps 函数中访问 API Routes, 因为这两个函数就是在服务器端运行的, 可以直接写服务器端代码.
npm init next-app movie
npm install @chakra-ui/core@next
npx chakra-cli init --theme 克隆主题
配置主题
在pages下新建_app.js
_app.js 默认导出根组件
_app.js
import {
ChakraProvider, CSSReset } from "@chakra-ui/core";
import theme from "../chakra";
export default function App({
Component, pageProps }) {
return (
<ChakraProvider theme={
theme}>
<CSSReset />
<Component {
...pageProps} />
</ChakraProvider>
);
}
npm install react-icons @emotion/core @emotion/styled
下载babel预置 npm install @emotion/babel-preset-css-prop --save-dev
在根目录下创建预设 .babelrc
{
"presets": ["next/babel","@emotion/babel-preset-css-prop"]
}
进行 npm run dev启动项目
新建components/Header.js 头部导航组件
import {
Box, Container, Button, Image } from "@chakra-ui/core";
import styled from "@emotion/styled";
import {
css } from "@emotion/core";
import {
FaSignInAlt, FaSearch } from "react-icons/fa";
import {
BsFillPersonFill } from "react-icons/bs";
const logo = css`
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 140px;
`;
const SignInAndJoin = styled.div`
height: 52px;
line-height: 52px;
border-left: 1px solid #393939;
border-right: 1px solid #393939;
padding: 0 6px;
float: left;
color: #fff;
& > button {
padding: 0 10px;
font-size: 12px;
}
& > button:nth-of-type(1):after {
content: "";
width: 1px;
height: 10px;
background: #fff;
position: absolute;
right: 0;
top: 16px;
}
`;
const Search = styled.a`
float: right;
height: 52px;
border-left: 1px solid #393939;
border-right: 1px solid #393939;
color: #fff;
font-size: 20px;
padding: 0 10px;
display: flex;
align-items: center;
`;
export default function Header() {
return (
<Box h={
52} bgColor="#202020" borderBottom="1px solid #393939">
<Container h={
52} maxW={
1200} pos="relative">
<SignInAndJoin>
<Button colorScheme="transparent" leftIcon={
<FaSignInAlt />}>
登录
</Button>
<Button colorScheme="transparent" leftIcon={
<BsFillPersonFill />}>
注册
</Button>
</SignInAndJoin>
<Image css={
logo} src="/images/logo.png" />
<Search>
<FaSearch />
</Search>
</Container>
</Box>
);
}
在pages/index.js中进行引用
创建Navigation.js
import {
Box, HStack } from "@chakra-ui/core";
import Link from "next/link";
export default function Navigation() {
return (
<Box h={
52} bgColor="#202020" color="#FFF">
<HStack h={
52} spacing={
3} justifyContent="center" alignItems="center">
<Link href="#">
<a>影片</a>
</Link>
<Link href="#">
<a>漫画</a>
</Link>
<Link href="#">
<a>电影</a>
</Link>
<Link href="#">
<a>电视</a>
</Link>
<Link href="#">
<a>新闻</a>
</Link>
</HStack>
</Box>
);
}
导出到pages/index.js
npm i react-responsive-carousel
创建Swiper.js并添加引用
import {
Carousel } from "react-responsive-carousel";
import Head from "next/head";
import {
css } from "@emotion/core";
import styled from "@emotion/styled";
import {
Box, Heading, Text, Button } from "@chakra-ui/core";
import axios from "axios";
import {
baseURL } from "../axiosConfig";
import Link from 'next/link';
const CarouselItem = styled.div`
position: relative;
& > div {
position: absolute;
left: 50%;
top: 0;
transform: translateX(-50%);
color: #fff;
padding-top: 180px;
text-align: left;
width: 100%;
max-width: 1200px;
& > p {
margin: 15px 0;
font-size: 14px;
width: 450px;
}
}
& > img {
filter: brightness(50%);
}
`;
const swiperContainer = css`
position: relative;
& > .carousel:last-child {
position: absolute;
left: 0;
bottom: 0;
& > .thumbs-wrapper > .thumbs {
display: flex;
justify-content: center;
}
}
`;
export default function Swiper({
data }) {
return (
<>
<Head>
<link rel="stylesheet" href="/css/carousel.min.css" />
</Head>
<Carousel
css={
swiperContainer}
showArrows={
false}
showIndicators={
false}
showStatus={
false}
>
{
data.map(swiper => (
<CarouselItem key={
swiper.id}>
<img src={
swiper.url} />
<Box>
<Heading as="h2" size="lg">
{
swiper.title}
</Heading>
<Text>
{
swiper.description}
</Text>
<Button colorScheme="red">
<Link href="/detail/[id]" as={
`/detail/${
swiper.vid}`}><a>CHECK DETAIL</a></Link>
</Button>
</Box>
</CarouselItem>
))}
</Carousel>
</>
);
}
export function loadSwiper() {
return axios.get("/api/swiper", {
baseURL });
}
创建个node服务器,提供几个接口
import express from "express";
import cors from 'cors';
const app = express();
app.use(cors());
app.use(express.static('public'));
const url = "http://localhost:3005";
const videos = [
{
id: "1",
title:
"It's an Event-Sized Episode of 'Marvel Presents: The World's Greatest Book Club with Paul Scheer' in Celebration of 'Empyre'",
sub:
"Paul Scheer and Steve Wacker are joined by Anthony Carboni of 'The Star Wars Show'!",
author: "JAMIE FREVELE",
publish: "2050-05-26",
content:
"Time for a new episode of Marvel Presents: The World's Greatest Book Club with Paul Scheer -- and this one, Marvelites, is super-sized! Why? Because there's a new Marvel comic event in our midst, and EMPYRE deserves no less than a big celebration with hosts Paul Scheer and Steve Wacker! Paul and Steve are joined by guest Anthony Carboni (The Star Wars Show) for a calamitous conversation about other notable Marvel events.
But first -- EMPYRE! Steve provided an inside look at the creation of the intergalactic conflict and what Marvel fans can expect:
“What [writers Al Ewing and Dan Slott] definitely wanted to get away from was making it a [Fantastic Four] versus the Avengers, yet another story where friends fight each other and try to kill each other. Much like this show.”
He went on to predict the lasting effects of EMPYRE on the Marvel Universe:
“There are some big changes coming, and I think when we’re in our sweet spot is when we at Marvel are a little nervous about how the fans are going to react. It’s our job to put them through the ringer, to put them through hell. I think EMPYRE is not the story at the beginning that you think it is.”
"
},
{
id: "2",
title: "Time Travel Tips from 'Marvel's Agents of S.H.I.E.L.D.'",
sub:
"Traveling back in time is never easy? Let us help by consulting the pros!",
author: "CHRISTINE DINH",
publish: "2050-03-13",
content:
"
Look, we all know hopping through the decades ain't easy. In fact, who can keep up with all the different rules of time travel.
Luckily, we know a bunch of experts. During the production of Marvel's Agents of S.H.I.E.L.D. Season 7, Marvel.com had the opportunity to consult the cast and showrunners how to remain composure while navigating time travel. Watch what they have to say, learn the Do's and Don't's, and word of advice, it's probably best to avoid the shenanigans of Deke Shaw. We haven't forgotten the events of Season 6, Deke .
"
},
{
id: "3",
title:
"The Next Shocking Chapter in Donny Cates and Ryan Stegman's Venom Saga Revealed",
sub: "'King in Black' conquers the Marvel Universe this December!",
author: "MARVEL",
publish: "2060-08-30",
content:
"This December, the entire Marvel Universe braces itself for KING IN BLACK, the latest installment in writer Donny Cates and artist Ryan Stegman’s revolutionary take on the Venom mythos. Knull is coming, and when he arrives, everyone from the Avengers to the X-Men will learn just how unprepared they are to face off against the God of the Symbiotes. Everything in Cates and Stegman’s landmark run on VENOM has led up to this monumental story, and readers will finally witness Eddie Brock’s climatic standoff with one of Marvel’s most terrifying villains.

With each mind-bending twist and turn, the stakes will be raised like never before as KING IN BLACK flips everything you thought you knew about Venom and the world of the symbiotes upside down and inside out. Learn more in the special video announcement from the mastermind creative team, and stay tuned for more news about what to expect when KING IN BLACK lands later this year!
"
},
{
id: "4",
title:
"Livestream: Let's Play LIVE: Fortnite Featuring the Captain America Outfit",
sub: "Follow along LIVE TODAY at 1pm PT / 4pm ET!",
author: "MARVEL",
publish: "2050-09-05",
content:
"Tune in to Marvel's Official Twitch Channel at 4:00 PM ET (1:00 PM PT) today to join Marvel host Josh Saleh as he channels the First Avenger – Captain America – who made his debut on Fortnite last week!
Follow along with Josh, and be sure to grab the Captain America Outfit in the Item Shop. Armed with his indestructible shield and iron will, Super-Soldier Steve Rogers won’t give up until the mission is finished.
Want to stay on top of everything in the Marvel Universe? Follow Marvel on social media—Twitter, Facebook, and Instagram—and keep watching Marvel.com for more news!
"
},
{
id: "5",
title: "Celebrate Ultraman Day with a Sneak Peek at 'Rise of Ultraman #1'",
sub: "Happy Ultraman Day!",
author: "MARVEL",
publish: "2080-09-28",
content:
"Ultraman has been a pop culture icon for over 50 years and this September, Marvel Comics will proudly contribute to the franchise’s incredible legacy with RISE OF ULTRAMAN #1!
Writers Kyle Higgins (Mighty Morphin Power Rangers, Winter Soldier) and Mat Groom (Self/Made) will join superstar artists Francesco Manna (Avengers, Fantastic Four) Michael Cho (Captain America) and Gurihiru (The Unstoppable Wasp) to reimagine the thrilling beginnings of the Ultraman phenomenon.
In honor of Ultraman Day, the celebration of Ultraman’s first public television appearance in 1966, check out a first look at the highly anticipated premiere issue including exclusive preview pages, a variant cover gallery, and more below!

Stay tuned for more news about Marvel’s exciting collaboration with Tsuburaya Productions and don’t miss THE RISE OF ULTRAMAN #1 when it hits stands September 9th!
"
},
{
id: "6",
title: "Marvel Mission Recap: Captain Marvel’s Star of Hala",
sub: "The results are out of this world!",
author: "RACHEL PAIGE",
publish: "2046-05-23",
content:
"Congrats agents — it appears that many of you successfully completed the latest Marvel Mission!

Tasked to bring Captain Marvel’s Star of Hala to life using only safe household products and materials, the results we saw were outstanding and would make Carol Danvers and the Carol Corps proud!
While it was tough to narrow down all the submissions we received, we’ve rounded up some of our favorites that we saw across social media. Take a look at the post below, and though this Marvel Mission might be closed, there’s always time to make a star for yourself!
"
},
{
id: "7",
title: "Make Your Video Calls Worthy With These Backgrounds",
sub: "Video call backgrounds, assemble!",
author: "RACHEL PAIGE",
publish: "2028-12-25",
content:
"Hey Marvel Insiders – did you know reading this article could earn you 250 points? All you need to do is sign in or join now before you keep reading!
Taking a video call in your living space with your regular home background is typical, mundane, and not at all dangerous.
But taking a video call with an Avengers approved background is exciting, heroic, and will definitely make your co-workers think you’re working from Asgard.
As more and more communication for work, fun, and play happens over our computer screens, we’ve assembled some video call backgrounds that you can use. Taking some of the Marvel Cinematic Universe's most iconic locations, have fun swapping out the backdrop of your kitchen for a sweeping landscape of Wakanda. Check out the backgrounds you can download below!


To download the images: Right-click on the selected background of your choice and select SAVE IMAGE AS. The image will download to your desktop and you can insert it into the video conferencing program of your choice. Enjoy!
By downloading the images you agree to be bound by the terms located here.
Want to stay on top of everything in the Marvel Universe? Follow Marvel on social media—Twitter, Facebook, and Instagram—and keep watching Marvel.com for more news!
"
},
{
id: "8",
title:
"Everything We Saw During the First 'Marvel’s Avengers' WAR TABLE Livestream",
sub: "Get ready to Embrace Your Powers on September 4!",
author: "CHRISTINE DINH",
publish: "2048-05-10",
content:
"Marvel Games, Square Enix, and Crystal Dynamics launched the very first Marvel’s Avengers WAR TABLE stream today. The Marvel’s Avengers WAR TABLE, which will be a monthly offering, gives players an in-depth look at many different aspects of the highly-anticipated game before it launches on September 4.
Opening up the Marvel’s Avengers WAR TABLE was the release of the brand-new story trailer narrated by the game’s central villain, Dr. George Tarleton. Tarleton joins the previously announced Taskmaster as another antagonist in the Avengers’ story.
Opening up the Marvel’s Avengers WAR TABLE was the release of the brand-new story trailer narrated by the game’s central villain, Dr. George Tarleton. Tarleton joins the previously announced Taskmaster as another antagonist in the Avengers’ story.
Marvel fans will recognize that Tarleton is none other than MODOK (Mental Organism Designed Only for Killing) – the artificially-mutated, super intelligent founder of AIM (Advanced Idea Mechanics). The story behind how Tarleton becomes MODOK is central to the game and one we’re eager to hear more about along with who voiced the deadly villain!
MODOK believes in AIM’s mission – fixing the damage the Avengers did, all those years ago on A-Day, by instilling order, ruling by science, and creating boundaries on what he reveals as the true threat to this world – the Inhumans disease. Taking his mission to the extreme, MODOK aims to rid the Earth of superpowers seeing it as a force that cannot be controlled or contained!
The Hero Missions allow Marvel’s Avengers to reveal more of each hero’s story, showcasing a variety of their narrative and backstory. Each hero has 3 iconic heroic moves: Assault, Ultimate, and Support. Learn more about these heroic moves and attacks for the Avengers by rewatching the Marvel’s Avengers WAR TABLE at the top of the article.
"
},
{
id: "9",
title:
"Marvel At Home: Here’s How to Stay Connected With Your Favorite Super Heroes",
sub: "Here's everything that's happening at the House of Ideas for fans!",
author: "RACHEL PAIGE",
publish: "2082-06-25",
content:
"We’re constantly dreaming up new ways to connect with readers, viewers, and fans at the House of Ideas and now, with everyone spending more time at home than ever, there are even more ways to bring Marvel into your home — wherever your home might be!

Over the past month, we’ve worked to bring fans a chance to escape within the Marvel Universe, and if you haven’t already, there are so many ways to experience #MarvelAtHome. Whether you’re spending the day working, entertaining family members, or catching up on reading (or watching), here are some of the ways we’re keeping you connected to your favorite Super Heroes.
Wondering what it takes to bring Marvel characters to life on the page? Well, first you have to start with pencils and paper and the pros will show you what to do next! Follow along as we learn how to draw iconic characters like Spider-Man, Groot, and Wolverine and stay tuned to see who’s next!
"
}
];
// 轮播图
app.get("/api/swiper", (req, res) => {
res.send([
{
id: 1,
title: "Event-Sized Episode!",
description:
"Paul Scheer and Steve Wacker are joined by Anthony Carboni of 'The Star Wars Show' for an event sized episode!",
url: `${
url}/api/images/api_swiper_1.jpg`,
vid: 1
},
{
id: 2,
title: "Time Travel Tips",
description:
"Traveling back in time is never easy? Let us help by consulting the pros!",
url: `${
url}/api/images/api_swiper_2.jpg`,
vid: 2
},
{
id: 3,
title: "KING IN BLACK",
description:
"The next shocking chapter in Donny Cates and Ryan Stegman's Venom Saga is revealed!",
url: `${
url}/api/images/api_swiper_3.jpg`,
vid: 3
},
{
id: 4,
title: "LET'S PLAY FORTNITE",
description:
"Watch as we stream the brand new Captain America outfit in Fortnite!",
url: `${
url}/api/images/api_swiper_4.jpg`,
vid: 4
},
{
id: 5,
title: "HAPPY ULTRAMAN DAY!",
description:
"Celebrate by getting a sneak peek at 'Rise of Ultraman #1'!",
url: `${
url}/api/images/api_swiper_5.jpg`,
vid: 5
}
]);
});
// 电影列表
app.get("/api/movie", (req, res) => {
res.send([
{
id: 1,
vid: 6,
url: `${
url}/api/images/api_movie_1.jpg`,
title: "Marvel Mission Recap: Captain Marvel’s Star of Hala"
},
{
id: 2,
vid: 7,
url: `${
url}/api/images/api_movie_2.jpg`,
title: "Make Your Video Calls Worthy With These Backgrounds"
},
{
id: 3,
vid: 8,
url: `${
url}/api/images/api_movie_3.jpg`,
title: "Make Your Video Calls Worthy With These Backgrounds"
},
{
id: 4,
vid: 9,
url: `${
url}/api/images/api_movie_4.jpg`,
title:
"Marvel At Home: Here’s How to Stay Connected With Your Favorite Super Heroes"
}
]);
});
// 电影详情
app.get("/api/detail", (req, res) => {
const id = req.query.id;
const result = videos.find(video => video.id === id);
res.send(result);
});
// 获取电影id集合
app.get('/api/videos', (req, res) => {
res.send(videos.map(video => video.id));
});
app.listen(3005, () => console.log("app is running on port 3005"));
在页面中请求3035的接口,通过getStaticProps方法得到axios.get获取的数据
导出静态网站,在package.json中添加命令
"scripts": {
"dev": "nodemon server/index.js",
"build": "next build",
"start": "next start",
"export": "next build && next export"
},
运行npm run export,会生成out文件夹,就是生成的网站
只要把out内容复制到服务端下,在访问服务器的地址就可以访问到
在项目下新建server/index.js文件,存放node-express代码
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production'
const app = next({
dev});
const handler = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.get('/hello', (req, res) => {
res.send('Hello Next.js')
});
server.get('*', (req, res) => {
handler(req, res)
});
server.listen(3000, () => console.log('服务器启动成功'));
});
需要在github创建新的仓库
将仓库地址复制,在Vercel上进行注册账号,选择github登录,在点击import Project导入一个项目,在将地址复制上,在点击Visit查看部署成功的地址