从 Vue 到 React:Tailwind CSS 布局 + BFF 代理实战
前言
上一篇文章写了 Vue 3 + DeepSeek API 的流式输出,今天切换到 React 生态继续学习。在动手写 React 代码前,先搞清楚几个重要的工程化概念:Tailwind CSS 原子化样式 、BFF 层代理 ,以及 React 和 Vue 在响应式数据上的异同。
一、Tailwind CSS 原子化布局
React 项目里经常用 Tailwind CSS,它跟传统写 CSS 完全不同------不需要写 CSS 文件,直接用类名拼布局。
1.1 Flex 布局核心类
tsx
<div className="flex flex-col justify-center items-center">
{/* 子元素会纵向排列,水平和垂直都居中 */}
</div>
逐词拆解:
| 类名 | CSS 等价 | 含义 |
|---|---|---|
flex |
display: flex |
开启弹性布局 |
flex-col |
flex-direction: column |
主轴改为垂直方向 |
justify-center |
justify-content: center |
主轴居中 |
items-center |
align-items: center |
交叉轴居中 |
主轴 vs 交叉轴 :默认主轴是水平方向,加了 flex-col 后主轴变成垂直方向。
justify-*控制主轴items-*控制交叉轴
1.2 常用工具类速查
tsx
<div className="
h-screen // height: 100vh --- 撑满整个屏幕
h-full // height: 100% --- 撑满父容器
mx-auto // margin-left/right: auto --- 水平居中
mb-2 // margin-bottom: 0.5rem (8px)
overflow-auto // 内容超出显示滚动条
relative // position: relative --- 相对定位锚点
justify-end // 主轴尾部对齐(配合 flex-col 即底部对齐)
text-center // text-align: center --- 文字居中
text-red-500 // color: #ef4444 --- 红色文字
">
记忆诀窍:{属性缩写}-{方向/值}-{大小},比如 mb-2 = margin-bottom 2 档 = 8px。
二、React vs Vue 响应式数据
两者都是响应式框架,但 API 不同:
Vue 3
js
import { ref } from 'vue'
const count = ref(0) // 用 ref 包装
count.value++ // 通过 .value 读写
React
tsx
import { useState } from 'react'
const [count, setCount] = useState(0) // 解构出值和 setter
setCount(count + 1) // 通过 setter 修改
核心差异:Vue 通过 .value 直接改,React 必须用 setCount 方法触发重渲染。
小技巧:!! 双取反
js
!!"hello" // true --- 非空字符串转 true
!!0 // false --- 0 转 false
!!undefined // false
! 取反一次得到布尔值(但是反的),再 ! 翻回来,等价于 Boolean(x),常用于条件判断。
三、BFF 层 + Vite 代理
3.1 为什么需要 BFF?
scss
浏览器 ─→ BFF(Node) ─→ DeepSeek API / 后端服务
(无 Key) (Key 安全存这里)
BFF = Backend For Frontend,面向前端的后端层。API Key 不能暴露在浏览器,所以前端不直接调 DeepSeek,而是通过 BFF 中转。
3.2 Vite 代理配置
前端 Vite 跑在 5173 端口,BFF 跑在 3000 端口。浏览器有同源策略,不能跨端口请求。Vite 代理解决跨域:
js
// vite.config.js
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:3000', // 转发到后端
secure: false,
rewrite: (path) => path.replace(/^\/api/, ''), // 去掉 /api 前缀
}
}
}
})
效果:
bash
前端请求: /api/stream
↓ Vite 代理转发 + rewrite 去前缀
后端收到: /stream
前端感觉自己在同源请求,实际是 Vite 偷偷转了。
3.3 Express 后端路由
js
import express from 'express'
const app = express()
app.get('/stream', async (req, res) => {
// 调用 DeepSeek API,流式返回给前端
const response = await fetch('https://api.deepseek.com/chat/completions', {
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
body: JSON.stringify({ stream: true, /* ... */ })
})
// 逐块转发
const reader = response.body.getReader()
while (true) {
const { done, value } = await reader.read()
if (done) break
res.write(value)
}
res.end()
})
app.listen(3000)
路由就是 URL 和处理函数的映射------用户访问什么路径,服务器执行什么代码。配合 RESTful 风格,URL 表示资源,HTTP 方法表示操作:
bash
GET /users → 获取用户列表
POST /users → 创建用户
PUT /users/1 → 更新用户
DELETE /users/1 → 删除用户
四、RAG 相关概念速览
项目中还涉及了 RAG(检索增强生成)的基础流程:
| 概念 | 一句话解释 |
|---|---|
| Loader | 负责读取不同格式文件(PDF、CSV、网页) |
| Cheerio | Node.js 版 jQuery,把 HTML 字符串解析成 DOM 树 |
| CSS Selector | 定位 HTML 元素,如 .main-area p 选文章段落 |
| Chunk | 大文件切成的具有语义完整性的小段文本,是 RAG 检索的最小单位 |
| 蒸馏(Distillation) | 用大模型"教"小模型,让小的也有大模型大部分能力 |
五、总结
今天在技术栈上做了横向和纵向的扩展:
| 维度 | 内容 |
|---|---|
| 框架 | Vue → React,理解了 useState 和 ref 的异同 |
| 样式 | 从手写 CSS 到 Tailwind 原子化类名 |
| 架构 | 从纯前端直接调 API 到 BFF 层代理转发 |
| 跨域 | 从 Vite proxy 理解前后端分离中的网络瓶颈 |
| AI | 从 RAG 流程(Loader → Splitter → Chunk)了解知识库底层 |
前端入门只是第一步,理解架构才能写出安全的代码。欢迎交流!