零基础也能轻松上手的React入门实战手册
开篇:为什么要写这篇教程
大家好,我是团队的技术培训负责人,这些年带过不少应届生和转行的新人。每次新人入职,我都会问一个问题:"你之前写过React吗?"很多人摇头,说在学校里学的是Vue或者纯HTML/CSS。
我当初学的时候,也是从零开始的,那时候网上的教程要么太深奥,要么太零散,踩了不少坑。所以今天我想用最直白的方式,带你从零开始,走完React从安装到第一个应用的全过程。
React是什么? 简单来说,它是Facebook(现在叫Meta)开发的一个用于构建用户界面的JavaScript库。它的核心思想是"组件化"——把页面拆成一个个独立的小模块,每个模块自己管理自己的状态和样式。这就像搭积木一样,你可以用不同的积木组合出各种各样的页面。
为什么选择React?
| 优势 | 说明 |
|---|---|
| 生态丰富 | 拥有庞大的社区和第三方库支持 |
| 组件化开发 | 代码复用性高,维护方便 |
| 虚拟DOM | 性能优秀,更新高效 |
| 就业面广 | 国内外大厂广泛使用 |
环境准备:工欲善其事,必先利其器
在开始写代码之前,我们需要准备好开发环境。别担心,我会一步步带你完成。
第一步:安装Node.js
React项目依赖Node.js环境。Node.js是一个让JavaScript可以在服务器端运行的平台,同时也是npm(Node包管理器)的载体。
安装步骤:
- 访问 Node.js 官网:https://nodejs.org
- 下载 LTS(长期支持)版本
- 安装完成后,打开终端(Windows用户用CMD或PowerShell,Mac用户用Terminal)
- 验证安装是否成功:
node -v
# 输出类似:v18.17.0
npm -v
# 输出类似:9.6.7
第二步:安装代码编辑器
推荐使用 Visual Studio Code(简称VS Code),它是目前最流行的前端编辑器,免费且功能强大。
必装插件清单:
| 插件名称 | 用途 |
|---|---|
| ES7+ React/Redux/React-Native snippets | React代码片段快捷输入 |
| Prettier - Code formatter | 代码自动格式化 |
| ESLint | 代码错误检查 |
| Auto Rename Tag | 自动重命名配对的HTML标签 |
| Live Server | 本地服务器预览 |
第三步:创建React项目
React官方提供了创建项目的工具,我们使用 create-react-app(简称CRA)来快速搭建项目骨架。
# 全局安装create-react-app(可选,npx方式不需要)
npm install -g create-react-app
# 使用npx创建项目(推荐方式)
npx create-react-app my-first-react-app
# 进入项目目录
cd my-first-react-app
# 启动开发服务器
npm start
执行 npm start 后,浏览器会自动打开 http://localhost:3000,你就能看到React的欢迎页面了。
项目目录结构说明:
my-first-react-app/
├── node_modules/ # 依赖包(不要手动修改)
├── public/ # 静态资源目录
│ ├── favicon.ico # 网站图标
│ ├── index.html # HTML模板
│ └── manifest.json # 应用元数据
├── src/ # 源代码目录(主要工作区)
│ ├── App.css # 根组件样式
│ ├── App.js # 根组件
│ ├── App.test.js # 测试文件
│ ├── index.css # 全局样式
│ ├── index.js # 入口文件
│ └── logo.svg # Logo图片
├── package.json # 项目配置和依赖信息
└── README.md # 项目说明
核心概念:用大白话理解React
概念一:JSX——JavaScript和HTML的混血儿
我当初学的时候,看到JSX觉得特别奇怪:这到底是JS还是HTML?
JSX 是JavaScript XML的缩写,它允许你在JavaScript中直接写类似HTML的语法。React用它来描述UI长什么样子。
// 这是一个JSX示例
function Welcome() {
const name = "小明";
return <h1>你好,{name}!</h1>;
}
JSX的关键规则:
- 必须有一个根元素(可以用
<>...</>包裹,这叫Fragment) - 使用
className代替class - 使用
htmlFor代替for - 所有标签必须闭合(包括
<img />、<br />) - 用
{}包裹JavaScript表达式
function Demo() {
const isLoggedIn = true;
const user = { name: "张三", age: 25 };
return (
<>
<h1 className="title">用户信息</h1>
{/* 条件渲染 */}
{isLoggedIn ? <p>欢迎回来,{user.name}</p> : <p>请先登录</p>}
{/* 表达式 */}
<p>年龄:{user.age + 1}</p>
</>
);
}
概念二:组件——页面的积木块
组件是React的核心。你可以把组件理解为一个自定义的HTML标签,它有自己的结构和逻辑。
函数组件(推荐):
// 定义一个组件
function Button({ text, onClick }) {
return (
<button className="btn" onClick={onClick}>
{text}
</button>
);
}
// 使用组件
function App() {
return (
<div>
<Button text="点击我" onClick={() => alert("你好!")} />
</div>
);
}
组件的命名规则:
- 必须以大写字母开头(小写字母会被当作普通HTML标签)
- 文件名建议与组件名一致
概念三:Props——组件之间的传话筒
Props(属性)是父组件向子组件传递数据的方式。它是只读的,子组件不能修改props。
// 子组件:接收props
function UserCard({ name, age, role }) {
return (
<div className="card">
<h2>{name}</h2>
<p>年龄:{age}</p>
<p>角色:{role}</p>
</div>
);
}
// 父组件:传递props
function App() {
return (
<div>
<UserCard name="李四" age={28} role="前端工程师" />
<UserCard name="王五" age={32} role="产品经理" />
</div>
);
}
概念四:State——组件的记忆
State(状态)是组件内部的数据,它可以变化。当state改变时,React会自动重新渲染组件。
使用useState Hook:
import { useState } from 'react';
function Counter() {
// 声明状态变量count,初始值为0
const [count, setCount] = useState(0);
return (
<div>
<p>当前计数:{count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
<button onClick={() => setCount(count - 1)}>-1</button>
<button onClick={() => setCount(0)}>重置</button>
</div>
);
}
useState的使用要点:
| 要点 | 说明 |
|---|---|
| 只能在顶层调用 | 不能在循环、条件语句或嵌套函数中调用 |
| 只在函数组件中使用 | 类组件使用this.state |
| 更新是异步的 | 不要依赖上一个状态值直接计算 |
概念五:事件处理——和用户互动
React的事件处理和原生HTML类似,但有一些区别:
function EventDemo() {
// 点击事件
const handleClick = () => {
console.log("按钮被点击了");
};
// 输入事件
const handleChange = (e) => {
console.log("输入内容:", e.target.value);
};
// 表单提交
const handleSubmit = (e) => {
e.preventDefault(); // 阻止默认行为
console.log("表单提交了");
};
return (
<form onSubmit={handleSubmit}>
<button onClick={handleClick}>点击我</button>
<input type="text" onChange={handleChange} />
<button type="submit">提交</button>
</form>
);
}
实战项目:从零打造一个待办事项应用
光说不练假把式。接下来,我们一步步实现一个功能完整的待办事项(Todo List)应用。这个项目涵盖了组件、Props、State、事件处理等核心知识点。
第一步:规划组件结构
在动手之前,先想清楚页面由哪些部分组成:
App(根组件)
├── Header(标题区域)
├── TodoInput(输入框 + 添加按钮)
├── TodoList(待办列表)
│ └── TodoItem(单个待办项)× N
└── Footer(统计信息)
第二步:创建Header组件
// src/components/Header.jsx
function Header() {
return (
<header style={{ textAlign: 'center', padding: '20px' }}>
<h1>📝 我的待办事项</h1>
<p>管理你的日常任务</p>
</header>
);
}
export default Header;
第三步:创建TodoInput组件
// src/components/TodoInput.jsx
import { useState } from 'react';
function TodoInput({ onAdd }) {
const [text, setText] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (text.trim() === '') return;
onAdd(text);
setText(''); // 清空输入框
};
return (
<form onSubmit={handleSubmit} style={{ display: 'flex', gap: '10px', padding: '0 20px' }}>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="输入新的待办事项..."
style={{ flex: 1, padding: '10px', fontSize: '16px' }}
/>
<button type="submit" style={{ padding: '10px 20px' }}>
添加
</button>
</form>
);
}
export default TodoInput;
第四步:创建TodoItem组件
// src/components/TodoItem.jsx
function TodoItem({ todo, onToggle, onDelete }) {
return (
<li style={{
display: 'flex',
alignItems: 'center',
padding: '10px',
borderBottom: '1px solid #eee',
textDecoration: todo.completed ? 'line-through' : 'none',
opacity: todo.completed ? 0.6 : 1
}}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => onToggle(todo.id)}
style={{ marginRight: '10px' }}
/>
<span style={{ flex: 1 }}>{todo.text}</span>
<button
onClick={() => onDelete(todo.id)}
style={{ color: 'red', border: 'none', cursor: 'pointer' }}
>
删除
</button>
</li>
);
}
export default TodoItem;
第五步:创建TodoList组件
// src/components/TodoList.jsx
import TodoItem from './TodoItem';
function TodoList({ todos, onToggle, onDelete }) {
if (todos.length === 0) {
return <p style={{ textAlign: 'center', color: '#999' }}>暂无待办事项</p>;
}
return (
<ul style={{ listStyle: 'none', padding: '0', margin: '20px' }}>
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={onToggle}
onDelete={onDelete}
/>
))}
</ul>
);
}
export default TodoList;
第六步:创建Footer组件
// src/components/Footer.jsx
function Footer({ total, completed }) {
return (
<footer style={{ textAlign: 'center', padding: '10px', color: '#666' }}>
<p>共 {total} 项,已完成 {completed} 项</p>
</footer>
);
}
export default Footer;
第七步:组装App组件
// src/App.jsx
import { useState } from 'react';
import Header from './components/Header';
import TodoInput from './components/TodoInput';
import TodoList from './components/TodoList';
import Footer from './components/Footer';
function App() {
const [todos, setTodos] = useState([]);
// 添加待办
const handleAdd = (text) => {
const newTodo = {
id: Date.now(),
text: text,
completed: false
};
setTodos([...todos, newTodo]);
};
// 切换完成状态
const handleToggle = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
// 删除待办
const handleDelete = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
// 统计数据
const completedCount = todos.filter(todo => todo.completed).length;
return (
<div style={{ maxWidth: '500px', margin: '0 auto', fontFamily: 'sans-serif' }}>
<Header />
<TodoInput onAdd={handleAdd} />
<TodoList
todos={todos}
onToggle={handleToggle}
onDelete={handleDelete}
/>
<Footer total={todos.length} completed={completedCount} />
</div>
);
}
export default App;
运行效果
启动项目后(npm start),你会看到一个完整的待办事项应用,可以:
- 输入新的待办事项并添加
- 勾选完成/取消完成
- 删除待办事项
- 查看统计数据
常见问题:新手踩坑指南
根据我带新人的经验,以下是大家最容易遇到的问题:
问题一:页面空白,控制台报错
原因: 通常是JSX语法错误,比如忘记闭合标签、使用了HTML属性名等。
解决方案:
- 检查所有标签是否正确闭合
- 确认使用的是
className而非class - 查看浏览器控制台的错误信息
问题二:状态更新后页面没有变化
原因: 直接修改了state,而不是使用setState。
// ❌ 错误写法
todos.push(newTodo);
setTodos(todos); // 不会触发重新渲染
// ✅ 正确写法
setTodos([...todos, newTodo]); // 创建新数组
问题三:列表渲染时出现警告
警告信息: Warning: Each child in a list should have a unique "key" prop.
原因: 渲染列表时没有给每个元素设置唯一的key。
解决方案:
// ❌ 错误写法
{todos.map(todo => <TodoItem todo={todo} />)}
// ✅ 正确写法
{todos.map(todo => <TodoItem key={todo.id} todo={todo} />)}
问题四:子组件修改props报错
错误信息: Cannot assign to read only property 'xxx'
原因: Props是只读的,不能在子组件中直接修改。
解决方案: 通过回调函数通知父组件修改。
// ✅ 正确做法
function Child({ value, onChange }) {
return <input value={value} onChange={(e) => onChange(e.target.value)} />;
}
学习建议:下一步怎么走
恭喜你完成了React的入门!但这只是开始。以下是我建议的学习路径:
第一阶段:巩固基础(1-2周)
- 多写几个小项目(计算器、天气查询、备忘录)
- 熟悉React的常用Hooks:
useState、useEffect、useRef - 理解组件的生命周期和渲染机制
第二阶段:进阶学习(2-4周)
- 学习React Router(路由管理)
- 学习状态管理(Context API、Redux或Zustand)
- 学习数据请求(Fetch API、Axios)
第三阶段:工程化实践(持续)
- 学习TypeScript + React
- 学习测试(Jest、React Testing Library)
- 学习性能优化(React.memo、useMemo、useCallback)
推荐学习资源
| 资源 | 类型 | 说明 |
|---|---|---|
| React官方文档 | 文档 | 最权威的学习资料 |
| React中文文档 | 文档 | 官方中文翻译 |
| 掘金/知乎 | 社区 | 大量优质技术文章 |
| B站/YouTube | 视频 | 适合视觉学习者 |
结语
React的学习曲线其实并不陡峭,关键在于多动手实践。我当初学的时候,也是从一个小Demo开始,慢慢扩展到完整项目。
记住几个原则:
- 先跑通,再优化——不要一开始就追求完美
- 多看官方文档——社区文章质量参差不齐
- 遇到问题先搜索——90%的问题别人都遇到过
- 坚持写代码——看十遍不如写一遍
希望这篇教程能帮你顺利入门React。如果有任何疑问,欢迎在评论区交流。加油,未来的前端工程师!


评论 0