React入门:从安装到第一个应用,一个前端架构师的真实经历

朱伟~
2025-06-18 10:53
阅读 328

初识React——一次项目重构的契机

初识React——一次项目重构的契机

那是个寻常的周二,但对我们团队来说却意义非凡。客户提出对一个旧版后台管理系统进行功能增强和界面重构的需求,而作为技术负责人,我需要在有限时间内做出技术选型决策。

这个系统原本是用jQuery写的,随着功能增多,维护成本越来越高。模块之间的依赖混乱,修改一个地方经常引发意想不到的问题。每次新增需求都像在走钢丝,代码结构不堪重击。

当时我们内部讨论过几种方案:Vue、Angular,还有React。最终决定采用React的主要原因有两个:一是社区活跃度高,二是组件化思想更符合我们的开发习惯。而且公司未来的技术路线也有向React倾斜的趋势,这次正好作为试点项目练兵。

说实话,我之前虽然了解React,但真正在项目中使用还是第一次。心里多少有些没底。不过也正是这种“半只脚踩水”的状态,让我能更真实地体会新手入门时的那种困惑与突破。

这篇文章就想和大家分享一下那次经历,从React环境搭建开始,一步步走到完成第一个可用的应用,中间遇到的问题以及解决方法。如果你正在考虑上手React,或者刚刚迈出第一步,希望我的经验能帮你在路上少摔几个跟头。


第一步:搭环境,为什么这么麻烦?

第一步:搭环境,为什么这么麻烦?

1. Node.js 和 npm 的安装

刚准备入手的时候,第一件事就是装好Node.js和npm(现在也可以选择yarn或pnpm)。很多人会忽略这一步,尤其是非前端出身的同事,总以为写JavaScript就直接浏览器里开干。

我们在本地机器上安装了最新的长期支持版本(LTS)Node.js,同时验证了一下npm是否正常工作:

node -v
npm -v

结果有位新人发现自己的命令行不识别npm,后来才发现是因为权限问题或者没有正确加入PATH。这类小问题其实很常见,特别是在多操作系统环境中,比如Mac和Windows之间切换的时候。

📌 小贴士:建议统一使用nvm(Node Version Manager)来管理不同项目的Node.js版本,这样避免全局污染,也便于协作。


2. 使用Create React App快速起步

为了省去手动配置Webpack、Babel等工具的时间,我们选择了官方推荐的脚手架工具——create-react-app。执行以下命令即可初始化项目:

npx create-react-app my-first-react-app
cd my-first-react-app
npm start

不出意外,这时候应该能看到一个默认页面,里面写着“Welcome to React”。整个过程非常顺滑,这就是Create React App的魅力所在。

但也不是一帆风顺。有次我在公司网络下下载依赖总是失败,后来换成了内网镜像:

npm config set registry https://registry.npmmirror.com

或者直接使用淘宝镜像:

npm install -g cnpm --registry=https://registry.npmmirror.com
cnpm install

这种方式在一些特殊网络环境下确实节省了不少时间。


写第一个组件:从零开始搭一个小应用

用户交互流程图-1

写第一个组件:从零开始搭一个小应用

我们决定做的第一个应用是一个简单的待办事项列表(To-Do List),这是学习React的经典案例之一。虽然是个玩具项目,但我坚持要求大家把它做得尽可能接近真实场景,比如添加数据持久化、样式组织、组件拆分等等。

1. 项目结构初探

进入项目目录之后,你会发现create-react-app已经帮我们生成了一些基础文件:

my-first-react-app/
├── node_modules/
├── public/
│   ├── index.html
├── src/
│   ├── App.css
│   ├── App.js
│   ├── App.test.js
│   ├── index.css
│   ├── index.js
│   └── logo.svg
├── package.json
└── README.md

其中,最核心的就是src/App.jsindex.js。前者是主组件,后者负责将App挂载到页面DOM节点上。

打开index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

看起来有点像是传统的React DOM渲染方式,但在v18之后引入了ReactDOM.createRoot()的新API,提高了性能并更好地支持并发模式。


2. 编写第一个组件:TodoList

我们先创建一个简单的TodoList组件,用来展示任务列表。

src/目录下新建一个components/TodoList.js文件,内容如下:

import React from 'react';

function TodoList({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item.text}</li>
      ))}
    </ul>
  );
}

export default TodoList;

然后在App.js中引入并使用它:

import React from 'react';
import TodoList from './components/TodoList';

function App() {
  const tasks = [
    { text: '学React', done: false },
    { text: '吃午饭', done: true }
  ];

  return (
    <div className="App">
      <h1>我的待办事项</h1>
      <TodoList items={tasks} />
    </div>
  );
}

export default App;

运行效果应该是一排文本列表,显示两个任务。看起来简单,但这正是React组件化的魅力所在——清晰、可复用、易于测试。

不过很快我们就遇到了一个痛点:任务状态怎么管理?用户怎么添加新任务?这就引出了React中最重要的概念之一:状态管理(state)。


状态管理实战:从useState到useEffect

状态管理实战:从useState到useEffect

1. 引入状态管理 useState

为了让任务列表可以动态变化,我们需要引入React的状态机制。我们使用了内置的Hook useState来实现这一点。

我们给App.js加上输入框和按钮,并通过useState来保存当前的任务数组。

import React, { useState } from 'react';
import TodoList from './components/TodoList';

function App() {
  const [tasks, setTasks] = useState([
    { text: '学React', done: false },
    { text: '吃午饭', done: true }
  ]);
  const [newTaskText, setNewTaskText] = useState('');

  const handleAddTask = () => {
    if (newTaskText.trim() === '') return;
    
    const newTask = {
      text: newTaskText,
      done: false
    };
    
    setTasks([...tasks, newTask]);
    setNewTaskText('');
  };

  return (
    <div className="App">
      <h1>我的待办事项</h1>
      <input 
        value={newTaskText}
        onChange={(e) => setNewTaskText(e.target.value)}
        placeholder="输入新任务..."
      />
      <button onClick={handleAddTask}>添加</button>
      <TodoList items={tasks} />
    </div>
  );
}

export default App;

现在你可以输入新任务,并点击“添加”按钮将其显示出来。这是React中最基础但也最关键的一部分——状态驱动视图。

不过还有一个问题:如果刷新页面,所有新增的数据都会丢失。这时候就需要引入持久化机制了。


2. 持久化处理:useEffect + localStorage

我们决定使用localStorage来存储任务列表,这样即使刷新页面也能保留用户数据。

这里就要用到另一个React Hook:useEffect,它可以响应状态变化并做副作用操作,比如保存到本地存储。

更新后的App.js如下:

import React, { useState, useEffect } from 'react';
import TodoList from './components/TodoList';

function App() {
  const [tasks, setTasks] = useState(() => {
    // 初次加载尝试从localStorage读取
    const saved = localStorage.getItem('tasks');
    return saved ? JSON.parse(saved) : [
      { text: '学React', done: false },
      { text: '吃午饭', done: true }
    ];
  });
  
  const [newTaskText, setNewTaskText] = useState('');


![CSS动画效果展示-2](https://code-guide.oss.shanghai.autogptai.club/common/file/download?name=date2025061810/2f3d55c3-a162-4d87-8823-5238908f9da3.jpg)


  useEffect(() => {
    localStorage.setItem('tasks', JSON.stringify(tasks));
  }, [tasks]); // 当tasks变化时执行

  const handleAddTask = () => {
    if (newTaskText.trim() === '') return;
    
    const newTask = {
      text: newTaskText,
      done: false
    };
    
    setTasks([...tasks, newTask]);
    setNewTaskText('');
  };

  return (
    <div className="App">
      <h1>我的待办事项</h1>
      <input 
        value={newTaskText}
        onChange={(e) => setNewTaskText(e.target.value)}
        placeholder="输入新任务..."
      />
      <button onClick={handleAddTask}>添加</button>
      <TodoList items={tasks} />
    </div>
  );
}

export default App;

这样就完成了基本的功能:添加任务、自动保存、页面刷新后恢复数据。虽然这只是个小例子,但它涵盖了React开发中常见的状态管理、生命周期控制、数据持久化等多个关键点。


拆分组件:从单文件走向模块化

随着功能越来越多,我们开始意识到把所有逻辑都塞在一个组件里越来越难维护。于是我们决定进一步拆分成多个小组件。

比如:

  • TodoInput:专门处理任务输入框和添加按钮
  • TodoItem:每个单独的任务项,包括是否完成的状态标记

这样的组件划分不仅让代码更清晰,还便于后续扩展,例如将来可能要添加任务编辑、删除等功能。

下面是TodoInput.js的一个示例实现:

import React from 'react';

function TodoInput({ onAddTask }) {
  const [text, setText] = useState('');

  const handleKeyDown = (e) => {
    if (e.key === 'Enter' && text.trim()) {
      onAddTask(text);
      setText('');
    }
  };

  return (
    <div>
      <input 
        value={text}
        onChange={(e) => setText(e.target.value)}
        onKeyDown={handleKeyDown}
        placeholder="输入新任务..."
      />
      <button onClick={() => {
        if (text.trim()) {
          onAddTask(text);
          setText('');
        }
      }}>添加</button>
    </div>
  );
}

export default TodoInput;

这种做法让我们在开发过程中逐渐体会到组件复用的好处,尤其是在项目规模不断扩大的时候。


性能优化与调试技巧

虽然只是一个入门级项目,但我们已经开始思考性能问题。毕竟,React本身是高效的,但如果滥用,一样会出现性能瓶颈。

1. 使用React.memo优化子组件

当任务列表很多的时候,我们可以对TodoItem组件使用React.memo,避免不必要的重复渲染。

import React from 'react';

const TodoItem = React.memo(({ item, onToggle }) => {
  return (
    <li>
      <span style={{ textDecoration: item.done ? 'line-through' : 'none' }}>
        {item.text}
      </span>
      <button onClick={onToggle}>
        {item.done ? '取消' : '完成'}
      </button>
    </li>
  );
});

export default TodoItem;

这样只有当传入的itemonToggle发生变化时,才会重新渲染这个组件。

2. 使用DevTools调试组件树

Chrome的React Developer Tools插件非常好用。它可以查看组件树结构,观察props和state的变化,甚至还可以进行快照分析。

有时候某个组件莫名其妙不更新了,用DevTools一看,原来是没有触发状态变更,或者key值写错了。

另外,在生产环境打包时,注意不要忘记使用npm run build生成优化过的静态资源。


实战中的挑战与收获

在整个开发过程中,我们也遇到了不少挑战:

  • 多人协作时组件命名规范不统一:有的叫TodoListItem,有的叫TaskCard。后来制定了命名规则:统一为PascalCase,并在README中说明。

  • 样式冲突严重:CSS类名没有隔离导致覆盖。后来引入了CSS Modules,每个组件都有独立的样式空间。

  • 移动端兼容性问题:某些设备上的点击事件反应慢。后来加了fastclick库或者直接用了Ant Design Mobile的部分组件。

这些都不是React本身的锅,但都是实际开发中必须面对的问题。


总结:从入门到实战的几点经验

经过这个小项目,我总结出几个对新手特别有用的建议:

  1. 别怕看官方文档:React的中文文档质量越来越高,特别是Hooks部分,讲解清晰易懂。
  2. 动手实践比看教程更重要:哪怕只是写一个简单的表单提交,动手做出来的记忆远胜于纸上谈兵。
  3. 学会使用开发者工具:React DevTools、Chrome Performance面板这些工具会让你事半功倍。
  4. 关注组件设计而非仅仅是功能实现:良好的组件划分能让你在后期维护中节省大量时间。
  5. 保持好奇心和技术敏感度:比如State Management方面,从Context API到Redux Toolkit,再到Zustand,每个阶段都有适合的解决方案。

React的确是一个很好的起点,它不会让你一开始就陷入太复杂的框架细节,而是让你聚焦在“如何构建用户界面”这件事上。这也是为什么越来越多公司愿意选择它的原因之一。

如果你也刚开始学习React,不妨就从搭建一个TodoList开始吧。相信我,当你看到自己写的代码在浏览器中跑起来的时候,那种成就感,比任何教程都来得真切。


🚀 如果你也在学习React,欢迎留言分享你的第一个组件!我会不定期回复问题,也希望能和更多同行交流心得。

评论 0

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