从零到第一个React应用:我的实战入门之路

写码的阿川
2025-06-26 04:30
阅读 735

我是在一家中型互联网公司做前端开发的,日常工作涉及到大量的用户交互界面设计与实现。随着业务需求的增长和前端技术的迭代更新,我们团队也在不断尝试引入一些更高效、结构更清晰的技术方案来应对日益复杂的项目规模。就在去年,我们决定在新项目中全面采用 React 作为主要开发框架。

说实话,React 的学习曲线对我个人来说不算太陡峭,但作为一个刚接触前端不久的开发者,我还是经历了不少曲折。今天我想结合自己的真实工作经历,写一篇比较“接地气”的 React 入门教程,帮助那些想快速上手 React 并用它做出第一个项目的小伙伴少走弯路。


背景 & 动机:为什么要学 React?

背景 & 动机:为什么要学 React?

先说一下我们项目的背景。我们正在做一个内部使用的数据管理平台,需要频繁地处理各种动态表格、筛选条件、图表展示,以及实时状态更新等功能。传统的 jQuery 和 Vue.js 虽然也能胜任,但当我们面临组件复用、状态管理和工程化维护的需求时,还是觉得需要一个更灵活、更具伸缩性的解决方案。

而 React 正好满足了这些需求:它允许我们将 UI 拆分为独立可复用的组件,并且拥有非常活跃的社区生态和强大的生态系统支持(如 Redux、React Router、Ant Design 等),这让我们对未来的扩展性有了更多信心。

于是,我开始了 React 的学习之旅,目标是用它做出我们项目的第一个原型页面——一个简单的员工信息管理系统。


遇到的第一个挑战:React 到底怎么装?Create React App 还是自己配 Webpack?

JavaScript框架对比-1

遇到的第一个挑战:React 到底怎么装?Create React App 还是自己配 Webpack?

刚开始的时候,最大的问题其实并不是写代码,而是不知道该如何搭建一个最基本的 React 工程环境。

网上一搜,“推荐使用 Create React App”几乎是标准答案。那我也下载了一个试试看:

npx create-react-app my-first-app

然后进入目录运行 npm start,本地服务器就跑起来了,默认打开一个欢迎页。看起来一切顺利,但问题是:我完全看不懂这个脚手架背后发生了什么。Webpack 配置文件在哪?Babel 是怎么配置的?ESLint 怎么生效的?如果我要改个默认端口号怎么办?

当时我就有点懵圈。后来我才意识到,虽然 CRA 很方便,但对于像我这样喜欢“搞明白原理”的人来说,直接上来就用,反而会成为一种负担。

我的选择:先自己搭一个迷你版本,再回到 CRA

为了理解流程,我决定从头开始手动搭建一个极简版本的 React 开发环境。这样虽然费劲,但对我理解模块打包机制很有帮助。

步骤如下:

  1. 创建项目文件夹:

    mkdir my-simple-react-app && cd my-simple-react-app
    npm init -y
    
  2. 安装基础依赖:

    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
    
  3. 编写 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
      }
    };
    
  4. 创建 .babelrc

    {
      "presets": ["@babel/preset-env", "@babel/preset-react"]
    }
    
  5. 添加入口 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>
    
  6. 创建主入口 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 />);
    
  7. 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;
    }
  }
});


![CSS动画效果展示-2](https://code-guide.oss.shanghai.autogptai.club/common/file/download?name=date2025062604/9e0a996d-5a41-4d3e-b05a-c9a2635d84a7.jpg)


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 的新手,以下几点建议希望对你有帮助:

  1. 不要一开始就追求完美架构:可以先从 Create React App 入手,先把功能跑起来,再去深入理解背后的机制。
  2. 多动手,少看理论视频:很多概念你不写一遍根本记不住,尤其是 Hooks 和状态管理这些内容。
  3. 别怕踩坑,遇到问题先自己尝试解决:查文档、看 GitHub Issues、Stack Overflow,都是很好的途径。
  4. 善用浏览器开发者工具:React DevTools 可以让你看到组件树、props、context 值的变化,非常实用。
  5. 尽早使用 TypeScript:虽然不是必须,但 TypeScript 能提前帮你发现许多潜在 bug,值得投入时间学习。
  6. 保持好奇心和持续学习的态度:React 社区发展很快,比如最近推出的 Server Components、Streaming SSR 等新特性,值得关注并实践。

最后的感悟:写代码不止是写代码

React 学习的过程让我明白,编程不仅仅是敲几行代码解决问题,更是一种思考问题、抽象结构、优化协作的能力训练。特别是在我们团队实践中,React 的组件化理念让我们更容易分工协作,提升了整体开发效率。

现在回过头来看,那个曾经让我望而却步的“虚拟 DOM”、“JSX 语法”、“Hooks 原理”,如今也都成了日常工作的标配。而我也不再只是复制粘贴示例代码的新手,而是能够根据需求选择合适的技术方案,独立完成组件开发甚至状态管理的规划。

React 未必是前端世界的终点,但它的确是一个起点,通向更高阶、更优雅的前端开发之路。


作者简介:我在某互联网公司担任前端工程师,热爱开源社区和技术写作,热衷于用技术推动产品迭代与用户体验提升。希望这篇文章能给还在 React 路上摸索的你带来一些启发和帮助。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝