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
这种方式在一些特殊网络环境下确实节省了不少时间。
写第一个组件:从零开始搭一个小应用


我们决定做的第一个应用是一个简单的待办事项列表(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.js和index.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

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('');

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;
这样只有当传入的item或onToggle发生变化时,才会重新渲染这个组件。
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本身的锅,但都是实际开发中必须面对的问题。
总结:从入门到实战的几点经验
经过这个小项目,我总结出几个对新手特别有用的建议:
- 别怕看官方文档:React的中文文档质量越来越高,特别是Hooks部分,讲解清晰易懂。
- 动手实践比看教程更重要:哪怕只是写一个简单的表单提交,动手做出来的记忆远胜于纸上谈兵。
- 学会使用开发者工具:React DevTools、Chrome Performance面板这些工具会让你事半功倍。
- 关注组件设计而非仅仅是功能实现:良好的组件划分能让你在后期维护中节省大量时间。
- 保持好奇心和技术敏感度:比如State Management方面,从Context API到Redux Toolkit,再到Zustand,每个阶段都有适合的解决方案。
React的确是一个很好的起点,它不会让你一开始就陷入太复杂的框架细节,而是让你聚焦在“如何构建用户界面”这件事上。这也是为什么越来越多公司愿意选择它的原因之一。
如果你也刚开始学习React,不妨就从搭建一个TodoList开始吧。相信我,当你看到自己写的代码在浏览器中跑起来的时候,那种成就感,比任何教程都来得真切。
🚀 如果你也在学习React,欢迎留言分享你的第一个组件!我会不定期回复问题,也希望能和更多同行交流心得。

评论 0