用 React 搞定第一个企业级小项目:从安装到实战全过程
引言:我为什么选择写这篇入门教程?

去年年底,我在一个中小型互联网公司担任前端开发,接到一个新的任务:为公司内部的审批流程系统构建一个前端模块。虽然这个模块功能不算复杂,但需要快速迭代、界面响应及时,并且要和其他模块兼容良好。最终我们决定尝试使用 React 来构建这次的小型前端应用。
这并不是一个“Hello World”级别的 demo,而是一个真正要在生产环境运行的应用。也正是在这个过程中,我对 React 的理解从概念逐步深入到实践层面,也踩了不少坑——比如状态管理混乱、组件拆分不合理、性能优化不到位等。
今天我想通过这篇文章,带大家从零开始搭建一个 React 应用,并结合我在实际项目中的经验和教训,讲清楚安装配置、编码实践、常见问题和注意事项。希望你也能在阅读后迅速上手自己的第一个 React 应用。
项目背景:一个小需求背后的技术选型

我们的审批模块需要实现以下几个核心功能:
- 展示待审批列表
- 支持点击查看详情并进行操作(如通过/驳回)
- 表单数据需要实时保存草稿
- 考虑未来可能接入移动端支持
考虑到团队中大多数人是 Vue 用户,但我们想尝试引入新技术栈,以提升整体技术能力。于是经过讨论,选择了 React + TypeScript + Tailwind CSS 组合来作为本次试点项目的框架选型。
React 在社区中的活跃度、生态丰富度以及组件化思想对我们来说都非常适合这次的模块结构设计。
技术挑战与关键决策点
1. 开发环境的搭建
最开始我们在搭建本地开发环境时就遇到了不少问题:
- Webpack 配置过于复杂
- Babel 编译器版本不兼容
- 不同开发人员机器配置差异导致依赖冲突
解决方案:直接使用 Create React App (CRA)
虽然 CRA 提供的封装屏蔽了底层细节,但也极大提升了初始开发效率。对于新手或小型项目而言,这是非常友好的选择。后期如果确实有定制需求,再用 eject 命令解构也不迟。
2. 状态管理的初步规划
审批系统涉及到多个层级的状态管理:
- 审批详情页中的表单项状态
- 列表页面与详情页之间的切换逻辑
- 用户权限控制影响按钮是否可见
我们一开始使用全局状态管理(context + reducer),但在开发过程中发现某些组件之间状态传递不够清晰,代码逐渐变得难以维护。
后来我们改为局部状态 + props 传值为主的模式,同时对部分共享状态采用了 Redux Toolkit 来做统一管理,效果好了很多。
实战篇:一步步搭建你的第一个 React 应用
第一步:创建项目
npx create-react-app my-approval-system --template typescript
我建议你加上
--template typescript参数,因为 TS 对类型安全和团队协作真的非常有帮助。而且现在的主流 IDE 如 VSCode 已经很好地支持了 React + TypeScript 的自动补全和类型提示。
进入项目目录后:
cd my-approval-system
npm start
这时你应该能看到默认的 “Welcome to React” 页面在浏览器里跑起来了。
第二步:组织目录结构
别急着写代码!先理清结构。我在项目初期没有好好设计目录,导致后面改了很多次结构,浪费了不少时间。
最终我们采用如下结构:
src/
│
├── components/ // 可复用 UI 组件
│ ├── ApprovalCard.tsx
│ └── StatusBadge.tsx
│
├── pages/ // 页面组件
│ ├── DashboardPage.tsx
│ └── DetailPage.tsx
│
├── hooks/ // 自定义 hook
│ └── useApprovalStatus.ts
│
├── store/ // 状态管理相关
│ ├── approvalSlice.ts
│ └── store.ts
│
├── utils/ // 工具函数
│ └── formatUtils.ts
│
└── App.tsx // 主入口
第三步:从简单组件开始 —— 构建审批卡片
我们要展示审批列表,所以第一步是做一个可复用的 ApprovalCard 组件:
// components/ApprovalCard.tsx
import React from 'react';
interface Props {
title: string;
status: 'pending' | 'approved' | 'rejected';
onClick: () => void;
}
const ApprovalCard: React.FC<Props> = ({ title, status, onClick }) => {
const getStatusColor = () => {
switch(status) {
case 'approved': return 'bg-green-100 text-green-800';
case 'rejected': return 'bg-red-100 text-red-800';
default: return 'bg-yellow-100 text-yellow-800';
}
};
return (
<div
className="border rounded p-4 mb-4 cursor-pointer hover:shadow-md transition-shadow"
onClick={onClick}
>
<div className="flex justify-between items-center">
<h3 className="text-lg font-semibold">{title}</h3>
<span className={`px-3 py-1 rounded-full text-sm ${getStatusColor()}`}>
{status}
</span>
</div>
</div>
);
};
export default ApprovalCard;
这里用到了 Tailwind CSS 类名来快速美化样式。如果你不熟悉 Tailwind,我建议花一点时间学习一下,它能让前端 UI 开发效率大幅提升。
第四步:接入状态管理
早期我们尝试使用 Context API 做状态管理,后来改用 Redux Toolkit,主要是因为它更简单高效。
首先安装依赖:
npm install @reduxjs/toolkit react-redux
然后创建一个简单的 slice:
// store/approvalSlice.ts
import { createSlice } from '@reduxjs/toolkit';
interface ApprovalState {
approvals: Array<{ id: number; title: string; status: string }>;
}
const initialState: ApprovalState = {
approvals: [
{ id: 1, title: '采购申请 #001', status: 'pending' },
{ id: 2, title: '出差报销 #005', status: 'approved' }
]
};
const approvalSlice = createSlice({
name: 'approvals',
initialState,
reducers: {}
});
export default approvalSlice.reducer;
最后在 store/store.ts 中组合起来:
import { configureStore } from '@reduxjs/toolkit';
import approvalReducer from './approvalSlice';
export const store = configureStore({
reducer: {
approvals: approvalReducer
}
});
并在 index.tsx 中注册:
import { Provider } from 'react-redux';
import { store } from './store/store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
这样我们就能在各个组件中使用 store 的数据了。
踩坑经验分享
1. useEffect 内存泄漏问题
在处理异步请求时,我们没注意清理副作用,导致出现内存泄漏警告。比如:
useEffect(() => {
fetchData().then(data => setData(data));
}, []);
解决方法很简单,加个 cleanup 函数即可:
useEffect(() => {
let mounted = true;
fetchData().then(data => {
if (mounted) setData(data);
});
return () => {
mounted = false;
};
}, []);
当然也可以使用 async 函数配合 AbortController 控制请求生命周期,这也是一个更好的做法。
2. 组件更新频繁的问题
有些组件因为 props 是对象或者数组,每次父组件 rerender 导致子组件都重新 render。
这时候可以考虑使用 React.memo() 包裹组件,或者使用 useCallback 固定回调地址:
const handleApprove = useCallback((id) => {
dispatch(approveAction(id));
}, [dispatch]);
这样能避免不必要的重复渲染。
性能优化 & 调试小技巧
1. 使用 DevTools 进行调试
Chrome 插件 React Developer Tools 和 Redux DevTools Extension 非常实用。它们可以帮助你查看组件树、props、state、action dispatch 等信息,特别适合排查状态更新问题。
2. 打包优化
上线前记得用 Webpack Bundle Analyzer 分析打包体积:
npm install --save-dev webpack-bundle-analyzer
然后修改 package.json:
"scripts": {
"build": "react-scripts build",
"analyze": "source-map-explorer 'build/static/js/*.js'"
}
运行:
npm run build && npm run analyze
你会看到一张分析图,帮你找到大体积文件,从而做出合理优化。
最终成果与收获总结
项目交付后,我们得到了业务部门的好评,审批流程的交互体验明显优于之前的旧系统。整个项目周期大约两周,其中用了不到两天就完成了基础结构搭建,剩下的时间都在打磨细节和修复 bug。
我们获得的收益包括:
- 组件化设计让代码复用率提高 60%+
- 状态管理更加清晰可控
- 团队协作效率提升,TS 提高了代码健壮性
- 后续扩展成本低,新同事上手快
同时也积累了宝贵的经验:
- React 并非万能,但它非常适合组件化的 UI 场景
- 技术选型要匹配团队能力和项目复杂度
- 工程规范比工具链更重要,特别是多人协作时
- 上线前一定要测试移动端适配和性能表现
给初学者的一些建议
不要死磕文档,多动手写代码
- 实践是最好的老师,跟着官方文档一步一步敲出来,哪怕是复制也要认真过一遍。
从小项目练起
- 像 TodoList、天气预报这种轻量应用很适合练手,既能巩固知识又不至于一开始就放弃。
学会看报错信息
- JS 错误往往就在控制台里,不要害怕红字。慢慢你就习惯了看 stack trace 定位问题。
保持关注社区动态
- React 的发展非常快,像 Server Components、React Compiler 新特性都值得关注。
坚持写笔记和总结
- 我现在仍然会把遇到的问题记下来,回头看看真的很香!
结语:从 Hello World 到正式项目其实并不远
这是我第一次独立负责一个 React 应用的真实经历,中间有迷茫、也有收获。我希望你能通过这篇文章少走一些弯路,更快地上手 React 的实战开发。
记住一句话:“学编程最重要的不是掌握多少语法,而是写出让人看得懂、能运行、还够优雅的代码。”愿你在 React 的路上越走越远,加油!

评论 0