React 中文教程
1. 项目概述
React 是由 Facebook 开发的用于构建用户界面的 JavaScript 库,它采用组件化的开发方式,使得构建复杂的用户界面变得更加简单和可维护。
1.1 主要功能
- 组件化开发:将 UI 拆分为独立、可复用的组件
- 虚拟 DOM:通过虚拟 DOM 提高渲染性能
- 单向数据流:数据流向清晰,便于调试和维护
- JSX 语法:在 JavaScript 中编写类似 HTML 的代码,提高开发效率
- Hooks API:在函数组件中使用状态和其他 React 特性
- 服务端渲染:支持在服务器端渲染 React 组件,提高首屏加载速度和 SEO
1.2 技术栈特点
- 声明式编程:只需描述 UI 的最终状态,React 会处理如何更新 DOM
- 高效渲染:通过虚拟 DOM 和 diff 算法,只更新需要变化的部分
- 生态系统丰富:拥有大量的第三方库和工具
- 跨平台:除了 Web 浏览器,还可以用于开发移动应用(React Native)和桌面应用
- 强大的社区支持:作为前端开发的主流框架之一,拥有庞大的社区和丰富的学习资源
1.3 GitHub Stars
220k+
2. 安装设置
2.1 使用 Create React App
Create React App 是 React 官方推荐的项目脚手架工具,它会自动配置好开发环境,让你可以专注于编写代码。
# 安装 Create React App
npm install -g create-react-app
# 创建新的 React 项目
npx create-react-app my-app
# 进入项目目录
cd my-app
# 启动开发服务器
npm start2.2 使用 Vite
Vite 是一个现代化的前端构建工具,它提供了更快的开发体验。
# 使用 npm
npm create vite@latest my-app -- --template react
# 使用 yarn
yarn create vite my-app --template react
# 使用 pnpm
pnpm create vite my-app --template react
# 进入项目目录
cd my-app
# 安装依赖
npm install
# 启动开发服务器
npm run dev2.3 手动配置
如果你需要更灵活的配置,可以手动设置 React 项目。
# 创建项目目录
mkdir my-app
cd my-app
# 初始化 package.json
npm init -y
# 安装 React 和 React DOM
npm install react react-dom
# 安装构建工具
npm install --save-dev webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-react
# 创建 .babelrc 文件
{
"presets": ["@babel/preset-react"]
}
# 创建 webpack.config.js 文件
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: 'babel-loader'
}
]
},
devServer: {
contentBase: path.resolve(__dirname, 'public'),
port: 3000
}
};
# 创建 src/index.js 文件
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
# 创建 src/App.js 文件
import React from 'react';
function App() {
return (
<div className="App">
<h1>Hello React!</h1>
</div>
);
}
export default App;
# 创建 public/index.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React App</title>
</head>
<body>
<div id="root"></div>
<script src="../dist/bundle.js"></script>
</body>
</html>3. 基本使用
3.1 组件定义
React 组件可以通过函数或类来定义。
3.1.1 函数组件
import React from 'react';
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
export default Greeting;3.1.2 类组件
import React, { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
export default Greeting;3.2 状态管理
在 React 中,可以使用 useState Hook 或类组件的 this.state 来管理组件状态。
3.2.1 使用 useState Hook
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Counter;3.2.2 使用类组件的状态
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
incrementCount() {
this.setState(prevState => ({
count: prevState.count + 1
}));
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.incrementCount()}>
Click me
</button>
</div>
);
}
}
export default Counter;3.3 生命周期
在函数组件中,可以使用 useEffect Hook 来处理副作用和模拟生命周期方法。在类组件中,可以使用生命周期方法。
3.3.1 使用 useEffect Hook
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 相当于 componentDidMount 和 componentDidUpdate
useEffect(() => {
// 更新文档标题
document.title = `You clicked ${count} times`;
// 清理函数,相当于 componentWillUnmount
return () => {
// 执行清理操作
};
}, [count]); // 只有当 count 变化时才会重新运行
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Example;3.3.2 使用类组件的生命周期方法
import React, { Component } from 'react';
class Example extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
// 组件挂载后执行
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate(prevProps, prevState) {
// 组件更新后执行
if (prevState.count !== this.state.count) {
document.title = `You clicked ${this.state.count} times`;
}
}
componentWillUnmount() {
// 组件卸载前执行
// 执行清理操作
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
export default Example;3.4 事件处理
React 中的事件处理与 DOM 事件类似,但有一些语法差异。
import React, { useState } from 'react';
function Toggle() {
const [isToggleOn, setIsToggleOn] = useState(true);
function handleClick() {
setIsToggleOn(prevState => !prevState);
}
return (
<button onClick={handleClick}>
{isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
export default Toggle;3.5 条件渲染
React 支持条件渲染,可以根据条件显示不同的内容。
import React, { useState } from 'react';
function Greeting() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
return (
<div>
{isLoggedIn ? (
<button onClick={() => setIsLoggedIn(false)}>Logout</button>
) : (
<button onClick={() => setIsLoggedIn(true)}>Login</button>
)}
</div>
);
}
export default Greeting;3.6 列表渲染
可以使用 map 方法来渲染列表。
import React from 'react';
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
export default NumberList;4. 高级功能
4.1 上下文(Context)
Context 提供了一种在组件树中共享值的方式,而不必显式地通过 props 传递。
import React, { createContext, useContext, useState } from 'react';
// 创建 Context
const ThemeContext = createContext();
// 创建 Provider 组件
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
// 创建使用 Context 的 Hook
function useTheme() {
return useContext(ThemeContext);
}
// 使用 Context 的组件
function ThemedButton() {
const { theme, setTheme } = useTheme();
return (
<button
onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
style={{
background: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#333' : '#fff'
}}
>
Toggle {theme === 'light' ? 'Dark' : 'Light'} Mode
</button>
);
}
// 应用组件
function App() {
return (
<ThemeProvider>
<ThemedButton />
</ThemeProvider>
);
}
export default App;4.2 引用(Refs)
Refs 提供了一种方式来访问 DOM 节点或在 render 方法中创建的 React 元素。
import React, { useRef, useEffect } from 'react';
function FocusInput() {
const inputRef = useRef(null);
useEffect(() => {
// 组件挂载后聚焦输入框
inputRef.current.focus();
}, []);
return (
<div>
<input ref={inputRef} type="text" />
</div>
);
}
export default FocusInput;4.3 性能优化
4.3.1 使用 React.memo
React.memo 可以缓存组件的渲染结果,避免不必要的重新渲染。
import React, { useState, memo } from 'react';
// 使用 memo 包装组件
const ExpensiveComponent = memo(({ value }) => {
console.log('Rendering ExpensiveComponent');
// 模拟昂贵的计算
for (let i = 0; i < 1000000000; i++) {
// 空循环
}
return <div>Value: {value}</div>;
});
function App() {
const [count, setCount] = useState(0);
const [value, setValue] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>
Increment Count: {count}
</button>
<button onClick={() => setValue(value + 1)}>
Increment Value: {value}
</button>
<ExpensiveComponent value={value} />
</div>
);
}
export default App;4.3.2 使用 useCallback 和 useMemo
useCallback 可以缓存函数引用,useMemo 可以缓存计算结果。
import React, { useState, useCallback, useMemo } from 'react';
function App() {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
// 使用 useCallback 缓存函数
const addTodo = useCallback(() => {
setTodos(prevTodos => [...prevTodos, `Todo ${prevTodos.length + 1}`]);
}, []);
// 使用 useMemo 缓存计算结果
const sortedTodos = useMemo(() => {
return todos.sort();
}, [todos]);
return (
<div>
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
<button onClick={addTodo}>
Add Todo
</button>
<ul>
{sortedTodos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
</ul>
</div>
);
}
export default App;4.4 错误边界
错误边界可以捕获其子组件树中的 JavaScript 错误,并显示备用 UI,而不是整个组件树崩溃。
import React, { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
// 更新状态,下次渲染时显示备用 UI
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
// 可以在这里记录错误信息
console.error('Error caught by ErrorBoundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
// 显示备用 UI
return <h1>Something went wrong: {this.state.error.message}</h1>;
}
// 正常渲染子组件
return this.props.children;
}
}
export default ErrorBoundary;4.5 自定义 Hooks
可以创建自定义 Hooks 来复用状态逻辑。
import React, { useState, useEffect } from 'react';
// 创建自定义 Hook
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
const reset = () => setCount(initialValue);
return { count, increment, decrement, reset };
}
// 使用自定义 Hook
function Counter() {
const { count, increment, decrement, reset } = useCounter(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
</div>
);
}
export default Counter;5. 实际应用场景
5.1 表单处理
import React, { useState } from 'react';
function LoginForm() {
const [formData, setFormData] = useState({
username: '',
password: ''
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prevData => ({
...prevData,
[name]: value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form submitted:', formData);
// 处理表单提交逻辑
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="username">Username:</label>
<input
type="text"
id="username"
name="username"
value={formData.username}
onChange={handleChange}
/>
</div>
<div>
<label htmlFor="password">Password:</label>
<input
type="password"
id="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
</div>
<button type="submit">Login</button>
</form>
);
}
export default LoginForm;5.2 数据获取
import React, { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchUsers() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
if (!response.ok) {
throw new Error('Failed to fetch users');
}
const data = await response.json();
setUsers(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
fetchUsers();
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<ul>
{users.map(user => (
<li key={user.id}>
{user.name} ({user.email})
</li>
))}
</ul>
);
}
export default UserList;5.3 路由
使用 React Router 来处理应用的路由。
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
function Home() {
return <h1>Home</h1>;
}
function About() {
return <h1>About</h1>;
}
function Contact() {
return <h1>Contact</h1>;
}
function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/contact">Contact</Link>
</li>
</ul>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</div>
</Router>
);
}
export default App;6. 代码优化建议
6.1 使用函数组件和 Hooks
函数组件和 Hooks 是 React 的现代特性,它们提供了更简洁、更灵活的方式来编写 React 代码。
6.2 合理使用 memo、useCallback 和 useMemo
这些优化手段可以减少不必要的渲染,提高应用性能,但不要过度使用,以免增加代码复杂度。
6.3 拆分组件
将大型组件拆分为更小、更专注的组件,提高代码的可维护性和可测试性。
6.4 使用 PropTypes 或 TypeScript
使用 PropTypes 或 TypeScript 来类型检查组件的 props,减少运行时错误。
6.5 避免在 render 方法中创建新函数
在 render 方法中创建新函数会导致每次渲染时都创建新的函数实例,影响性能。可以使用 useCallback 或在组件外部定义函数。
6.6 合理使用状态
将状态放在最合适的组件中,避免状态提升过高或过低。
6.7 使用正确的 key
在渲染列表时,使用唯一且稳定的 key,避免使用索引作为 key(除非列表是静态的)。
6.8 优化条件渲染
对于频繁切换的条件渲染,可以使用 React.memo 来缓存组件。
6.9 使用懒加载
对于大型应用,可以使用 React.lazy 和 Suspense 来实现组件的懒加载,减少初始包大小。
6.10 合理使用 Context
Context 适合共享那些被多个组件需要的值,避免过度使用 Context,以免导致不必要的渲染。
7. 参考资源
8. 总结
React 是一个功能强大、灵活且高效的前端框架,它通过组件化开发、虚拟 DOM、单向数据流等特性,使得构建复杂的用户界面变得更加简单和可维护。
通过本教程的学习,你应该已经掌握了 React 的核心概念和基本使用方法,包括组件定义、状态管理、生命周期、事件处理、条件渲染、列表渲染等。同时,你也了解了 React 的一些高级特性,如 Context、Refs、性能优化、错误边界和自定义 Hooks 等。
React 的生态系统非常丰富,有许多优秀的第三方库和工具,如 React Router、Redux、Material-UI 等,它们可以帮助你更高效地开发 React 应用。
作为前端开发的主流框架之一,React 拥有庞大的社区和丰富的学习资源,如果你在学习或开发过程中遇到问题,可以通过官方文档、社区论坛、GitHub 等渠道寻求帮助。
希望本教程对你有所帮助,祝你在 React 开发之路上取得成功!