学习 React:中文快速入门指南
欢迎来到 React 的世界!
如果你是前端开发新手,或是希望从其他框架转向 React,那么你来对地方了。React 是一个用于构建用户界面的 JavaScript 库,由 Facebook(现 Meta)及其社区维护。凭借其组件化、声明式和高效的特性,React 已经成为构建现代 Web 应用和移动应用(通过 React Native)的主流选择之一。
本指南将带领你快速掌握 React 的核心概念和基础用法,帮助你迈出学习 React 的第一步。我们将从环境搭建开始,逐步深入组件、JSX、Props、State、事件处理、条件渲染、列表渲染以及 Hooks 这些基石。
准备好了吗?让我们开始吧!
1. React 是什么?为什么选择 React?
React 是什么?
React 不是一个完整的框架,而是一个专注于构建用户界面的 JavaScript 库。它的核心理念是将复杂的 UI 拆分成独立、可复用的组件,通过管理组件的状态来驱动 UI 的更新。
为什么选择 React?
- 组件化: React 的核心是组件。你可以将 UI 划分为独立的、可维护的小块,每个组件只关注自身的数据和渲染逻辑。这大大提高了代码的可读性、可维护性和复用性。
- 声明式: 你只需要描述你的 UI 在特定状态下应该是什么样子,React 会负责高效地更新和渲染正确的组件。这使得代码更易于理解和调试,因为你不需要关心具体的 DOM 操作步骤。
- 高效: React 使用虚拟 DOM (Virtual DOM) 技术。在状态改变时,React 会先在内存中构建一个新的虚拟 DOM 树,然后将其与旧的虚拟 DOM 树进行比较(Diffing),找出差异,最后只更新实际需要修改的真实 DOM 部分。这种方式最大限度地减少了直接操作真实 DOM 的开销,提高了应用性能。
- 生态系统丰富: React 拥有庞大而活跃的社区,围绕 React 衍生出了丰富的库和工具,例如用于路由的 React Router、用于状态管理的 Redux、Zustand 等,以及各种 UI 组件库。
- 跨平台: 通过 React Native,你可以使用相同的 React 理念和大部分 JavaScript 知识来构建原生 iOS 和 Android 应用程序。
2. 准备工作:你需要知道什么?
在开始学习 React 之前,你需要具备一些基础知识:
- HTML & CSS: 了解如何构建网页结构和样式。
- JavaScript (ES6+): 这是 React 的基础语言。你需要熟悉变量、函数、对象、数组等基本概念,以及 ES6+ 的一些常用特性,如箭头函数 (
=>
)、let
和const
、模块导入导出 (import
/export
)、解构赋值、Promise 等。
此外,你还需要安装:
- Node.js: React 开发环境依赖 Node.js 及其包管理器 npm 或 yarn 或 pnpm。请访问 Node.js 官网(https://nodejs.org/)下载并安装 LTS (长期支持) 版本。安装 Node.js 后,npm (或 yarn/pnpm) 也将一并安装。
3. 搭建开发环境:创建你的第一个 React 应用
创建 React 应用有多种方式,对于初学者和快速开始,推荐使用现代化的构建工具,如 Vite。Vite 是一个非常快速的前端构建工具,它利用浏览器原生的 ES 模块功能,提供了极速的开发服务器启动和热模块更新。
- 打开终端或命令行工具。
-
使用 npm, yarn 或 pnpm 创建一个新的 Vite 项目:
“`bash
使用 npm
npm create vite@latest my-react-app –template react
或者 使用 yarn
yarn create vite my-react-app –template react
或者 使用 pnpm (如果你安装了 pnpm)
pnpm create vite my-react-app –template react
“`这里的
my-react-app
是你的项目名称,--template react
指定使用 React 模板。Vite 还会提供一些变种模板,例如react-swc
通常更快,你可以选择它。按照命令行提示完成项目的创建。 -
进入项目目录:
bash
cd my-react-app -
安装项目依赖:
“`bash
npm install或者 yarn
或者 pnpm install
“`
-
启动开发服务器:
“`bash
npm run dev或者 yarn dev
或者 pnpm dev
“`
命令执行后,你会在终端看到类似
Local: http://localhost:5173/
的输出。复制这个地址并在浏览器中打开,你就看到你的第一个 React 应用正在运行了!
4. 项目结构概览
使用 Vite 创建的 React 项目结构通常比较简洁:
my-react-app/
├── node_modules/ # 项目依赖库
├── public/ # 静态文件,如 index.html, favicon.ico
│ └── index.html # 应用的入口 HTML 文件
├── src/ # 源代码目录
│ ├── assets/ # 静态资源,如图片
│ ├── App.css # App 组件的样式文件
│ ├── App.jsx # 主应用组件
│ ├── index.css # 全局样式文件
│ ├── main.jsx # 应用的入口文件,将 App 组件渲染到 DOM
│ └── react.svg # Vite 默认的 SVG 文件
├── .gitignore # Git 忽略文件配置
├── package.json # 项目配置文件,包含依赖和脚本
├── vite.config.js # Vite 配置文件
└── README.md # 项目说明文件
public/index.html
是应用的骨架,你的 React 应用最终会渲染到这个 HTML 文件中的一个特定元素(通常是<div id="root">
或<div id="app">
)。src/main.jsx
(或src/index.jsx
) 是应用的入口文件。它负责导入你的根组件 (App.jsx
) 并使用ReactDOM.createRoot
方法将其渲染到index.html
中的 DOM 元素上。src/App.jsx
是你的主应用组件,你将在这里构建应用的大部分 UI。
5. React 核心概念
5.1 组件 (Components)
组件是 React 应用的基石。它们是独立、可复用的代码块,负责渲染 UI 的一部分。在现代 React 中,我们主要使用函数组件。
函数组件 (Functional Components):
函数组件是一个 JavaScript 函数,它接收一个 props
对象作为参数,并返回 React 元素(通常由 JSX 创建),描述了 UI 的样子。
“`jsx
// src/components/Greeting.jsx
import React from ‘react’;
function Greeting(props) {
// 函数组件接收 props 作为参数
return (
你好,{props.name}!
// 返回 JSX
);
}
// 导出组件,以便在其他地方使用
export default Greeting;
“`
使用组件:
在另一个组件(比如 App.jsx
)中导入并使用它:
“`jsx
// src/App.jsx
import React from ‘react’;
import Greeting from ‘./components/Greeting’; // 导入 Greeting 组件
import ‘./App.css’; // 导入样式
function App() {
return (
欢迎学习 React!
);
}
export default App;
“`
5.2 JSX (JavaScript XML)
JSX 是一种 JavaScript 的语法扩展,它允许你在 JavaScript 代码中书写类似 HTML 的结构。React 强烈推荐使用 JSX 来描述 UI 的外观。
JSX 的特点:
- 看起来像 HTML:
<div className="app">...</div>
- 是 JavaScript 的语法糖: JSX 会被 Babel 等工具编译成纯 JavaScript 代码 (调用
React.createElement
)。 - 可以在其中嵌入 JavaScript 表达式: 使用花括号
{}
将 JavaScript 表达式嵌入到 JSX 中。
“`jsx
const name = ‘世界’;
const element =
Hello, {name}!
; // 在 JSX 中使用 {} 嵌入变量
function formatUser(user) {
return user.firstName + ‘ ‘ + user.lastName;
}
const user = { firstName: ‘张’, lastName: ‘三’ };
const greetElement = (
你好,{formatUser(user)}! {/* 在 JSX 中调用函数 */}
);
“`
JSX 注意事项:
-
必须有一个根元素: JSX 代码块必须被一个父元素包裹,或者使用 React Fragment (
<>
或<React.Fragment>
)。
“`jsx
// 错误:没有单一根元素
// return (
//标题
//
段落
// );
// 正确:使用 div 作为根元素
return (标题
段落
);
// 正确:使用 Fragment
return (
<>标题
段落
);
``
className
* **属性使用 camelCase:** HTML 属性在 JSX 中使用驼峰命名法,例如代替
class,
htmlFor代替
for,
onClick代替
onclick。
* **自闭合标签必须闭合:** 例如而不是
`。
5.3 Props (属性)
Props 是父组件向子组件传递数据的方式。它们是只读的,子组件不应该直接修改接收到的 props。Props 使得组件更具通用性和可复用性。
我们在上面的 Greeting
例子中已经看到了 props 的使用:
“`jsx
// 父组件 App.jsx 传递 props
// 子组件 Greeting.jsx 接收并使用 props
function Greeting(props) { // props 是一个对象 { name: “React 初学者” }
return (
你好,{props.name}!
);
}
“`
通常,我们会使用 ES6 的对象解构来更方便地访问 props:
jsx
function Greeting({ name }) { // 直接解构出 name 属性
return (
<h1>你好,{name}!</h1>
);
}
5.4 State (状态)
State 是组件内部管理的可变数据。当 State 发生变化时,组件会重新渲染。State 使得组件能够记住用户的输入、是否选中、当前计数等信息。
在函数组件中,我们使用 useState
这个 Hook 来管理 State。
“`jsx
import React, { useState } from ‘react’; // 需要从 react 中导入 useState
function Counter() {
// 声明一个名为 count 的 state 变量,初始值为 0
// setCount 是更新 count 的函数
const [count, setCount] = useState(0);
// 定义一个函数来处理点击事件,更新 state
const handleClick = () => {
// 使用 setCount 更新 state
setCount(count + 1);
// 或者使用函数形式,更安全,特别是当新状态依赖于前一个状态时
// setCount(prevCount => prevCount + 1);
};
return (
你点击了 {count} 次按钮。
);
}
export default Counter;
“`
使用 useState
的注意事项:
useState
返回一个数组,第一个元素是当前的 state 值,第二个元素是更新 state 的函数。通常使用数组解构来获取它们。- 永远不要直接修改 state 变量(例如
count = count + 1
),而是使用 state 更新函数 (setCount
)。直接修改不会触发组件重新渲染。 setCount
是异步的。如果你需要在更新 state 后立即执行某个依赖新 state 的操作,可以使用useEffect
或setCount
的函数形式。
5.5 事件处理 (Event Handling)
在 React 中处理事件与在普通 HTML 中类似,但有一些区别:
- 事件名使用 camelCase: 例如
onClick
而不是onclick
。 - 事件处理函数作为值传递: 你传递一个 JavaScript 函数作为事件属性的值,而不是一个字符串。
“`jsx
function MyButton() {
function handleClick() {
alert(‘你点击了按钮!’);
}
return (
);
}
// 如果需要传递参数或访问 event 对象
function AnotherButton() {
function handleClick(event, message) {
// event 是浏览器原生事件对象
console.log(‘Event:’, event);
console.log(‘Message:’, message);
alert(message);
}
return (
// 使用箭头函数来包裹事件处理函数,以便传递额外参数或在渲染时调用
);
}
“`
5.6 条件渲染 (Conditional Rendering)
在 React 中,你可以根据条件决定渲染哪些元素。常用的方法有:
-
if
语句 (在 JSX 外):jsx
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>欢迎回来!</h1>;
}
return <h1>请先登录。</h1>;
}
* 三元运算符 (在 JSX 内):jsx
function Greeting({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? (
<h1>欢迎回来!</h1>
) : (
<h1>请先登录。</h1>
)}
</div>
);
}
* 逻辑与&&
(用于条件渲染一个元素或不渲染):“`jsx
function WarningBanner({ warn }) {
// 如果 warn 为 false,组件将不渲染任何东西
if (!warn) {
return null; // 返回 null 或 false 表示不渲染任何内容
}return (
警告!);
}// 在另一个组件中使用
function Page() {
const [showWarning, setShowWarning] = useState(true);
const handleToggleClick = () => {
setShowWarning(prev => !prev);
};return (
);
}// 或者在 JSX 中使用 &&
function MyComponent({ isLoggedIn }) {
return ({isLoggedIn &&你已登录。
} {/ 如果 isLoggedIn 为 true,则渲染
/}
{!isLoggedIn &&请登录。
}
);
}
“`
5.7 列表渲染 (List Rendering)
渲染列表元素通常使用 JavaScript 的 map()
方法来处理数组,并将每个元素转换成 React 元素。
“`jsx
function NumberList({ numbers }) {
// 使用 map 遍历数组,为每个数字创建一个
const listItems = numbers.map((number) =>
// 重要:列表中每个元素都需要一个唯一的 key prop
);
return (
- {listItems}
);
}
// 在另一个组件中使用
function App() {
const numbers = [1, 2, 3, 4, 5];
return (
数字列表:
);
}
“`
关于 key
Prop 的重要性:
key
prop 帮助 React 识别列表中哪些项目被改变、添加或删除。它应该是一个在列表内唯一且稳定的字符串或数字。通常使用数据的 ID 作为 key
。如果列表项没有稳定的 ID,可以使用索引作为 key
,但只在列表项不变化、不重排或不增删时才推荐,否则可能导致性能问题或状态错乱。
“`jsx
// 使用对象的 id 作为 key (推荐)
const todos = [
{ id: 1, text: ‘学习 React’ },
{ id: 2, text: ‘构建应用’ },
{ id: 3, text: ‘分享经验’ }
];
function TodoList({ todos }) {
return (
-
{todos.map(todo =>
- {/ 使用 todo.id 作为 key /}
{todo.text}
)}
);
}
“`
5.8 Hooks (useState, useEffect 简介)
Hooks 是 React 16.8 引入的一项重要特性,它们让你在不编写 Class 组件的情况下使用 State 和其他 React 特性(如生命周期)。useState
我们已经见过了。另一个常用的 Hook 是 useEffect
。
useEffect
:
useEffect
允许你在函数组件中执行副作用 (side effects)。副作用包括数据获取、订阅、手动更改 DOM、设置定时器等。
useEffect
接收两个参数:一个包含副作用逻辑的函数,以及一个依赖项数组 (可选)。
“`jsx
import React, { useState, useEffect } from ‘react’;
function DataFetcher({ userId }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// useEffect 会在组件渲染后运行
useEffect(() => {
// 这是一个副作用:数据获取
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(https://jsonplaceholder.typicode.com/users/${userId}
);
if (!response.ok) {
throw new Error(‘数据获取失败’);
}
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
// 清理函数 (可选): 在组件卸载或依赖项变化时运行
return () => {
// 例如:取消订阅,清除定时器等
console.log(`清理旧的 userId: ${userId}`);
};
}, [userId]); // 依赖项数组:只有当 userId 变化时,useEffect 才会重新运行
if (loading) return
加载中…
;
if (error) return
加载失败: {error.message}
;
return (
用户信息:
姓名: {data.name}
邮箱: {data.email}
);
}
“`
useEffect
的依赖项数组:
- 空数组
[]
: 副作用只在组件挂载 (mount) 时运行一次,并在组件卸载 (unmount) 时执行清理(如果返回了清理函数)。这常用于一次性的设置或数据获取。 - 有依赖项的数组
[prop1, state1]
: 副作用在组件挂载时运行,并在数组中的任何依赖项发生变化时重新运行。 - 没有依赖项数组 (省略第二个参数): 副作用在每次组件渲染后都会运行。这应该谨慎使用,因为它可能导致性能问题或无限循环。
6. 动手实践:一个简单的计数器
现在,让我们综合运用学到的知识,在 App.jsx
中创建一个更完整的计数器组件。
修改 src/App.jsx
文件:
“`jsx
import React, { useState } from ‘react’;
import ‘./App.css’; // 导入 App 的样式
function App() {
// 使用 useState Hook 来管理计数器的状态
const [count, setCount] = useState(0);
// 处理点击增加按钮的函数
const handleIncrement = () => {
setCount(prevCount => prevCount + 1); // 使用函数形式确保基于最新状态更新
};
// 处理点击减少按钮的函数
const handleDecrement = () => {
// 也可以直接使用 count,但函数形式更安全
setCount(count – 1);
};
// 处理点击重置按钮的函数
const handleReset = () => {
setCount(0);
};
// 渲染计数器 UI
return (
简单的计数器
当前计数: {count}
{/ 显示当前计数 /}
{/* 按钮区域 */}
<div className="button-container">
{/* 减少按钮,当 count <= 0 时禁用 */}
<button onClick={handleDecrement} disabled={count <= 0}>
减少
</button>
{/* 增加按钮 */}
<button onClick={handleIncrement}>
增加
</button>
{/* 重置按钮,当 count === 0 时禁用 */}
<button onClick={handleReset} disabled={count === 0}>
重置
</button>
</div>
{/* 条件渲染:当计数大于 10 时显示一条消息 */}
{count > 10 && (
<p className="warning-message">计数有点高了!</p>
)}
</header>
</div>
);
}
export default App;
“`
在 src/App.css
中添加一些简单的样式(可以替换默认的样式):
“`css
.App {
text-align: center;
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.count-display {
font-size: 3em;
margin: 20px 0;
}
.button-container {
margin-top: 20px;
}
.button-container button {
font-size: 1em;
padding: 10px 20px;
margin: 0 10px;
border: none;
border-radius: 5px;
cursor: pointer;
background-color: #61dafb;
color: #282c34;
transition: background-color 0.3s ease;
}
.button-container button:hover:not(:disabled) {
background-color: #21a1f9;
}
.button-container button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.warning-message {
color: yellow;
margin-top: 20px;
font-size: 0.9em;
}
“`
保存文件后,你的开发服务器会自动刷新页面。你现在应该能看到一个简单的计数器界面,可以通过按钮增加、减少或重置计数。
7. 下一步:继续深入学习
恭喜你!你已经掌握了 React 的核心基础。这仅仅是一个开始。要成为一名熟练的 React 开发者,你还需要学习更多内容:
- 更多的 Hooks:
useContext
,useReducer
,useCallback
,useMemo
,useRef
等。 - 组件之间的通信: 除了 Props (父传子),还有 Context API、事件总线或状态管理库 (如 Redux, Zustand, Pinia) 处理更复杂的组件通信。
- 路由: 如何使用 React Router 等库实现页面导航。
- 状态管理: 学习如何使用 Redux, Zustand, Recoil, Context API 等处理应用全局状态。
- 数据获取: 使用
fetch
,axios
或更现代的库如 React Query, SWR 来管理数据加载、缓存和更新。 - 样式化: CSS Modules, Styled Components, Tailwind CSS 等多种样式方案。
- 表单处理: 如何在 React 中处理表单输入和提交。
- 性能优化: Memoization (
React.memo
),useCallback
,useMemo
等。 - 错误边界 (Error Boundaries): 处理组件渲染过程中的错误。
- 测试: 组件测试 (如 Testing Library, Jest)。
- TypeScript: 为你的 React 应用添加类型检查。
- 服务端渲染 (SSR) 或静态网站生成 (SSG): 了解 Next.js, Gatsby 等框架。
8. 学习资源
- React 官方文档: 这是最权威、最全面的学习资源。强烈推荐阅读新的 Beta 版文档(https://react.dev/),它使用了 Hook 作为主要教学方式,对初学者更友好,并且提供了中文翻译选项。
- MDN Web Docs: 巩固你的 JavaScript 基础。
- 社区和论坛: Stack Overflow、React 相关的 Discord 群组或社区论坛。
- 在线课程平台: Udemy, Coursera, Codecademy 等平台提供了许多优质的 React 课程。
- 技术博客和文章: 关注一些优秀的 React 开发者或技术社区,阅读他们的分享。
9. 总结
通过本指南,你了解了 React 的基本概念:
- 组件化: UI 的构建块。
- JSX: 在 JavaScript 中编写类似 HTML 的结构。
- Props: 从父组件向子组件传递数据(单向数据流)。
- State: 组件内部管理的可变数据。
- 事件处理: 如何响应用户交互。
- 条件渲染和列表渲染: 根据数据动态显示 UI。
- Hooks: 在函数组件中使用 State 和副作用。
React 的学习曲线是存在的,特别是 Hooks 的概念可能需要一些时间来消化。最重要的是多加练习,动手构建一些小项目。尝试实现一个简单的待办事项列表、一个计算器、一个天气应用等,将学到的概念应用到实际中。
希望这篇快速入门指南能帮助你顺利踏入 React 开发的大门。祝你学习愉快,编码顺利!