我review了一份Vibe Coding写的前端代码——能跑,但5个地方迟早要命
上周帮一个做独立项目的朋友看代码。他用Claude Code Cursor三天做了一个完整的React管理后台——能登录能CRUD能导出Excel页面UI还不错。他说“你帮我看看准备上线了。”我打开项目npm start跑起来页面确实能用。然后我打开代码——看了十分钟告诉他“能跑但别上线。至少改完这5个地方再说。”这不是个例。Vibe Coding现在最大的问题不是写不出来而是写出来的东西看起来很好实际上全是定时炸弹。FT最近有篇报道标题就是Who cleans up after the vibe-coding party?。Reddit上也有人说“The first 80% of vibe coding feels fast. The last 20% has broken me.”以下是我在这份代码里发现的5个典型问题。如果你也在用AI写代码对照检查一下。问题一所有状态都往全局塞打开项目的状态管理我看到一个巨大的AppContext// ❌ AI最爱干的事把所有状态塞进一个Context const AppContextcreateContext(null);functionAppProvider({children}){const[user, setUser]useState(null);const[theme, setTheme]useState(light);const[sidebarOpen, setSidebarOpen]useState(true);const[notifications, setNotifications]useState([]);const[tableData, setTableData]useState([]);const[filters, setFilters]useState({});const[selectedRows, setSelectedRows]useState([]);const[modalVisible, setModalVisible]useState(false);const[formData, setFormData]useState({});const[loading, setLoading]useState(false);//...还有20多个return(AppContext.Providervalue{{user, setUser, theme, setTheme, sidebarOpen, setSidebarOpen, //...全部暴露出去}}{children}/AppContext.Provider);}40多个state全塞在一个Provider里。结果就是任何一个state变化整棵组件树都重新渲染。你在表格里勾选一行selectedRows变了——侧边栏、导航栏、通知弹窗全部重新渲染。AI为什么这样写因为你告诉它加一个XX功能它就在已有的Context里加一个state。它不会主动说这个state应该放到单独的Context里。// ✅ 按职责拆分Context const AuthContextcreateContext(null);const UIContextcreateContext(null);functionAuthProvider({children}){const[user, setUser]useState(null);return(AuthContext.Providervalue{{user, setUser}}{children}/AuthContext.Provider);}functionUIProvider({children}){const[theme, setTheme]useState(light);const[sidebarOpen, setSidebarOpen]useState(true);return(UIContext.Providervalue{{theme, setTheme, sidebarOpen, setSidebarOpen}}{children}/UIContext.Provider);}// 表格页面的状态留在表格组件里根本不需要ContextfunctionDataTable(){const[selectedRows, setSelectedRows]useState([]);const[filters, setFilters]useState({});//...}判断标准这个state是不是只有一个页面/组件用只有一个地方用的state别往Context里放。问题二每个请求都裸奔翻了一下数据请求的代码// ❌ AI写的典型请求代码只管发不管防functionUserList(){const[users, setUsers]useState([]);useEffect((){ fetch(/api/users).then(resres.json()).then(datasetUsers(data));},[]);const handleDeleteasync(id){await fetch(/api/users/${id},{method:DELETE});// 删完重新拉列表 const resawait fetch(/api/users);const dataawait res.json();setUsers(data);};return(ul{users.map(u(likey{u.id}{u.name}buttononClick{()handleDelete(u.id)}删除/button/li))}/ul);}问题清单没有loading状态——用户不知道在加载没有error处理——接口挂了页面空白没有竞态处理——快速切换页面会把旧数据覆盖新数据删除按钮没有防重复点击——连点两下发两个DELETE没有乐观更新——每次操作都要等整个列表重新加载// ✅ 生产级别的请求应该这样functionUserList(){const queryClientuseQueryClient();const{data: users, isLoading, error}useQuery({queryKey:[users], queryFn:()fetch(/api/users).then(rr.json()),});const deleteMutationuseMutation({mutationFn:(id)fetch(/api/users/${id},{method:DELETE}), onMutate: async(id){await queryClient.cancelQueries({queryKey:[users]});const prevqueryClient.getQueryData([users]);queryClient.setQueryData([users], oldold.filter(uu.id!id));return{prev};}, onError:(err, id, context){queryClient.setQueryData([users], context.prev);}, onSettled:(){queryClient.invalidateQueries({queryKey:[users]});},});if(isLoading)returnSkeleton /;if(error)returnErrorFallbackerror{error}/;return(ul{users.map(u(likey{u.id}{u.name}buttondisabled{deleteMutation.isPending}onClick{()deleteMutation.mutate(u.id)}删除/button/li))}/ul);}不是说每个请求都要写这么多。而是AI根本不会主动帮你考虑这些边界情况。它只实现了你描述的正常流程所有异常路径都不存在。问题三环境变量明文写在代码里这是让我最紧张的一个// ❌ 真的在代码里看到了这个 const supabasecreateClient(https://xxxxx.supabase.co,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx...);// 另一个文件里 const STRIPE_KEYsk_live_xxxxxxxxxxxxx;Supabase的anon key直接写在代码里。Stripe的私钥直接写在前端代码里。我问他“这个key是从哪来的”他说“我在prompt里告诉Claude我的key它就帮我配好了。”AI不会主动告诉你这个key不能放在前端代码里。它只管让代码跑起来。如果你在prompt里给了key它就原样写进去。// ✅ 环境变量必须走.env // .env.local不提交到git //NEXT_PUBLIC_SUPABASE_URLhttps://xxxxx.supabase.co //NEXT_PUBLIC_SUPABASE_ANON_KEYeyJhbGci... const supabasecreateClient(process.env.NEXT_PUBLIC_SUPABASE_URL, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY);// Stripe私钥绝不能出现在前端 // 必须放在服务端API route里 // pages/api/checkout.js // const stripenew Stripe(process.env.STRIPE_SECRET_KEY);检查清单该检查什么怎么查代码里有没有硬编码的key全局搜索sk_、eyJ、key、secret、password.gitignore有没有忽略.env打开.gitignore看有没有.env*前端代码有没有后端密钥前端代码里的key只能是NEXT_PUBLIC_或VITE_前缀的git历史里有没有泄露过git log --all -p -- *.env问题四权限检查只在前端看到一个管理员才能看到的页面打开路由// ❌ AI写的权限控制functionAdminRoute({children}){const{user}useAuth();if(user?.role!admin){returnNavigateto/dashboard/;}returnchildren;}// 路由配置Routepath/admin/userselement{AdminRouteUserManagement //AdminRoute}/看起来没问题对吧管理员才能进管理页面。但是——打开UserManagement组件里的API调用// 这个接口任何人都能调 const handleDeleteUserasync(userId){await fetch(/api/admin/users/${userId},{method:DELETE,});};前端藏了按钮但接口没有权限验证。任何人打开浏览器DevTools直接调/api/admin/users/123就能删用户。这就是OWASP Top 10里的Broken Access Control——连续多年排第一的Web安全漏洞。// ✅ 权限必须在后端验证Next.js API Route示例exportdefault asyncfunctionhandler(req, res){const sessionawait getServerSession(req, res, authOptions);if(!session||session.user.role!admin){returnres.status(403).json({error:Forbidden});}if(req.methodDELETE){const{id}req.query;await db.user.delete({where:{id}});returnres.status(200).json({success:true});}res.status(405).end();}铁律前端的权限检查是UX优化不给用户看到没权限的按钮后端的权限检查才是安全防线。两个都要有但后端那个不能省。问题五组件巨大无比一个文件500行这是AI写代码最显眼的特征——所有逻辑都塞在一个组件里// ❌ AI的经典作品一个500行的完整组件functionOrderManagement(){//20个useState const[orders, setOrders]useState([]);const[filters, setFilters]useState({});const[selectedOrder, setSelectedOrder]useState(null);const[isEditing, setIsEditing]useState(false);//... //10个handler函数 const handleSearch(){/*30行 */};const handleFilter(){/*25行 */};const handleEdit(){/*40行 */};const handleDelete(){/*20行 */};const handleExport(){/*50行 */};//... //200行JSXreturn(div{/* 搜索栏 */}div{/*50行搜索表单 */}/div{/* 筛选器 */}div{/*40行筛选条件 */}/div{/* 表格 */}table{/*80行表格渲染 */}/table{/* 编辑弹窗 */}{isEditingdiv{/*60行编辑表单 */}/div}{/* 分页 */}div{/*30行分页器 */}/div/div);}为什么AI喜欢写成这样因为你说做一个订单管理页面它就在一个文件里把所有东西都实现了。它的目标是让你的需求跑起来不是让代码可维护。当你要改一个筛选器的bug时你要在500行代码里找到那20行。当你要给表格加一列时你要理解这500行的所有状态依赖关系。// ✅ 按职责拆分 // components/OrderFilters.jsxfunctionOrderFilters({value, onChange}){return(/* 筛选器UI只管筛选 */);}// components/OrderTable.jsxfunctionOrderTable({data, onEdit, onDelete}){return(/* 表格UI只管展示 */);}// components/OrderEditModal.jsxfunctionOrderEditModal({order, onSave, onClose}){return(/* 编辑弹窗只管编辑 */);}// hooks/useOrders.jsfunctionuseOrders(filters){returnuseQuery({queryKey:[orders, filters], queryFn:()fetchOrders(filters),});}// pages/OrderManagement.jsx — 组装层不超过50行functionOrderManagement(){const[filters, setFilters]useState({});const[editingOrder, setEditingOrder]useState(null);const{data: orders, isLoading}useOrders(filters);return(divOrderFiltersvalue{filters}onChange{setFilters}/OrderTabledata{orders}onEdit{setEditingOrder}onDelete{handleDelete}/{editingOrder(OrderEditModalorder{editingOrder}onSave{handleSave}onClose{()setEditingOrder(null)}/)}/div);}Review速查表检查项怎么查AI代码常见问题全局状态搜Context/Provider所有state塞一个Context请求处理搜fetch/axios没有loading/error/竞态处理密钥泄露搜sk_/eyJ/secret/password硬编码在前端代码里权限控制看API路由有没有auth检查前端藏按钮但接口裸奔组件大小看文件行数单文件500行逻辑全混在一起Vibe Coding不是问题不Review才是我不反对Vibe Coding。三天能跑起来一个完整的管理后台这在两年前不可想象。但AI生成的代码和人写的代码需要同一套审查标准。你不会让一个实习生提交的代码不经过review就直接上线AI写的代码也不应该。区别在于实习生的代码你一看就知道哪里不对AI写的代码看起来很专业——命名规范结构清晰注释齐全。但那5个问题就藏在这些看起来很对的代码里。如果你正在Vibe Coding一个准备上线的项目至少跑一遍上面的速查表。你review过AI写的代码吗发现过什么让你冒冷汗的问题

相关新闻

STM32 CAN总线初始化全解析:从硬件连接到软件配置与调试

STM32 CAN总线初始化全解析:从硬件连接到软件配置与调试

1. 从“点灯”到“通信”:为什么CAN初始化是STM32进阶的必经之路如果你是从点灯、串口打印开始接触STM32的,那么恭喜你,你已经迈出了嵌入式开发的第一步。但当你开始接触电机控制、汽车电子、工业自动化这些更复杂的领域时,你会发…

2026/7/29 5:17:15 阅读更多 →
.NET应用SSL证书信任链问题:手动导入根证书的完整解决方案

.NET应用SSL证书信任链问题:手动导入根证书的完整解决方案

1. 项目概述:为什么.NET的证书信任链如此“脆弱”?如果你在Windows或Linux上部署.NET应用,尤其是那些需要调用外部API、访问HTTPS服务或者使用NuGet包时,大概率遇到过这个令人头疼的错误:“底层连接已关闭:…

2026/7/29 5:17:15 阅读更多 →
I2C通信波形分析实战:从协议原理到示波器调试

I2C通信波形分析实战:从协议原理到示波器调试

1. 项目概述:从“黑盒”到“白盒”的I2C通信搞嵌入式开发,尤其是和传感器、EEPROM、OLED屏这些外设打交道,I2C(也叫IIC)总线绝对是绕不开的一道坎。很多新手朋友一上来就对着库函数一顿I2C_Read、I2C_Write&#xff0c…

2026/7/29 5:17:15 阅读更多 →

最新新闻

在湖南选子母门公司,这3点居然没人告诉你?

在湖南选子母门公司,这3点居然没人告诉你?

在湖南跑了两三个月建材市场,自认为做足了攻略,结果和几位刚装完别墅的前辈一聊,还是发现自己漏掉了几个关键细节。尤其是在选子母门这件事上,很多商家不会主动说,但直接影响你未来十年甚至二十年的居住体验。今天不聊…

2026/7/29 5:25:18 阅读更多 →
如何用旧 iPhone 设置新 iPhone?

如何用旧 iPhone 设置新 iPhone?

购买新 iPhone 后,您通常首先要做的是将旧设备上的数据(包括联系人、照片、信息、应用数据等)传输到新设备。在将旧 iPhone 的数据迁移到新 iPhone 的过程中,许多用户担心数据丢失或操作步骤繁琐。实际上,苹果已经提供…

2026/7/29 5:25:18 阅读更多 →
网安领域下载量很高的几个离线靶场,学黑客技术一定要知道,一文带你介绍这几个靶场下载、安装和使用

网安领域下载量很高的几个离线靶场,学黑客技术一定要知道,一文带你介绍这几个靶场下载、安装和使用

在网络安全学习中,靶场是所有零基础小白、入门白帽子黑客最核心的练习工具。相比于一些在线靶场网速卡顿、环境重置、名额限制、做题收费等问题,离线靶场支持本地部署、永久使用、自由复现、可反复调试漏洞,完全满足个人合法练手需求&#xf…

2026/7/29 5:25:18 阅读更多 →
5 种将视频从 iPhone 发送到荣耀手机的实用方法

5 种将视频从 iPhone 发送到荣耀手机的实用方法

当用户从 iPhone 切换到 HONOR 手机,或者同时使用两款设备时,他们很快就会发现,从 iPhone 向 HONOR 手机发送视频并不像想象中那么简单。由于iOS和Android系统完全不同,因此无法使用隔空投送 (AirDrop) 等功能。正因如此&#xff…

2026/7/29 5:25:18 阅读更多 →
内置MOS升压恒流LED驱动芯片OC6700B应用详解

内置MOS升压恒流LED驱动芯片OC6700B应用详解

1. 项目概述:从一颗芯片看LED驱动设计的进化最近在做一个户外亮化项目,客户要求用单节锂电池驱动一串20颗的LED灯珠,还要保证亮度稳定。这个需求听起来简单,但实际一算就头疼:单节锂电满电4.2V,放到3V左右就…

2026/7/29 5:25:18 阅读更多 →
从0到1:企业级AI项目迭代日记 Vol.76|能生成,不等于能消化

从0到1:企业级AI项目迭代日记 Vol.76|能生成,不等于能消化

今天有两个问题,都出在同一个方向:AI执行完成,结果体积很大,系统在读取这个结果时出了错。这是AI系统里最难发现的一类问题——执行链走完了,但信息在中转点悄悄丢了,而系统表面上“没有报错”。一、结果读…

2026/7/29 5:24:18 阅读更多 →

日新闻

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:00:23 阅读更多 →
AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础 在上一期「AI编程系列」中,我们学习了如何构建一个基础的 AI 问答系统,通过简单的输入输出让模型回应问题。但现实世界中的 AI 应用往往需要处理更复杂的场景:…

2026/7/29 0:00:23 阅读更多 →
AI智能体开发实战:从工具调用到企业级部署

AI智能体开发实战:从工具调用到企业级部署

1. 从被动问答到主动执行:AI Agent的范式转变过去两年,大语言模型最显著的应用形态是聊天机器人——用户提问,AI回答。但真正的生产力革命发生在2023年下半年:当AI学会主动调用工具完成任务时,生产力工具的历史被彻底改…

2026/7/29 0:00:23 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/28 12:04:22 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/28 8:29:16 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/28 5:03:42 阅读更多 →

月新闻