从零跑通React:一个全栈打杂仔的实战踩坑日记
上周五晚上九点半,办公室只剩我和隔壁组的运维小哥还在对着屏幕发呆。他忙着救火——又一个K8s集群挂了;我则在和Node版本打架,因为产品经理临时加了个需求:“咱们后台管理界面能不能用React重写一下?下周三上线。”
我当时差点把MacBook合上走人。
但没办法,谁让我是创业公司唯一的“全栈开发”呢?前端、后端、数据库、部署、甚至帮UI设计师调色……啥都得干。入职才两个月,已经写了三个微服务、两个爬虫脚本,还顺手修了测试同学提的二十多个Jira单子。React?说实话,之前只在GitHub上点过star,自己从来没正经搭过环境。
不过也好,正好借这个机会系统学一遍。毕竟咱这种小公司,没人给你写详细文档,更没有资深前端带你飞。一切靠自己,要么卷死,要么跑路。
于是周末两天没出门,泡了三壶咖啡,翻烂了一本《React学习手册》(其实是从公司书架上顺来的),终于把第一个React应用跑起来了。这篇文章,就是记录下那些让我半夜想砸键盘的坑,以及一些实用的小技巧——尤其是当你像我一样,既要写页面又要搞数据抓取的时候。
为什么选React?不是Vue不香吗?
先说句实话:我其实更喜欢Vue。语法简洁,文档友好,上手快。但在我们公司,技术栈早就定死了——后端用Go + Gin,前端统一React + TypeScript。理由?CTO去年在某大厂待过,觉得React生态更“企业级”。
行吧,那就React。
不过话说回来,React确实有它的优势。比如组件化思维特别清晰,状态管理虽然复杂但灵活,而且社区资源多到爆炸。你遇到的任何问题,Stack Overflow上基本都有人踩过坑。再加上我们最近在搞一个内部数据监控平台,需要对接好几个爬虫服务(对,就是我写的Python脚本),前端得频繁拉取动态数据——React的useEffect + fetch组合拳,写起来还挺顺手。
别信网上那些“一行命令搞定”的鬼话
很多教程一上来就说:“运行 npx create-react-app my-app 就完事了!”
听起来很简单对吧?但现实是——你的Node版本可能不对,npm缓存可能炸了,网络可能被墙,甚至Mac的权限都可能拦你一道。
我第一次执行时,终端直接报:
Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/.cache'
啊?我可是用Mac开发的!怎么连个目录都建不了?后来才发现,之前为了装某个全局工具用了sudo,结果把.cache目录的owner搞成了root。解决办法很简单:
sudo chown -R $(whoami) /usr/local/lib/node_modules/.-cache
但如果你不知道底层原理,光看报错根本无从下手。这也是为什么我一直坚持:前端不能只写JSX,得懂点系统、懂点网络、懂点构建流程。
正确的安装姿势(2024年最新)
截至今天(2024年6月),推荐的方式其实是用 Vite 而不是 Create React App(CRA)。原因有三:
- 快:Vite基于ES模块原生加载,冷启动秒开,HMR(热更新)快如闪电;
- 轻:CRA封装太重,Webpack配置藏得深,想改个Babel插件都得弹出(eject),而Vite配置透明;
- 现代:默认支持TypeScript、CSS Modules、JSX自动引入等新特性。
所以我的操作是:
npm create vite@latest my-react-app -- --template react-ts
cd my-react-app
npm install
npm run dev
几秒钟后,本地 http://localhost:5173 就跑起来了。清爽,干净,没有一堆看不懂的依赖。
💡 小贴士:如果你公司还在用CRA,别急着换。但新项目,闭眼选Vite。
第一个组件:别只写Hello World
大多数教程到这里就结束了:“恭喜你,成功运行了React!”
但现实项目哪有这么简单?我们需要的是能干活的页面,比如展示爬虫抓回来的数据。
假设我们有个后端API:/api/scraped-data,返回如下JSON:
{
"items": [
{ "id": 1, "title": "某电商商品A", "price": "¥299" },
{ "id": 2, "title": "某新闻标题B", "price": null }
]
}
我们的任务:在React页面上渲染这个列表,并处理加载状态和错误。
关键代码(带注释)
// src/components/DataList.tsx
import { useState, useEffect } from 'react';
interface ScrapedItem {
id: number;
title: string;
price: string | null;
}
export default function DataList() {
const [data, setData] = useState<ScrapedItem[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch('/api/scraped-data');
if (!res.ok) throw new Error('Network response was not ok');
const json = await res.json();
setData(json.items);
} catch (err) {
setError((err as Error).message);
} finally {
setLoading(false);
}
};
fetchData();
}, []); // 注意空依赖数组:只在组件挂载时请求一次
if (loading) return <div>正在从爬虫服务器拉取数据……</div>;
if (error) return <div>出错了:{error}</div>;
return (
<ul>
{data.map(item => (
<li key={item.id}>
<strong>{item.title}</strong>
{item.price && <span> — {item.price}</span>}
</li>
))}
</ul>
);
}
这段代码看似简单,但包含了几个生产级实践:
- 使用
useState管理三种状态:数据、加载中、错误; useEffect模拟componentDidMount,避免重复请求;- 错误边界虽未实现,但至少做了基础错误提示;
- 列表项用
key={item.id}避免React警告(别用index!); - 对
price字段做空值判断,防止渲染null字符串。
调试技巧:别只会 console.log
刚写完组件,发现页面空白。打开DevTools一看,Network里API返回200,但页面就是不显示。
这时候,很多人会疯狂加 console.log(data)。但更好的方式是:
- 用React DevTools:Chrome插件,可以直接查看组件状态树;
- 开启Strict Mode:Vite模板默认已开启,能帮你发现副作用问题;
- 用TS类型守卫:比如上面的
ScrapedItem接口,如果后端字段变了,编译直接报错,而不是运行时报undefined is not a function。
有一次我爬虫返回的字段名是 product_title,但我前端写成了 title,结果页面一直空着。后来靠TS接口定义一眼就发现了问题——这比肉眼debug快多了。
书籍 vs 爬虫:两种学习路径
说到学习React,我发现身边有两种人:
| 类型 | 学习方式 | 优点 | 缺点 |
|---|---|---|---|
| 书虫型 | 买《React权威指南》《深入React技术栈》,逐章精读 | 基础扎实,理解原理 | 容易陷入理论,动手慢 |
| 爬虫型 | 直接扒GitHub热门项目代码,边抄边改 | 上手快,解决问题导向 | 容易写出“能跑但烂”的代码 |
我自己其实是混合型:先快速跑通一个demo(爬虫式),再回头看书补原理(书虫式)。比如这次,我先用Vite跑起项目,然后翻《React学习手册》第5章“状态与副作用”,才真正理解 useEffect 的依赖数组机制。
📚 强烈推荐:Dan Abramov(React核心成员)写的 Just JavaScript 虽然不讲React,但能帮你打通JS底层认知——这对理解React的渲染机制至关重要。
性能与兼容性:别等上线才后悔
创业公司节奏快,经常为了赶deadline忽略性能。但作为全栈,我吃过亏:去年双11期间,一个没做懒加载的列表页直接把用户浏览器卡死,导致转化率暴跌。
所以在写React组件时,我会默认考虑:
- 列表虚拟滚动:超过50条就上
react-window; - 避免内联回调:用
useCallback包裹事件处理器; - 图片懒加载:
<img loading="lazy" />; - 浏览器兼容:虽然我们主要用Chrome,但测试同学总拿Safari测,所以记得检查
fetch、Promise等是否需polyfill(Vite默认处理了大部分)。
另外,别忘了在 vite.config.ts 里加上:
export default defineConfig({
build: {
target: 'es2015', // 兼容现代浏览器
sourcemap: true // 方便线上错误定位
}
})
最后:React只是工具,解决问题才是目的
折腾两天后,我的React后台页面终于上线了。产品经理看了一眼,说:“能不能把字体调大一点?”
我默默改了行CSS,心里却在笑:当初那个连 npx 都跑不通的人,现在居然能独立交付一个带状态管理、错误处理、类型安全的React应用了。
创业公司的全栈开发,本质上是个“问题解决机”。React、爬虫、数据库、部署……技术只是手段。重要的是,你能用最短路径把需求变成可运行的代码。
所以别纠结“该不该学React”,而是问自己:“我现在有什么问题需要用它解决?”
如果你也刚入行,或者像我一样被逼着学新技术,记住:每个大神都曾被Hello World卡住过。关键不是不踩坑,而是踩了之后能爬出来,还能写篇博客帮别人绕过去。
哦对了,那本《React学习手册》我放回书架了——但书签夹在第7章,因为下周要搞React Router。
(运维小哥刚发消息说K8s好了,我去合并PR了。)

评论 0