如何使用NextJS开发网站?尽管像 React 这样的现代基于 Javascript 的前端框架帮助我们开发了强大的动态网站,但它们有一个主要缺点:客户端必须等到所有 Javascript 代码加载后才能呈现页面并向用户显示内容。由于页面的加载速度会显着影响其用户体验和搜索引擎排名,这已成为 Web 开发中的主要问题
Next.js 是一个基于 React 的框架,为这个问题提供了解决方案。它承诺使用一组易于使用的功能(包括预渲染)来提高网站的性能。考虑到开发者社区在框架发布后的短时间内蜂拥而至,可以肯定地说 Next 毫无保留地兑现了这一承诺。
因此,我们决定在本教程中向你介绍 Next.js,该框架正迅速成为开发人员的最爱。让我们了解 Next 如何通过提高性能和简化开发过程来改进 React,包括详细的NextJS网站开发示例。
Next.js 的主要特点
NextJS用法示例介绍:与 React 这样的框架相比,Next.js 最突出的特性是预渲染。如上所述,在接收到 Javascript 代码后在客户端渲染网页是一个缓慢的过程。Next 通过向客户端发送每个页面的预渲染版本来解决这个问题。
它使用三种类型的预渲染。他们是:
- 静态站点生成
- 服务端渲染
- 增量静态再生
虽然静态站点生成最适合构建静态网页,但服务器端渲染适合具有动态内容的页面。Next 的特殊之处在于它允许你分别决定为每个网页使用哪种渲染类型。
除了预渲染之外,Next 还提供了一组精心设计的功能来简化如下所列的开发过程。
- 自动打包和代码拆分:与在 React 中必须设置 Webpack 以手动打包代码不同,Next.js 会使用 Webpack 自动打包代码。它还支持基于单独路由和动态导入的代码拆分。它减少了网页和动态组件的加载时间。= 图像优化:Next 原生支持按需调整图像大小和优化图像。你可以将其与默认的延迟加载选项配对以获得最佳性能。
- 快速刷新:当开发过程中代码发生变化时,立即重新渲染组件。
Next 入门
如何使用NextJS开发网站?要开始使用 Next,你应该 在你的设备上安装 Node.js 和 npm。安装完成后,你可以继续构建新的 Next 应用程序。
使用创建下一个应用程序
Next 提供了一个create-next-app
类似于的工具,create-react-app
用于快速设置项目文件夹和环境。以下是调用create-next-app
操作的方法。
npx create-next-app
按照提示添加应用程序名称后,该命令将创建一个项目文件夹并安装必要的包(next、react 和 react-dom)。它还使用以下内容设置 package.json 文件:
{
"name": "first-next-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "11.0.1",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"eslint": "7.30.0",
"eslint-config-next": "11.0.1"
}
}
手动设置下一个应用程序
你还可以手动设置 Next 应用程序,而无需借助 create-next-app。为此,首先,创建一个项目目录并使用npm init
. 然后,使用以下 npm 命令安装必要的软件包。
npm install next, react, react-dom
使用以下内容更新 package.json 的脚本部分。
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
},
- 在开发脚本运行在开发模式下的应用程序。
- 在启动脚本运行在生产模式下的应用程序。
- 在构建脚本编译和构建应用程序。
我们将在本教程中假设一个手动设置的项目,以帮助你了解创建 Next 应用程序的背景详细信息。
将页面添加到下一个应用程序
NextJS网站开发示例:在 Next.js 中,页面是存储在名为“pages”的目录中的文件。每个页面都与 Web 应用程序中的一个路由相关联,并为该特定路由导出一个 React 组件。
例如,带有文件路径的页面pages/products/display.js
应该存储/products/display
路由为访问者呈现的 React 组件。具有名称的页面与pages/products/index.js
路由相关联/products
。
因此,要开始向 Web 应用程序添加页面,你应该首先创建一个名为pages.
Then的目录,你应该在该目录中添加一个 index.js 文件以关联/
Web 应用程序的路由。
在我们的第一页上,我们可以导出一个向访问者显示“Hello World”的简单组件,如下所示。
const Home = () => (
<div>
<h1>Hello World!</h1>
</div>
);
export default Home;
现在,我们可以使用以下命令在开发模式下启动 Next 应用程序。
npm run dev
它在端口 3000 上构建并启动我们的应用程序。你可以使用 URL http://localhost:3000/ 访问其主页。
遵循类似的模式,你可以向应用程序添加更多页面。
NextJS用法示例:页面之间的链接
Next 提供了一个名为“Link”的 React 组件来确保链接页面之间的最佳转换。尽管可以使用常规锚标记来连接页面,但 Next 的 Link 组件通过防止客户端重新导入两个页面共有的包来加快操作速度。
为了演示链接功能,首先,我们需要向我们的 Web 应用程序添加另一个页面。为此,我们将在 pages 目录中创建一个新的 about.js 文件,并向其中添加以下代码。
//about.js
const About = () => (
<div>
<h3>About Us</h3>
<p>We strive to provide the best services to you</p>
</div>
);
export default About;
保存更改后,Next 会自动使用新组件重建应用程序。你可以使用 URL http://localhost:3000/about 访问该页面。
现在,我们应该提供一个链接到网站主页上的关于页面。这是我们如何实现这一目标。
import Link from "next/link";
const Home = () => (
<div>
<h1>Hello World!</h1>
<Link href="/about"><a>Learn more about us</a></Link>
</div>
);
export default Home;
如何使用NextJS开发网站:动态链接
如果你想使用动态路由链接页面怎么办?Next 在动态页面名称和路由器的帮助下使这个任务变得非常简单。
还记得 Next 如何在 Web 应用程序中使用页面名称作为路由吗?同样,Next 允许我们创建具有与动态路由相关的动态名称的页面。
例如,考虑像/shows/[tvshow]
. 此动态路由根据电视节目更改 URL(例如:/shows/game-of-thrones、shows/friends)。
接下来允许我们为这条路线中的所有电视节目创建一个通用模板。我们称它们为动态页面。动态页面的名称遵循以下格式:pages/shows/[tvshow].js
.
然后,我们可以使用 Next 路由器提取动态 URL 中的信息并呈现页面以适合每个电视节目。
让我们通过创建一个名为 的页面来开始这个实现pages/shows/[tvshow].js
。在这个文件中,我们应该创建一个路由器对象来检索 URL 参数。然后,我们可以返回包含与此参数相关的信息的组件。
import {useRouter} from "next/router";
const TVShow = () => {
const router = useRouter();
const tvshow = router.query.tvshow;
return (
<div>
<h3>{tvshow}</h3>
</div>
);
}
export default TVShow
现在我们已经设置了动态页面内容,我们可以在网站的主页上提供指向不同电视节目的链接。
import Link from "next/link";
const Home = () => (
<div>
<h1>Hello World!</h1>
<p>Popular TV Shows</p>
<ul>
<li>
<Link href={`/shows/game-of-thrones`}><a>Game of Thrones</a></Link>
</li>
<li>
<Link href={`/shows/friends`}><a>Friends</a></Link>
</li>
<li>
<Link href={`/shows/westworld`}><a>Westworld</a></Link>
</li>
</ul>
<Link href="/about"><a>Learn more about us</a></Link>
</div>
);
export default Home;
现在,我们的主页显示了电视节目列表,并带有将它们连接到动态路由的链接:
当我们单击其中一个链接时,它会呈现 [tvshow].js 页面,其中包含与每个电视节目相关的内容。
在下一节中,让我们看看如何从远程 API 获取数据以显示更多电视节目数据。
NextJS网站开发示例:获取数据
Next 提供了三种不同的方法来从远程 API 获取数据。他们是getStaticProps
,getStaticPaths
和getServerSideProps
。
让我们通过从TV Maze API检索电视节目数据来了解每种数据获取方法的差异 。
NextJS用法示例:getStaticProps
这个函数应该用在静态生成的页面上,因为它在构建时获取数据。当我们在与 React 组件相同的页面上声明一个异步 getStaticProps 函数时,它会接收检索到的数据作为属性。
让我们使用此方法从 TV Maze API 检索最近的电视节目列表以显示在主页上。
//index.js
export async function getStaticProps() {
const res = await fetch("https://api.tvmaze.com/shows?page=1");
const data = await res.json();
return { props: { data } }
}
Home 组件现在可以使用返回的数据来显示电视节目名称列表。下面是我们如何修改组件来实现这一点。
//index.js
import Link from "next/link";
const Home = ({data}) => (
<div>
<h1>Hello World!</h1>
<p>Popular TV Shows</p>
<ul>
{data.map(tvshow => {
return (
<li>
<Link href={`/shows/${tvshow.id}`}><a>{tvshow.name}</a></Link>
</li>
);
})}
</ul>
<Link href="/about"><a>Learn more about us</a></Link>
</div>
);
export async function getStaticProps() {
const res = await fetch("https://api.tvmaze.com/shows?page=1");
const data = await res.json();
return { props: { data } }
}
export default Home;
每个电视节目的动态链接现在使用节目 ID 而不是其名称shows/[tvshow-id]
。我们的主页现在看起来像这样:
getStaticPaths
getStaticPaths 也用于静态生成,特别是动态路由。
如何使用NextJS开发网站?在具有动态路由的页面中,它们显示的内容取决于用于访问该页面的 URL。例如,如果用户访问 /shows/123,他们应该会看到一个使用 ID 为 123 的电视节目中的数据呈现的页面。由于 Next 在静态生成的构建期间预呈现这些页面,因此它应该知道所有 ID(路径) 可以事先在网站上找到。我们可以使用 getStaticPaths 方法检索此列表。
下面是我们将如何为[tvshow].js
页面实现 ID 检索。
export async function getStaticPaths() {
const res = await fetch("https://api.tvmaze.com/shows?page=1");
const data = await res.json();
//Get the available TV show IDs
const paths = data.map(tvshow => {
return { params: {tvshow: tvshow.id.toString()}}
});
//Pass the paths to prerender their content at build time
return {paths, fallback: false}
}
在这里,我们将 fallback 设置为 false,以便应用程序为不在检索到的列表中的 ID 返回 404 错误。
使用 getStaticPaths 方法时,我们还应该声明一个getStaticProps
方法,使 Next 能够检索每个电视节目的数据。我们可以实现这个功能,如下所示。
export async function getStaticProps({params}) {
//Params points to each TV show ID we retrieved in getStaticPaths
//Retrieve data for the TV show with the given ID
const res = await fetch(`https://api.tvmaze.com/shows/${params.tvshow}`);
const data = await res.json();
//Return the data as a prop to TVShow component
return {props: {data}}
}
然后我们可以设置 TVShow 组件以在网页上显示检索到的数据。
const TVShow = ({data}) => {
return (
<div>
<h3>{data.name}</h3>
<div>{data.summary.replace(/<\/?[^>]+(>|$)/g, "")}</div>
<p>Language: {data.language}</p>
<p>Status: {data.status}</p>
</div>
);
}
export async function getStaticPaths() {...}
export async function getStaticProps({params}) {...}
export default TVShow
这就是我们的电视节目页面显示这些结果的方式。
getServerSideProps
NextJS网站开发示例:如果你使用该getServerSideProps
方法获取数据,Next 将获取数据并为每个客户端请求生成 HTML 内容。换句话说,这种方法用于需要服务端渲染的页面。例如,如果要检索的数据不断变化,则应使用此功能获取最新结果。
以下是当客户端请求查看特定电视节目页面时,我们如何使用此方法检索数据。
export async function getServerSideProps(context) {
//context contains the URL user requests
const res = await fetch(`https://api.tvmaze.com/shows/${context.params.tvshow}`);
const data = await res.json();
return { props: { data } }
}
然后,TVShow 组件可以显示请求的电视节目的数据。
const TVShow = ({data}) => {
return (
<div>
<h3>{data.name}</h3>
<div>{data.summary.replace(/<\/?[^>]+(>|$)/g, "")}</div>
<p>Language: {data.language}</p>
<p>Status: {data.status}</p>
</div>
);
}
export async function getServerSideProps(context) {...}
export default TVShow
它返回一个类似于前面实现的输出getStaticPaths
和getStaticProps
。这里唯一的区别是应用程序不会在构建期间为每个可用的电视节目预渲染页面。相反,它仅在用户发送观看特定电视节目的请求时才检索数据并呈现页面。
NextJS用法示例:添加 CSS
Next 提供了几种向应用程序组件添加 CSS 的方法。让我们在本节中讨论允许添加我们自己的样式表的那些。
全局样式表
你可以使用此方法添加网站上所有组件通用的 CSS 属性。在了解如何添加此类样式表之前,让我们创建一个名为“styles”的新子目录来存储应用程序中的所有 CSS 文件。然后,在此目录中,我们可以使用以下全局样式创建名为“globals.css”的文件。
//globals.css
html, body {
padding: 0;
margin: 0;
font-family: Segoe UI, Roboto;
}
a {
color: inherit;
}
现在,我们应该通知 Next 应用有关全局样式表的信息。为此,我们使用 _app.js
文件。
_app.js 文件允许开发人员覆盖 Next 为初始化应用程序定义的默认配置。即使此文件存储在 pages 目录中,它也不会转换为 web 应用程序中的路由。
我们通过将全局样式表导入到 Next 中来将其引入_app.js
.
//_app.js
import '../styles/globals.css'
//This code section should be in the _app.js by default
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
现在,当应用程序重新加载时,这些全局样式将应用于每个网页。
组件级 CSS
如何使用NextJS开发网站?我们可以使用第二种方法为应用程序中的不同组件定义 CSS。组件级 CSS 文件也存储在样式目录中,应遵循名称格式 [component-name].module.css。然后,我们可以通过简单地导入文件并引用正确的类名来将这些样式应用到相关组件。
这是一个示例 CSS 文件,它应该为我们的应用程序中的 Home 组件设置样式。
import Link from "next/link";
import styles from "../styles/Home.module.css";
const Home = ({data}) => (
<div className={styles.container}>
<h1>Hello World!</h1>
<p>Popular TV Shows</p>
<ul>
{data.map(tvshow => {
return (
<li className={styles.item}>
<Link href={`/shows/${tvshow.id}`}><a>{tvshow.name}</a></Link>
</li>
);
})}
</ul>
<Link href="/about"><a>Learn more about us</a></Link>
</div>
);
造型后我们的主页:
Styled-JSX
NextJS网站开发示例:我们可以使用 styled-jsx 块在组件级 JSX 本身中添加 CSS。在这个方法中,我们使用一个特殊的标签{`` } ,并在引号内添加 CSS 代码,就像在常规 CSS 文件中一样。
让我们使用 styled-jsx 块修改我们的主页。
从“下一个/链接”导入链接;从“../styles/Home.module.css”导入样式;
const Home = ({data}) => (
<div className={styles.container}>
<h1>Hello World!</h1>
<p>Popular TV Shows</p>
<ul>
{data.map(tvshow => {
return (
<li className={styles.item}>
<Link href={`/shows/${tvshow.id}`}><a>{tvshow.name}</a></Link>
</li>
);
})}
</ul>
<Link href="/about"><a>Learn more about us</a></Link>
<style jsx>{`
a {
text-decoration: none;
}
ul {
list-style: none;
}
`}</style>
</div>
);
修改后的首页:
NextJS用法示例总结
至此,我们结束了对 Next.js 教程的介绍。我希望这篇文章能说服你将 Next.js 添加到你的 Web 开发工具库中。即使你以前没有使用 React 的经验,Next 也可以通过一组直观的功能和快速的性能轻松找到你的立足点。考虑到 Next 才在五年前首次面世,我们一定能够在未来几年看到它成长为一个更好的工具。