如今,无论你是经验丰富的开发人员还是完全的初学者,你都没有什么不能用 React 做的。
这主要是由于创建了诸如Next.js之类的工具,这些工具成功地简化了React前端开发。
因此,我们将探讨如何快速制作 Next.js 电子商务单页应用程序。
在下面的技术教程中,我将向您展示如何:
设置 Next.js 开发环境
创建新页面和组件
获取数据并导入组件
在 Next 中创建无服务器 API 路由
将购物车添加到 Next.js 应用
设置应用样式
但在我们讨论这个问题之前,让我们确保我们了解Next.js是什么以及它如何改善您的下一个电子商务项目。
简而言之,Next.js 是一个用于 React 应用程序的轻量级框架,它允许您轻松地在 React 中构建服务器端渲染和静态应用程序。
它吸收了 React 的所有优点,并使应用程序以优化的渲染性能运行变得更加容易。Next.js 通过多种内置配置(自动代码拆分、文件系统路由、服务器端渲染、静态文件导出和样式解决方案)来实现这一点。
相信我,当我说你可以用 Next.js 构建很多不同的东西时:
静态网站——我们已将其列为?2021 年顶级静态网站生成器之一。
渐进式 Web 应用?(PWA)
服务器呈现的应用程序
对 SEO 友好的网站——正如我们在这里所展示的那样。
移动应用
它由?Zeit(现为 Vercel)于 2016 年构建,并迅速获得关注,成为同类工具中最受欢迎的工具之一。它被漫威、Netflix、Uber、耐克......使用,这样的例子不胜枚举。
好吧,这一切都很棒,我真的很高兴能在这里玩 Next.js。但这对电子商务有什么好处吗?
与任何静态网站生成器或 JavaScript 框架一样,与更传统的电子商务平台相比,它最显着的优势之一是它为开发人员提供了创建令人振奋的购物用户体验的选项,同时消除了构建 Web 应用程序所需的许多实现细节的负担。
根据您的需要,您可以使用 Next 轻松构建服务器端或静态渲染应用程序,它会为您实现这些功能,同时还抽象出其他细节,例如应用程序捆绑和转编译。
Jamstack?的力量就在这里!
→ 使用组件以提高灵活性。
基于组件的开发使代码可以通过您的应用程序轻松重用,还可以编写小功能。或者,在我们的例子中,小型电子商务功能。一旦您开始扩展和扩展购物车集成,这就会派上用场。
→ Virtual DOM(文档对象模型)以提高性能。
React 的虚拟 DOM?提供了一种更有效的方式来更新 Web 应用程序中的视图。在电子商务中,性能就是一切;所有毫秒都很重要。
→ 受欢迎程度和庞大的社区。
任何问题都可能已经记录在案,因此您可能会找到解决任何潜在陷阱的方法。
Next.js 功能,如服务器端渲染和静态导出,通过保证您的网站/应用程序对 SEO 友好,进一步推动了这些 React 优势。这对任何电子商务企业都至关重要。
还需要社会证明吗?以下是一些?Next.js 电子商务网站示例。
好的,是时候跳入代码并在 Snipcart 的帮助下创建我们自己的手工制作的 Next.js 电子商务应用程序了。对于鱼类爱好者——或者任何等待任何很酷的软件库测试版的人来说——请放心,因为我们今天将制作一家斗鱼商店。
基本了解单页应用程序?(SPA)
一个 Snipcart 帐户(在测试模式下永久免费)
React?和?TypeScript?的基本知识也会在这里帮助你,但不是强制性的。
首先,让我们设置我们的环境,以便我们可以开始构建。
打开终端并键入以下命令:npx create-next-app --typescript
将出现一个提示,询问您输入项目的名称。然后,它将为您安装所有项目依赖项,并创建文件和文件夹。在本教程中,我们将进一步研究这些内容。
初学者笔记:该命令的选项将设置一个 Typescript 项目,这是我经常喜欢的。键入系统有助于防止许多运行时错误和活泼的错误。从长远来看,它还允许更好的重构!
--typescript
然后,运行 npm run dev
.应用现在应在 localhost:3000
运行。
准备好环境后,让我们为商店创建布局。它将包括一个页眉和一个页脚,其中包含指向我们购物车和联系信息的链接。
我们会将此布局添加到应用的主入口点。在?Next
中,此入口点位于 pages/_app.tsx
。您可以看到该函数返回 MyApp
.我们将使用此函数来创建应用程序的布局:pageProps
在项目的根目录下,创建components
一个目录——你猜对了——我们将在其中创建我们的组件。
现在让我们创建我们需要的组件。
在components
目录中,创建一个包含以下内容的文件:Header.tsx
// components/Header.tsx
import Link from "next/link";
export default function Header() {
return (
<header >
<Link href="/">
<img src="/static/logo.svg" alt="" >
</Link>
<Link href="/">
<h1 >FishCastle</h1>
</Link>
<a href="#" style={{textDecoration: "none"}}>
<svg width="31" height="27" viewBox="0 0 31 27" fill="none" xmlns="<http://www.w3.org/2000/svg>">
<path d="" fill="#9094FF"/>
</svg>
<span></span>
</a>
</header>
)
}
Next.js 中的组件允许我们将大多数 HTML 元素转换为网站内链接。Link
仍在components
目录中,创建一个包含以下内容的文件:Footer.tsx
// components/Footer.tsx
export default function Footer(){
return (
<footer>
<p>
Next.js app with a <a href="<https://snipcart.com>">Snipcar t</a> - powered store
<div >
<a href="<https://github.com/snipcart/snipcart-nextjs>-spa">Github</a>
</div>
</p>
</footer>
)
}
现在,让我们将这些组件集成到我们的Layout
应用程序中。首先,创建一个组件并将 Header
和 Footer
放入其中:
import Header from "./Header";
import Footer from "./Footer";
import {PropsWithChildren} from "react";
export default function Layout({ children }: PropsWithChildren<any>) {
return (
<>
<Header />
<main>{children}</main>
<Footer />
</>
)
}
创建布局组件后,剩下要做的就是将其添加到_app.tsx
文件中:
// _app.tsx
function MyApp({ Component, pageProps }: AppProps) {
return <>
<Layout>
<Component {...pageProps} />
</Layout>
</>
}
如果运行应用的开发模式并转到 localhost 页面,现在应该会看到已创建应用的布局。在本教程的后面部分,我们将看到如何为它添加样式并赋予它drip。
但首先,让我们为我们的主页提供它应得的内容。
由于我们需要显示有关我们商店和我们将销售的产品的信息,因此我们将创建一些不同的组件以保持模块化和可维护性。然后,我们将看看如何组装它们:
由于这是电子商务应用程序的Next.js教程,因此您需要一个Product
组件才能显示在主页上。
该组件将输出您需要显示的有关我们特定产品的任何信息。您可以创建一个与 Snipcart 的产品定义相匹配的接口IProduct
IProductProps
,以及一个定义我们道具类型的接口,这些道具将作为参数传递给函数。
// components/Product.tsx
export interface IProduct {
id: string
name: string
price: number
url: string
description: string
image: StaticImageData
}
在界面下方,添加以下组件:
// components/Product.tsx
interface IProductProps {
product: IProduct
}
const Product = (props: IProductProps) => {
return (
<div className={styles.product}>
<h2 className={styles.product__title}>{props.product.name}</h2>
<p className={styles.product__description}>{props.product.description}</p>
<div className={styles.product__image}>
<Image src={props.product.image} alt={props.product.image.src} />
</div>
<div className="product__price-button-container">
<div className={styles.product__price}>${props.product.price.toFixed(2)}</div>
<button
className={`snipcart-add-item ${styles.product__button}`}
data-item-id={props.product.id}
data-item-name={props.product.name}
data-item-price={props.product.price}
data-item-url={props.product.url}
data-item-image={props.product.image.src}>
Add to cart
</button>
</div>
</div>
)
}
请注意,在下面的块中,我们使用的是 Next.js?的 Image 组件,而不是一个好的 ol' 标签。前者实际上是后者的延伸。它允许自动图像优化,默认延迟加载,并在浏览器允许时以?WebP?格式提供图像,从而将图像优化到客户端设备。此外,该组件会根据请求优化图像,从而节省您的构建时间。这有助于减少您的网站加载时间,从而保持用户的兴趣!img
我们将此产品组件集成到一个ProductList
组件中,其名称不言自明ProductList.tsx
。该组件将用于在主页上显示我们的产品列表。因此,您可以创建一个接口IProductListProps
来描述一个数组IProduct
,该数组最终将由我们的网站传递:???????
import Product, {IProduct} from "./Product";
interface IProductListProps {
products: IProduct[]
}
const ProductList = (props: IProductListProps) => {
return (
<div className="product-list">
{props.products.map((product, index) => <Product product={product} key={index}/>)}
</div>
)
}
export default ProductList
在此阶段,您可能希望将产品填充到 ProductList 组件中。在纯 React 中,你可以在?ProductList
中使用 React 的 useEffect 生命周期来填充数据。但是,在静态或服务器端呈现期间,不会在服务器上调用此方法。
值得庆幸的是,Next.js 添加了两种预呈现数据的方法:getStaticProps,getServerSideProps。
在构建时获取数据,以及在每个请求上获取数据。例如,后者对于价格可能快速波动的拍卖店可能很有用。在我们的用例中,由于产品不经常更改,我们将使用前者,因为预渲染将通过保存用户请求来减少加载时间。???????
<main className="main">
<Jumbotron />
<ProductList products={products}/>
<Contact/>
</main>
export const products: IProduct[] = [
{
id: "halfmoon",
name: "Halfmoon Betta",
price: 25.00,
image: halfmoonBettaPicture,
description: "The Halfmoon betta is arguably one of the prettiest betta species. It is recognized by its large tail that can flare up to 180 degrees.",
url: '/api/products/halfmoon'
},
(...)
{
id: "veiltail",
name: "Veiltail Betta",
price: 5.00,
image: veiltailBettaPicture,
description: "By far the most common betta fish. You can recognize it by its long tail aiming downwards.",
url: '/api/products/veiltail'
}
]
export const getStaticProps: GetStaticProps = async (context) => {
return {
props: {
products
}
}
}
Jumbotron
?&?Contact
添加组件是为了完成页面,但它们对于演示不是必需的。可以在此处查看 GitHub 存储库中的组件。
现在,让我们将 Snipcart 安装到我们的网站中。首先,您需要从 index.tsx 页面内的 next/head 导入组件Head
,这将允许您在???????<Head>
元素中添加 HTML。
为此,可以在 Index 函数 return 子句中添加以下代码:
// pages/index.tsx
<Head>
<title>My awesome store</title>
<link rel="preconnect" href="<https://app.snipcart.com>"/>
<link rel="preconnect" href="<https://cdn.snipcart.com>"/>
<link rel="stylesheet" href="<https://cdn.snipcart.com/themes/v3.2.0/default/snipcart.css>"/>
<link rel="shortcut icon" href="../public/favicon.ico" />
</Head>
我们现在需要加载 Snipcart 的脚本内容。Next.js 在 next/script
模块中提供了一个脚本组件来执行此操作。它允许通过提供不同的加载策略来优化性能。
// pages/index.tsx
<script src="https://cdn.snipcart.com/themes/v3.2.0/default/snipcart.js"></script>
<div hidden id="snipcart" data-api-key="YOUR_PUBLIC_API_KEY"></div>
不要忘记将属性data-api-key
替换成您自己的 API 密钥;)
现在 Snipcart 已安装,完成订单前的最后一步是验证您的产品。
第一种方法是简单地将产品列表中的 URL 更改为每个产品的主页,以进行 Snipcart?的 HTML 验证。它会读取我们主页上的内容并对其进行抓取,以便根据需要验证产品。您可以这样做并跳到下一节,您将拥有一个有效的电子商务网站!/
/
如果您好奇,让我们借此机会查看一个简洁的 Next.js 功能:无服务器 API 路由与 Snipcart 的?JSON 验证相结合。
对于更复杂的方案,让 API 以 JSON 格式返回我们的产品信息可能很有用。为此,我们需要为每个产品设置一个唯一的 URL,该 URL 将在 JSON 文件中返回其信息。
配置静态 API 路由
虽然从技术上讲,我们只需要一个返回每个产品的动态 API 路由,但让我们让这个 API?RESTful?并有一个返回整个产品列表的路由。
您可能已经注意到,已使用该项目创建了一个 API 文件夹。在此文件夹中,创建另一个名为“的文件夹,并向其添加一个包含以下内容的文件:products
index.ts
// In pages/api/products/index.ts
import {NextApiRequest, NextApiResponse} from "next";
import {products} from "../../index";
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json(products);
}
如果您现在转到 ,您将获得一个包含您的产品列表的 JSON 文件。https://localhost:3000/${YOUR_PORT}
配置动态 API 路由
在文件夹products
中,将以下内容添加到文件[productId].ts
中。请注意括号。这种特殊语法告诉 Next.js [productid] 是一个动态参数。因此,如果您转到 ,您应该获得我们产品之一的 JSON 信息。??????????????/api/products/ONE_OF_YOUR_PRODUCTS_ID
import {NextApiRequest, NextApiResponse} from "next";
import {products} from "../../index";
import {IProduct} from "../../../components/Product";
export interface ISnipcartProduct {
id: string
name: string
price: number
url: string
description: string
image: string // Hack to pass the image URL instead of the StaticImage object we required
}
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const {productId} = req.query;
const product: IProduct | undefined = products.find(p => p.id === productId);
if (!product) {
res.status(404).json({});
return ;
}
const snipcartProduct: ISnipcartProduct = {...product, image: product?.image.src ?? ""}
res.status(200).json(snipcartProduct);
}
您现在应该能够完成测试订单了!
是时候设计我们的网站了,这样它对我们未来的客户更具吸引力。
如果你注意了,你就会发现本教程中的大多数组件已经有了类名。我们现在将看看 2 种不同的方法来应用它们:
在 style
文件夹中,创建一个样式表???????global.scss
。之后,只需将其导入:??????pages/_app.tsx
// in pages/_app.tsx
import "../styles/globals.scss";
全局样式表只能导入到_app.tsx
文件中。我使用了 SCSS,它没有内置于 Next.js 中,但只需运行 npm install sass
Next.js 还支持 CSS 模块,如果您的 CSS 文件变大,这将变得非常方便。要使用它,只需创建一个遵守约定的文件,例如,或 .[name].module.css?
Product.module.css?
Product.module.scss
之后,您可以将其作为对象导入组件文件中,并用它访问样式:styles
import styles from '../styles/Product.module.scss';
(...)
const Product = (props: IProductProps) => {
return (
<div className={styles.product}>
<h2 className={styles.product__title}>{props.product.name}</h2>
<p className={styles.product__description}>{props.product.description}</p>
(...)
)
}
有关如何应些样式的更多示例,请查看该项目:
???????Github 存储库
服务器端呈现的 Next.js 电子商务商店应该已经准备好了。
使用 Next.js 创建一个具有出色性能的静态网站是多么容易。我确实注意到 Next.js 文档的某些部分可以更新。
我们本可以使用组件或 Next 的动态导入来探索移动设备上的图像优化,以进一步推动此演示。Image
???????