1. 组件基础
// 函数组件
const FunctionComponent = (props) => {
// props 是只读的,不能修改
const { name, age } = props
// 返回 JSX
return (
<div>
<h1>Hello, {name}</h1>
<p>Age: {age}</p>
</div>
)
}
// 类组件
class ClassComponent extends React.Component {
// 构造函数,初始化 state
constructor(props) {
super(props) // 必须调用 super(props)
this.state = {
count: 0
}
// 方法绑定 this
this.handleClick = this.handleClick.bind(this)
}
// 生命周期方法
componentDidMount() {
// 组件挂载后执行,适合做初始化工作
console.log('Component mounted')
}
componentDidUpdate(prevProps, prevState) {
// 组件更新后执行,可以比较前后 props 和 state
if (prevState.count !== this.state.count) {
console.log('Count changed')
}
}
componentWillUnmount() {
// 组件卸载前执行,适合做清理工作
console.log('Component will unmount')
}
// 事件处理方法
handleClick() {
// 使用 setState 更新状态
this.setState((prevState) => ({
count: prevState.count + 1
}))
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleClick}>Increment</button>
</div>
)
}
}
2. Hooks 使用
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react'
const HooksExample = () => {
// useState: 状态管理
const [count, setCount] = useState(0) // 初始值为 0
const [user, setUser] = useState(null) // 初始值为 null
// useRef: 引用 DOM 元素或保存任意可变值
const inputRef = useRef(null) // 用于引用 input 元素
const timerRef = useRef(null) // 用于保存定时器 ID
// useEffect: 副作用处理
useEffect(() => {
// 组件挂载时执行
console.log('Component mounted')
// 启动定时器
timerRef.current = setInterval(() => {
setCount(c => c + 1)
}, 1000)
// 返回清理函数,组件卸载时执行
return () => {
clearInterval(timerRef.current)
}
}, []) // 空依赖数组表示只在挂载和卸载时执行
// useEffect: 数据获取
useEffect(() => {
const fetchUser = async () => {
try {
const response = await fetch('https://api.example.com/user')
const data = await response.json()
setUser(data)
} catch (error) {
console.error('Failed to fetch user:', error)
}
}
fetchUser()
}, []) // 空依赖数组表示只在挂载时获取数据
// useCallback: 记忆化回调函数
const handleClick = useCallback(() => {
setCount(c => c + 1)
}, []) // 空依赖数组表示函数永远不变
// useMemo: 记忆化计算结果
const expensiveValue = useMemo(() => {
// 复杂计算
return count * 2
}, [count]) // 只在 count 变化时重新计算
return (
<div>
<p>Count: {count}</p>
<p>Expensive Value: {expensiveValue}</p>
<button onClick={handleClick}>Increment</button>
<input
ref={inputRef} // 引用 DOM 元素
type="text"
placeholder="Type something..."
/>
{user && (
<div>
<h2>User Info</h2>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
</div>
)}
</div>
)
}
3. 自定义 Hook
// 自定义 Hook:管理表单状态
function useForm(initialValues = {}) {
// 表单状态
const [values, setValues] = useState(initialValues)
// 错误状态
const [errors, setErrors] = useState({})
// 处理输入变化
const handleChange = useCallback((e) => {
const { name, value } = e.target
setValues(prev => ({
...prev,
[name]: value
}))
}, [])
// 表单验证
const validate = useCallback(() => {
const newErrors = {}
// 验证规则
Object.entries(values).forEach(([key, value]) => {
if (!value) {
newErrors[key] = 'This field is required'
}
})
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}, [values])
// 表单提交
const handleSubmit = useCallback((onSubmit) => {
return (e) => {
e.preventDefault()
if (validate()) {
onSubmit(values)
}
}
}, [values, validate])
// 重置表单
const reset = useCallback(() => {
setValues(initialValues)
setErrors({})
}, [initialValues])
return {
values,
errors,
handleChange,
handleSubmit,
reset
}
}
// 使用自定义 Hook
const LoginForm = () => {
const { values, errors, handleChange, handleSubmit } = useForm({
email: '',
password: ''
})
const onSubmit = async (data) => {
try {
// 发送登录请求
const response = await api.login(data)
console.log('Login success:', response)
} catch (error) {
console.error('Login failed:', error)
}
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<input
name="email"
value={values.email}
onChange={handleChange}
placeholder="Email"
/>
{errors.email && <span>{errors.email}</span>}
</div>
<div>
<input
type="password"
name="password"
value={values.password}
onChange={handleChange}
placeholder="Password"
/>
{errors.password && <span>{errors.password}</span>}
</div>
<button type="submit">Login</button>
</form>
)
}
4. Context API
// 创建 Context
const ThemeContext = React.createContext({
theme: 'light',
toggleTheme: () => {}
})
// Context Provider
const ThemeProvider = ({ children }) => {
// 主题状态
const [theme, setTheme] = useState('light')
// 切换主题方法
const toggleTheme = useCallback(() => {
setTheme(t => t === 'light' ? 'dark' : 'light')
}, [])
// 提供 context 值
const value = {
theme,
toggleTheme
}
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
)
}
// 自定义 Hook 使用 Context
const useTheme = () => {
const context = useContext(ThemeContext)
if (!context) {
throw new Error('useTheme must be used within ThemeProvider')
}
return context
}
// 使用 Context 的组件
const ThemedButton = () => {
// 使用自定义 Hook 获取主题
const { theme, toggleTheme } = useTheme()
return (
<button
style={{
backgroundColor: theme === 'light' ? '#fff' : '#000',
color: theme === 'light' ? '#000' : '#fff'
}}
onClick={toggleTheme}
>
Toggle Theme
</button>
)
}
// 应用入口
const App = () => {
return (
<ThemeProvider>
<div>
<h1>Themed App</h1>
<ThemedButton />
</div>
</ThemeProvider>
)
}
5. 性能优化
import React, { memo, useCallback, useMemo } from 'react'
// 使用 memo 包装组件,只在 props 变化时重新渲染
const ExpensiveComponent = memo(({ data, onItemClick }) => {
console.log('ExpensiveComponent render')
return (
<ul>
{data.map(item => (
<li key={item.id} onClick={() => onItemClick(item)}>
{item.name}
</li>
))}
</ul>
)
})
const ParentComponent = () => {
const [items, setItems] = useState([])
const [count, setCount] = useState(0)
// 使用 useCallback 记忆化回调函数
const handleItemClick = useCallback((item) => {
console.log('Item clicked:', item)
}, []) // 空依赖数组表示函数永远不变
// 使用 useMemo 记忆化计算结果
const processedData = useMemo(() => {
return items.map(item => ({
...item,
processed: true
}))
}, [items]) // 只在 items 变化时重新计算
return (
<div>
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
<ExpensiveComponent
data={processedData}
onItemClick={handleItemClick}
/>
</div>
)
}
-
组件基础(函数组件和类组件)
-
Hooks 的使用(useState, useEffect, useCallback, useMemo, useRef)
-
自定义 Hook
-
Context API
-
性能优化(memo, useCallback, useMemo)