0

用 React+React Hook+Egg 造轮子 全栈开发旅游电商应用 | 完结

钱多多456
25天前 2

夏哉ke: bcwit.top/413

在技术圈,“造轮子”常常被贴上负面标签。但在真实的职场环境中,有节制、有思考的造轮子,恰恰是技术人员从“能用框架”走向“理解框架”、从“业务实现者”走向“架构设计者”的必经之路。

旅游电商是一个非常典型的全栈应用场景:

  • 业务复杂度高:动态库存、多供应商、实时价格、复杂营销、多步骤订单流程

  • 用户体验要求高:首屏加载、交互流畅、支付安全、多端适配

  • 技术覆盖面广:前端交互、后端接口、数据库设计、缓存策略、安全防护

选择 React.js + Egg.js 这套组合从零搭建,意味着你要直面所有技术决策——没有现成的脚手架帮你屏蔽复杂性,你需要自己决定目录结构、状态管理方案、接口设计规范、部署策略等一切细节。

这个过程会很痛苦,但正是这种“从零到一”的实践,才能让你真正理解全栈开发的底层逻辑,积累下可复用的架构模式。本文将带你走完这趟旅程,分享其中的核心设计思想和避坑经验。


第一部分:启程——项目启动与技术选型

一、为什么选 React.js + Egg.js?

在开始搭建之前,需要先回答一个关键问题:为什么是这对组合?

1. React.js 的选择理由

  • 组件化思维:旅游电商页面复杂,组件化能够有效拆分复杂度,实现高复用

  • 生态成熟:路由(React Router)、状态管理(Zustand/Redux)、请求(React Query)等周边生态完善

  • 性能可控:虚拟 DOM、Fiber 架构、代码分割等机制能够支撑复杂交互场景

  • 团队友好:语法直观,学习曲线相对平缓,团队成员上手快

2. Egg.js 的选择理由

  • 企业级框架:阿里出品,经过双十一等极端场景验证,稳定可靠

  • 约定优于配置:目录结构规范,团队协作时认知成本低

  • 插件生态:数据库(Sequelize)、鉴权(JWT)、跨域(CORS)等常用能力都有官方插件

  • 多进程模型:内置 Master-Worker 进程管理,充分利用多核 CPU

二、项目初始化与目录结构设计

好的目录结构是项目可维护性的基石。

前端目录结构(React)

text
src/
├── pages/           # 页面组件(路由级别)
│   ├── home/        # 首页
│   ├── product/     # 商品详情
│   ├── cart/        # 购物车
│   └── order/       # 订单
├── components/      # 可复用组件
│   ├── common/      # 通用组件(Button、Modal)
│   └── business/    # 业务组件(PriceCard、DatePicker)
├── hooks/           # 自定义 Hook
├── services/        # API 接口定义
├── stores/          # 状态管理
├── utils/           # 工具函数
├── styles/          # 全局样式
└── constants/       # 常量定义

后端目录结构(Egg.js)

text
app/
├── controller/      # 控制器(接收请求、返回响应)
├── service/         # 业务逻辑层
├── middleware/      # 中间件(鉴权、日志、限流)
├── model/           # 数据模型(Sequelize)
├── extend/          # 扩展(helper、context)
├── router.js        # 路由配置
config/
├── config.default.js    # 默认配置
├── config.local.js      # 本地开发配置
└── config.prod.js       # 生产环境配置

第二部分:前端 React 架构设计

三、组件设计:从原子到页面

旅游电商应用的组件层级可以借鉴原子设计理论

1. 原子组件(Atoms)

  • 最基础的 UI 元素:Button、Input、Icon、Tag

  • 特点:无业务逻辑,纯展示,高度可复用

  • 设计要点:支持 className 透传、ref 转发,遵循统一的设计规范

2. 分子组件(Molecules)

  • 多个原子组件的组合:SearchBar、PriceCard、DateRangePicker

  • 特点:有一定的业务语义,但仍保持相对通用

  • 设计要点:通过 props 控制行为,避免内部硬编码业务逻辑

3. 有机体组件(Organisms)

  • 分子组件的组合:ProductDetail、CheckoutForm、OrderList

  • 特点:承载具体业务逻辑,与后端 API 交互

  • 设计要点:使用自定义 Hook 封装业务逻辑,保持组件本身的“薄”

4. 页面组件(Pages)

  • 有机体的组合 + 路由匹配

  • 特点:负责页面布局、路由参数获取、页面级状态管理

  • 设计要点:页面组件应尽可能“轻”,将复杂逻辑下沉到有机体或 Hook

四、状态管理:精准用药

旅游电商应用涉及多种类型的状态,需要采用不同的管理策略:

状态类型示例管理方案
局部 UI 状态弹窗显隐、表单输入值useState / useReducer
共享状态用户信息、购物车数量Context + 合理拆分
服务端状态商品列表、订单数据React Query / SWR
全局响应式状态主题切换、通知中心Zustand(轻量级)

避坑经验

  • 不要把所有状态都塞进全局 Store,这会导致不必要的重渲染

  • React Query 是管理服务端状态的利器,内置缓存、重试、后台刷新,比手写 useEffect + useState 优雅得多

  • 购物车数据建议同时使用 Context(用于 UI 展示)和 localStorage(用于持久化)

五、路由设计:页面导航的骨架

使用 React Router v6 构建路由系统:

核心设计点

  1. 路由懒加载:配合 React.lazy 和 Suspense 实现代码分割,首屏只加载首页代码

  2. 路由守卫:封装 ProtectedRoute 组件,未登录时跳转登录页

  3. 嵌套路由:订单详情页可以复用订单列表的布局结构

  4. 404 处理:兜底路由展示 NotFound 页面

六、API 请求层:统一管理

将 API 请求统一收口到 services/ 目录:

设计要点

  • 按模块拆分:product.jsorder.jsuser.js

  • 统一错误处理:在请求拦截器中根据错误码弹出提示或跳转登录

  • 请求取消:使用 AbortController 避免组件卸载后还在更新状态

  • TypeScript 类型:前后端共享类型定义,通过 OpenAPI 自动生成


第三部分:后端 Egg.js 架构设计

七、Controller 层:请求的“门卫”

Controller 的职责是接收请求、参数校验、调用 Service、返回响应。

设计规范

  • 每个 Controller 对应一个资源模块(如 ProductController

  • 方法命名遵循 RESTful:index(列表)、show(详情)、create(创建)、update(更新)、destroy(删除)

  • 参数校验:使用 validate 插件或自定义校验逻辑,拒绝非法请求进入 Service

  • 统一响应格式:{ code: 0, message: 'success', data: {...} }

八、Service 层:业务逻辑的“大脑”

Service 是 Egg.js 的核心,负责业务逻辑的实现。

旅游电商的核心 Service 设计

1. 用户服务(UserService)

  • 注册/登录(JWT 生成与验证)

  • 用户信息查询与更新

  • 收藏夹管理

2. 商品服务(ProductService)

  • 商品列表(支持分页、筛选、排序)

  • 商品详情(聚合库存、价格、评价)

  • 库存查询(调用库存服务或缓存)

3. 订单服务(OrderService)

  • 创建订单(预占库存、计算金额、生成订单号)

  • 订单查询(状态过滤、分页)

  • 订单取消(释放库存)

  • 状态机管理(待支付 → 已支付 → 已出票 → 已完成)

4. 支付服务(PaymentService)

  • 调用第三方支付接口(支付宝/微信)

  • 支付回调处理(验签、更新订单状态)

  • 退款处理

九、中间件:横切关注点的“拦截器”

Egg.js 的中间件机制是实现横切逻辑的利器:

中间件职责
鉴权中间件验证 JWT Token,将用户信息挂载到 ctx.user
日志中间件记录请求耗时、响应状态
限流中间件基于 IP 或用户 ID 进行接口限流
跨域中间件处理 CORS,配置允许的域名
错误处理中间件捕获异常,返回统一格式的错误响应

注意事项:中间件的配置顺序很重要,鉴权中间件通常需要放在路由之前。

十、数据库设计:数据模型的“蓝图”

旅游电商涉及的核心数据表:

表名核心字段说明
usersid, mobile, password_hash, nickname用户表
productsid, title, description, price, stock, images商品表
ordersid, order_no, user_id, total_amount, status, payment_no订单表
order_itemsid, order_id, product_id, quantity, price订单明细表
cartsid, user_id, product_id, quantity购物车表

设计要点

  • 订单号使用分布式 ID 生成器(如雪花算法),避免自增 ID 暴露数据量

  • 金额字段使用 DECIMAL(10,2),避免浮点精度问题

  • 状态字段使用 TINYINT + 注释,减少联表查询

十一、缓存策略:Redis 的使用场景

旅游电商中,Redis 主要用在以下场景:

  1. 会话管理:存储 JWT 黑名单(用户登出后失效)

  2. 热点商品缓存:高并发商品详情页,缓存商品基础信息,降低数据库压力

  3. 库存预占:用户下单时预占库存,防止超卖

  4. 分布式锁:处理库存扣减、订单创建等并发场景

  5. 限流计数器:基于 IP 的接口限流


第四部分:核心业务模块实现思路

十二、用户认证:安全的第一道防线

登录流程

  1. 前端提交手机号 + 密码

  2. 后端验证密码正确性

  3. 生成 JWT Token,设置 HttpOnly Cookie(防止 XSS 攻击)

  4. 返回用户基本信息(不含敏感信息)

鉴权机制

  • 每次请求携带 Cookie,中间件验证 JWT 有效性

  • Token 过期时返回 401,前端自动跳转登录页

  • 退出登录时,将 Token 加入 Redis 黑名单,设置过期时间

安全考虑

  • 密码使用 bcrypt 加密存储

  • 生产环境必须启用 HTTPS

  • 敏感接口(修改密码、退款)二次验证

十三、商品详情页:聚合的挑战

旅游电商的详情页需要聚合多个数据源:

  • 商品基础信息(数据库)

  • 实时库存(Redis 或库存服务)

  • 实时价格(考虑促销活动)

  • 用户状态(是否收藏、是否已购)

  • 评价列表

实现策略

  • BFF 层(Egg.js)聚合以上数据,一次返回前端所需

  • 使用 Promise.all 并发请求多个下游服务,减少总耗时

  • 设置合理的超时和降级策略(库存服务不可用时返回“库存紧张”)

十四、购物车与订单:状态流转的关键

购物车设计

  • 未登录状态:购物车数据存 localStorage

  • 登录状态:购物车数据存后端(Redis 或数据库)

  • 登录时自动合并本地购物车与后端购物车

订单流程

  1. 创建订单:前端提交订单信息 → 预占库存 → 生成订单号 → 返回待支付订单

  2. 支付:调用第三方支付 → 返回支付二维码或跳转链接

  3. 支付回调:第三方回调 → 验签 → 更新订单状态 → 扣减真实库存 → 发送通知

  4. 超时取消:定时任务扫描未支付订单 → 超时则取消 → 释放预占库存

关键设计:订单状态机必须清晰定义每个状态的可转移路径,避免非法状态变更。

十五、搜索功能:从关键词到结果

旅游电商的搜索需要支持:

  • 关键词搜索(商品标题、目的地)

  • 筛选(价格区间、品类、评分)

  • 排序(综合、销量、价格)

实现思路

  • 初期使用 MySQL 的全文索引或 LIKE 查询

  • 数据量增长后,接入 Elasticsearch 或使用专业的搜索服务

  • 搜索关键词记录到日志,用于后续优化和热门词分析


第五部分:工程化与部署实践

十六、环境配置管理

前端

  • 使用 .env.development.env.production 文件管理环境变量

  • 构建时通过 process.env 注入 API 地址

后端

  • Egg.js 支持多环境配置:config.default.js(基础配置)+ config.local.js(本地覆盖)+ config.prod.js(生产覆盖)

  • 敏感信息(数据库密码、密钥)通过环境变量注入,不写入代码仓库

十七、构建与打包

前端

  • 使用 Webpack 或 Vite 构建

  • 配置代码分割(路由级别、第三方库分离)

  • 图片资源使用 CDN 加速

  • 生产环境启用 Gzip 压缩

后端

  • Egg.js 无需构建,直接运行 Node.js 代码

  • 使用 egg-scripts 启动和管理进程

  • 生产环境使用 PM2 或容器化部署

十八、部署策略

传统部署

  • 前端构建产物上传到 Nginx 静态目录或 CDN

  • 后端使用 PM2 启动,Nginx 反向代理

容器化部署(推荐)

  • Docker 打包前后端应用

  • 使用 Docker Compose 或 Kubernetes 编排

  • 便于扩缩容和环境一致性

CI/CD 流程

  • 代码推送 → 自动测试 → 构建镜像 → 部署到测试环境 → 人工验证 → 发布生产

十九、日志与监控

日志

  • 前端:接入 Sentry 捕获 JS 错误

  • 后端:Egg.js 内置日志模块,按天切割,接入 ELK 或日志平台

监控

  • 后端接入 Node.js 性能监控平台(如阿里云 ARMS、EasyMonitor)

  • 关注关键指标:QPS、响应时间、错误率、CPU 使用率


第六部分:避坑指南与经验总结

二十、常见陷阱与应对

1. 前端性能陷阱

  • 问题:图片未优化导致首屏加载慢

  • 解决:使用 WebP 格式、懒加载、CDN 加速

2. 状态管理陷阱

  • 问题:滥用 Context 导致不必要的重渲染

  • 解决:拆分 Context(用户信息、主题配置分开),使用 useMemoReact.memo 优化

3. 后端接口陷阱

  • 问题:接口返回字段过多,前端用不上

  • 解决:遵循“按需返回”原则,前端需要什么就返回什么

4. 数据库陷阱

  • 问题:N+1 查询问题

  • 解决:使用 include 预加载关联数据,或优化为单条 SQL

5. 安全陷阱

  • 问题:XSS 攻击、CSRF 攻击

  • 解决:输入转义、使用 HttpOnly Cookie、配置 CSRF Token

二十一、从“造轮子”到“沉淀资产”

“造轮子”的终极目标不是写一套代码,而是沉淀出可复用的模式:

  1. 组件库:提炼出可复用的业务组件,供后续项目使用

  2. 脚手架:将目录结构、配置规范沉淀为团队脚手架,新项目快速启动

  3. 文档:记录架构决策、设计思路、常见问题,降低团队沟通成本

  4. 规范:形成代码规范、接口规范、数据库设计规范,提升团队协作效率

结语:从零到一的价值

从零搭建一个旅游电商应用,不是一件轻松的事。你会在过程中遇到无数问题:路由配置不生效、状态更新不同步、跨域报错、数据库死锁、部署失败……但正是这些问题,让你真正理解全栈开发的本质。

你收获的,不只是一套能跑的代码,而是:

  • 对 React 组件化设计的深刻理解

  • 对 Egg.js 框架内核的透彻认知

  • 对前后端协作模式的实践经验

  • 对工程化与部署流程的完整掌控

  • 对复杂业务场景的架构决策能力

当你走完这一趟“从零到一”的旅程,你会发现,自己已经从一个“会使用框架的开发者”,成长为一个“能够独立构建完整应用的工程师”。这份能力,将成为你在技术道路上走得更远的坚实基石。


本站不存储任何实质资源,该帖为网盘用户发布的网盘链接介绍帖,本文内所有链接指向的云盘网盘资源,其版权归版权方所有!其实际管理权为帖子发布者所有,本站无法操作相关资源。如您认为本站任何介绍帖侵犯了您的合法版权,请发送邮件 [email protected] 进行投诉,我们将在确认本文链接指向的资源存在侵权后,立即删除相关介绍帖子!
最新回复 (0)

    暂无评论

请先登录后发表评论!

返回
请先登录后发表评论!