从零到第一个React应用:我的实战入门之路
我是在一家中型互联网公司做前端开发的,日常工作涉及到大量的用户交互界面设计与实现。随着业务需求的增长和前端技术的迭代更新,我们团队也在不断尝试引入一些更高效、结构更清晰的技术方案来应对日益复杂的项目规模。就在去年,我们决定在新项目中全面采用 React 作为主要开发框架。
说实话,React 的学习曲线对我个人来说不算太陡峭,但作为一个刚接触前端不久的开发者,我还是经历了不少曲折。今天我想结合自己的真实工作经历,写一篇比较“接地气”的 React 入门教程,帮助那些想快速上手 React 并用它做出第一个项目的小伙伴少走弯路。
背景 & 动机:为什么要学 React?

先说一下我们项目的背景。我们正在做一个内部使用的数据管理平台,需要频繁地处理各种动态表格、筛选条件、图表展示,以及实时状态更新等功能。传统的 jQuery 和 Vue.js 虽然也能胜任,但当我们面临组件复用、状态管理和工程化维护的需求时,还是觉得需要一个更灵活、更具伸缩性的解决方案。
而 React 正好满足了这些需求:它允许我们将 UI 拆分为独立可复用的组件,并且拥有非常活跃的社区生态和强大的生态系统支持(如 Redux、React Router、Ant Design 等),这让我们对未来的扩展性有了更多信心。
于是,我开始了 React 的学习之旅,目标是用它做出我们项目的第一个原型页面——一个简单的员工信息管理系统。
遇到的第一个挑战:React 到底怎么装?Create React App 还是自己配 Webpack?


刚开始的时候,最大的问题其实并不是写代码,而是不知道该如何搭建一个最基本的 React 工程环境。
网上一搜,“推荐使用 Create React App”几乎是标准答案。那我也下载了一个试试看:
npx create-react-app my-first-app
然后进入目录运行 npm start,本地服务器就跑起来了,默认打开一个欢迎页。看起来一切顺利,但问题是:我完全看不懂这个脚手架背后发生了什么。Webpack 配置文件在哪?Babel 是怎么配置的?ESLint 怎么生效的?如果我要改个默认端口号怎么办?
当时我就有点懵圈。后来我才意识到,虽然 CRA 很方便,但对于像我这样喜欢“搞明白原理”的人来说,直接上来就用,反而会成为一种负担。
我的选择:先自己搭一个迷你版本,再回到 CRA
为了理解流程,我决定从头开始手动搭建一个极简版本的 React 开发环境。这样虽然费劲,但对我理解模块打包机制很有帮助。
步骤如下:
创建项目文件夹:
mkdir my-simple-react-app && cd my-simple-react-app npm init -y安装基础依赖:
npm install react react-dom npm install --save-dev webpack webpack-cli webpack-dev-server html-webpack-plugin npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader编写
webpack.config.js:const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-react'] } } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './public/index.html' }) ], devServer: { static: './dist', port: 3001 } };创建
.babelrc:{ "presets": ["@babel/preset-env", "@babel/preset-react"] }添加入口 HTML 文件
public/index.html:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>My First React App</title> </head> <body> <div id="root"></div> </body> </html>创建主入口
src/index.js:import React from 'react'; import ReactDOM from 'react-dom/client'; const App = () => { return ( <div> <h1>Hello, React!</h1> </div> ); }; const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />);在
package.json中添加启动脚本:"scripts": { "start": "webpack serve" }
执行 npm start 后,在浏览器访问 http://localhost:3001,就能看到 “Hello, React!” 的页面了!
第二个挑战:如何组织组件结构与状态管理?

接下来,我就开始着手写我们的“员工信息管理系统”。页面大概包括几个部分:顶部搜索栏、员工列表、详情模态框、新增按钮等。
起初我觉得每个部分都单独写成一个组件应该挺好,但写着写着发现一个问题:多个组件之间需要共享状态,比如当前选中的员工、筛选条件、是否显示详情面板等等。
最开始我只是简单用父子组件传 props 来传递数据,但当组件层级变深之后,传参变得越来越臃肿,维护起来也困难。
这时候我想到之前学过的 Context API,便尝试将其用于状态共享。例如,将员工列表封装在一个 Provider 组件中,子组件通过 useContext 获取当前选中的员工数据:
// EmployeeContext.jsx
import React, { createContext, useState } from 'react';
const EmployeeContext = createContext();
export const EmployeeProvider = ({ children }) => {
const [selectedEmployee, setSelectedEmployee] = useState(null);
return (
<EmployeeContext.Provider value={{ selectedEmployee, setSelectedEmployee }}>
{children}
</EmployeeContext.Provider>
);
};
export default EmployeeContext;
然后在父组件中包裹子组件:
import { EmployeeProvider } from './EmployeeContext';
function App() {
return (
<EmployeeProvider>
<SearchBar />
<EmployeeList />
<EmployeeDetailsModal />
</EmployeeProvider>
);
}
子组件中直接使用:
import React, { useContext } from 'react';
import EmployeeContext from './EmployeeContext';
const EmployeeDetailsModal = () => {
const { selectedEmployee } = useContext(EmployeeContext);
return selectedEmployee ? (
<div className="modal">
<h3>{selectedEmployee.name}</h3>
<p>Email: {selectedEmployee.email}</p>
</div>
) : null;
};
虽然这个方案解决了组件间通信的问题,但在实际工作中我们逐渐发现,当状态变得越来越多、逻辑越来越复杂时,这种做法也开始显得力不从心。
于是我们评估了一下,最终选择了 Redux Toolkit 作为状态管理方案。它相比传统 Redux 写法要简洁得多,而且官方推荐度高,适合大多数中小型项目。
实战演练:构建一个员工管理应用
下面是我用 React 构建的一个简化版员工管理系统的结构图:
my-first-react-app/
├── public/
│ └── index.html
├── src/
│ ├── components/
│ │ ├── SearchBar.jsx
│ │ ├── EmployeeList.jsx
│ │ └── EmployeeDetailsModal.jsx
│ ├── store/
│ │ ├── employeeSlice.js
│ │ └── store.js
│ ├── App.jsx
│ └── main.jsx
├── package.json
└── webpack.config.js
关键点说明:
main.jsx是主入口文件,创建根 DOM 并挂载 App;employeeSlice.js使用 Redux Toolkit 定义 slice;- 所有组件统一从 store 获取数据或 dispatch action;
- 每个组件职责单一,便于测试与维护。
Redux 示例代码
定义 Slice(员工相关状态):
// src/store/employeeSlice.js
import { createSlice } from '@reduxjs/toolkit';
const employeeSlice = createSlice({
name: 'employees',
initialState: {
list: [],
selectedId: null
},
reducers: {
selectEmployee: (state, action) => {
state.selectedId = action.payload;
}
}
});

export const { selectEmployee } = employeeSlice.actions;
export default employeeSlice.reducer;
创建 Store:
// src/store/store.js
import { configureStore } from '@reduxjs/toolkit';
import employeeReducer from './employeeSlice';
const store = configureStore({
reducer: {
employees: employeeReducer
}
});
export default store;
组件中使用:
// src/components/EmployeeList.jsx
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { selectEmployee } from '../store/employeeSlice';
const EmployeeList = () => {
const employees = [{ id: 1, name: '张三', email: 'zhangsan@example.com' }];
const dispatch = useDispatch();
const handleSelect = (id) => {
dispatch(selectEmployee(id));
};
return (
<ul>
{employees.map(emp => (
<li key={emp.id} onClick={() => handleSelect(emp.id)}>
{emp.name}
</li>
))}
</ul>
);
};
export default EmployeeList;
踩坑经验分享:React 开发中的那些事
坑 1:函数组件中无法使用 findDOMNode
我们有个组件需要用到 DOM 操作,比如点击某个区域展开内容。一开始用了 ReactDOM.findDOMNode() 方法,结果控制台报错:
Warning: findDOMNode is deprecated in StrictMode.
因为 React 新版本在严格模式下禁用了 findDOMNode,所以需要用 ref 来代替。
解决方式很简单,使用 useRef Hook:
const containerRef = useRef(null);
useEffect(() => {
// containerRef.current 就是 DOM 元素
}, []);
坑 2:事件绑定重复触发
我在一个自定义组件里绑定了一个点击事件,但每次点击后函数都会执行多次。排查后发现是因为我把函数定义放到了组件体内而不是 useCallback 中:
const MyComponent = () => {
const handleClick = () => {
console.log('Clicked!');
};
return <button onClick={handleClick}>Click me</button>;
};
虽然看起来没问题,但如果这个组件被反复渲染(比如父组件频繁刷新),可能会导致重复绑定事件。更合理的方式是加上 useCallback:
const handleClick = useCallback(() => {
console.log('Clicked!');
}, []);
坑 3:跨域请求失败
开发过程中遇到接口调用失败的问题,提示“Blocked by CORS policy”。这是前端开发中最常见的问题之一。为了解决这个问题,我们在本地开发时通过 proxy 解决:
// package.json 中加入代理设置
"proxy": "http://api.myproject.com",
然后所有 /api/** 请求都会转发到对应的后端地址,避免跨域。
效果总结:React 给我带来了什么?
整个项目做完后,我觉得 React 带来的最大优势体现在以下几个方面:
- 组件化思维:真正做到了“关注分离”,让 UI 结构更加清晰,后期维护成本大大降低;
- 生态圈强大:从路由(React Router)、表单验证(Formik、Yup)、UI 库(Ant Design),到调试工具(React Developer Tools),社区提供的资源丰富;
- 开发体验提升:配合 Hot Module Replacement、TypeScript 支持、Prettier 自动格式化等,工作效率提高不少;
- 性能优化空间大:可以通过 memo、useMemo、useCallback 等手段精细化控制渲染行为,做到高性能和良好的用户体验。
给新手的一些建议
如果你也是一个刚准备入坑 React 的新手,以下几点建议希望对你有帮助:
- 不要一开始就追求完美架构:可以先从 Create React App 入手,先把功能跑起来,再去深入理解背后的机制。
- 多动手,少看理论视频:很多概念你不写一遍根本记不住,尤其是 Hooks 和状态管理这些内容。
- 别怕踩坑,遇到问题先自己尝试解决:查文档、看 GitHub Issues、Stack Overflow,都是很好的途径。
- 善用浏览器开发者工具:React DevTools 可以让你看到组件树、props、context 值的变化,非常实用。
- 尽早使用 TypeScript:虽然不是必须,但 TypeScript 能提前帮你发现许多潜在 bug,值得投入时间学习。
- 保持好奇心和持续学习的态度:React 社区发展很快,比如最近推出的 Server Components、Streaming SSR 等新特性,值得关注并实践。
最后的感悟:写代码不止是写代码
React 学习的过程让我明白,编程不仅仅是敲几行代码解决问题,更是一种思考问题、抽象结构、优化协作的能力训练。特别是在我们团队实践中,React 的组件化理念让我们更容易分工协作,提升了整体开发效率。
现在回过头来看,那个曾经让我望而却步的“虚拟 DOM”、“JSX 语法”、“Hooks 原理”,如今也都成了日常工作的标配。而我也不再只是复制粘贴示例代码的新手,而是能够根据需求选择合适的技术方案,独立完成组件开发甚至状态管理的规划。
React 未必是前端世界的终点,但它的确是一个起点,通向更高阶、更优雅的前端开发之路。
作者简介:我在某互联网公司担任前端工程师,热爱开源社区和技术写作,热衷于用技术推动产品迭代与用户体验提升。希望这篇文章能给还在 React 路上摸索的你带来一些启发和帮助。

评论 0