React 基础
为初学者和中级开发者提供的 React 基础知识全面指南。
React 简介
React 是一个用于构建用户界面的 JavaScript 库,特别适用于单页应用程序。它用于处理 Web 和移动应用中的视图层。React 允许您为应用程序中的每个状态设计简单的视图,当数据发生变化时,它会高效地更新和渲染正确的组件。
React 的主要特点
- 基于组件的架构:构建封装的组件,每个组件管理自己的状态
- 声明式 UI:为应用程序中的每个状态设计简单的视图
- 虚拟 DOM:当数据变化时高效地更新和渲染组件
- JSX:JavaScript 语法扩展,允许在 JavaScript 中使用类似 HTML 的代码
- 单向数据流:数据从父组件流向子组件
React 入门
前提条件
在开始学习 React 之前,您应该具备:
- HTML、CSS 和 JavaScript 的基础知识
- 理解 ES6 特性(箭头函数、类、解构等)
- 系统上已安装 Node.js 和 npm
设置 React 项目
使用 Create React App(推荐给初学者)
# 全局安装 Create React App
npm install -g create-react-app
# 创建新的 React 项目
npx create-react-app my-react-app
# 导航到项目目录
cd my-react-app
# 启动开发服务器
npm start
使用 Vite(更快的替代方案)
# 使用 Vite 创建新的 React 项目
npm create vite@latest my-react-app -- --template react
# 导航到项目目录
cd my-react-app
# 安装依赖
npm install
# 启动开发服务器
npm run dev
核心概念
1. 组件
组件是 React 应用程序的构建块。它们是可重用的代码片段,返回描述屏幕上应该显示内容的 React 元素。
函数组件
function Welcome(props) {
return <h1>你好,{props.name}</h1>;
}
// 使用箭头函数语法
const Welcome = (props) => {
return <h1>你好,{props.name}</h1>;
};
类组件
import React, { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>你好,{this.props.name}</h1>;
}
}
2. JSX
JSX 是 JavaScript 的语法扩展,看起来类似于 HTML。它使 React 代码更具可读性和表现力。
const element = <h1>你好,世界!</h1>;
// 带表达式的 JSX
const name = '张三';
const element = <h1>你好,{name}!</h1>;
// 带属性的 JSX
const element = <img src={user.avatarUrl} alt={user.name} />;
// 带子元素的 JSX
const element = (
<div>
<h1>你好!</h1>
<p>很高兴在这里见到你。</p>
</div>
);
3. Props
Props(属性的缩写)是组件的只读输入。它们允许您将数据从父组件传递到子组件。
// 父组件
function App() {
return <Welcome name="小明" />;
}
// 子组件
function Welcome(props) {
return <h1>你好,{props.name}</h1>;
}
4. State
State 是存储可能随时间变化的组件数据的 JavaScript 对象。当状态变化时,组件会重新渲染。
import React, { useState } from 'react';
function Counter() {
// 声明一个名为"count"的状态变量,初始值为0
const [count, setCount] = useState(0);
return (
<div>
<p>你点击了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>
点击我
</button>
</div>
);
}
5. 生命周期和副作用
在函数组件中,useEffect
钩子让您执行副作用(如数据获取、订阅或 DOM 操作)。
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 类似于 componentDidMount 和 componentDidUpdate
useEffect(() => {
// 使用浏览器 API 更新文档标题
document.title = `你点击了 ${count} 次`;
// 可选的清理函数(类似于 componentWillUnmount)
return () => {
document.title = 'React App';
};
}, [count]); // 仅当 count 变化时重新运行副作用
return (
<div>
<p>你点击了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>
点击我
</button>
</div>
);
}
处理事件
React 事件使用驼峰命名法,并作为函数而非字符串传递。
function ActionButton() {
function handleClick(e) {
e.preventDefault();
console.log('按钮被点击了');
}
return (
<button onClick={handleClick}>
点击我
</button>
);
}
条件渲染
您可以使用 JavaScript 运算符如 if
或条件(三元)运算符来创建表示当前状态的元素。
function UserGreeting(props) {
return <h1>欢迎回来!</h1>;
}
function GuestGreeting(props) {
return <h1>请注册。</h1>;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
// 使用三元运算符
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
return (
<>
{isLoggedIn ? <UserGreeting /> : <GuestGreeting />}
</>
);
}
列表和键
React 使用键来识别列表中哪些项目已更改、添加或删除。
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
表单
在 React 中,表单元素自然保持一些内部状态。要拥有受控组件,您需要使用 React 状态管理表单数据。
import React, { useState } from 'react';
function NameForm() {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
const handleSubmit = (event) => {
alert('提交的名字是:' + value);
event.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
<label>
名字:
<input type="text" value={value} onChange={handleChange} />
</label>
<input type="submit" value="提交" />
</form>
);
}
最佳实践
组件组织
- 保持组件小巧,专注于单一职责
- 使用一致的文件结构(例如,每个文件一个组件)
- 将相关组件分组到文件夹中
性能优化
- 对经常使用相同 props 渲染的函数组件使用 React.memo
- 使用 useCallback 钩子来记忆函数
- 使用 useMemo 钩子来记忆昂贵的计算
- 使用 React DevTools Profiler 识别性能瓶颈
import React, { memo, useCallback, useMemo } from 'react';
const ExpensiveComponent = memo(function ExpensiveComponent({ data, onItemClick }) {
// 此组件仅在 data 或 onItemClick 变化时重新渲染
return (
<div>
{data.map(item => (
<div key={item.id} onClick={() => onItemClick(item.id)}>
{item.name}
</div>
))}
</div>
);
});
function ParentComponent() {
const [items, setItems] = useState([/* 一些数据 */]);
// useCallback 记忆函数
const handleItemClick = useCallback((id) => {
console.log('项目被点击:', id);
}, []);
// useMemo 记忆计算值
const sortedItems = useMemo(() => {
return [...items].sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
return (
<ExpensiveComponent
data={sortedItems}
onItemClick={handleItemClick}
/>
);
}
代码风格和约定
- 使用带钩子的函数组件而非类组件
- 对 props 和 state 使用解构
- 使用展开运算符复制对象和数组
- 遵循 Create React App 推荐的 ESLint 规则
常见模式
用于状态管理的 Context API
用于在不使用 prop 钻取的情况下跨多个组件共享状态:
import React, { createContext, useContext, useState } from 'react';
// 创建上下文
const ThemeContext = createContext();
// 提供者组件
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// 消费者组件
function ThemedButton() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<button
onClick={toggleTheme}
style={{
background: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#333' : '#fff'
}}
>
切换主题
</button>
);
}
// 应用
function App() {
return (
<ThemeProvider>
<div>
<h1>主题示例</h1>
<ThemedButton />
</div>
</ThemeProvider>
);
}
自定义钩子
将可重用逻辑提取到自定义钩子中:
import { useState, useEffect } from 'react';
// 用于获取数据的自定义钩子
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP 错误!状态:${response.status}`);
}
const result = await response.json();
setData(result);
setError(null);
} catch (error) {
setError(error.message);
setData(null);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// 使用自定义钩子
function UserProfile({ userId }) {
const { data, loading, error } = useFetch(`https://api.example.com/users/${userId}`);
if (loading) return <div>加载中...</div>;
if (error) return <div>错误:{error}</div>;
return (
<div>
<h1>{data.name}</h1>
<p>邮箱:{data.email}</p>
</div>
);
}
常见问题解答
state 和 props 有什么区别?
- Props 是从父组件传递给组件的,是只读的
- State 是在组件内部管理的,可以使用 setState 或 useState 更新
什么时候应该使用类组件与函数组件?
在现代 React(16.8+)中,带钩子的函数组件适用于大多数用例。类组件仍然受支持,但主要用于遗留代码或特定用例。
如何在 React 中处理表单?
使用受控组件,其中表单数据由 React 状态处理,或者对于复杂表单,使用 Formik 或 React Hook Form 等库。
如何为 React 组件添加样式?
几种方法:
- 使用 className 的常规 CSS
- 使用 style 属性的内联样式
- CSS 模块
- CSS-in-JS 库(styled-components, emotion)
- 实用优先的 CSS 框架(Tailwind CSS)
如何优化 React 中的性能?
- 对函数组件使用 React.memo
- 使用 useCallback 和 useMemo 钩子
- 对长列表实现虚拟化
- 使用 React.lazy 和 Suspense 进行代码分割
- 避免不必要的重新渲染
相关资源
本文档将持续更新,如有问题请通过 GitHub Issues 反馈。