1877 字
9 分钟

React Hooks

React Hooks#

React Hooks是React 16.8引入的新特性,允许你在函数组件中使用state和其他React特性,而不需要编写类组件。Hooks的出现使得函数组件的功能更加强大,代码更加简洁易读。

1. useState Hook#

useState是最基本的Hook,用于在函数组件中添加state。

基本用法#

import React, { useState } from 'react';
function Counter() {
// 声明一个名为count的state变量,初始值为0
// setCount是更新count的函数
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

注意事项#

  • useState接收一个初始值作为参数,返回一个数组,包含当前state值和更新state的函数
  • 初始值只在组件首次渲染时使用
  • 调用更新函数时,React会重新渲染组件
  • 可以在一个组件中使用多个useState Hook

2. useEffect Hook#

useEffect Hook用于在组件渲染后执行副作用操作,如数据获取、订阅或手动修改DOM。

基本用法#

import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 类似于componentDidMount和componentDidUpdate
useEffect(() => {
// 更新文档标题
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

清理副作用#

import React, { useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
// 订阅好友状态
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// 清理函数,在组件卸载或重新渲染前执行
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}

控制副作用的执行时机#

import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
// 只在count变化时执行
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 依赖数组,只有当数组中的值变化时,才会重新执行副作用
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
);
}
  • 依赖数组为空[]时,副作用只在组件首次渲染时执行一次,类似于componentDidMount
  • 依赖数组中包含变量时,只有当这些变量变化时,副作用才会重新执行
  • 不提供依赖数组时,副作用会在每次组件渲染后都执行

3. useContext Hook#

useContext Hook用于在函数组件中访问React的Context API,避免了使用Context.Consumer。

基本用法#

import React, { useContext } from 'react';
// 创建Context
const ThemeContext = React.createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
// 使用useContext Hook访问Context
const theme = useContext(ThemeContext);
return (
<button style={{ background: theme === 'dark' ? '#333' : '#fff', color: theme === 'dark' ? '#fff' : '#333' }}>
{theme} theme button
</button>
);
}

4. useReducer Hook#

useReducer Hook是useState的替代方案,用于管理复杂的state逻辑。

基本用法#

import React, { useReducer } from 'react';
// 定义reducer函数
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
// 初始化state和dispatch函数
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>
Increment
</button>
<button onClick={() => dispatch({ type: 'decrement' })}>
Decrement
</button>
</div>
);
}

5. useCallback Hook#

useCallback Hook用于缓存函数,避免在每次渲染时都创建新的函数实例。

基本用法#

import React, { useState, useCallback } from 'react';
function Button({ onClick, children }) {
console.log('Button rendered');
return <button onClick={onClick}>{children}</button>;
}
function App() {
const [count, setCount] = useState(0);
// 缓存handleClick函数,只有当count变化时才会重新创建
const handleClick = useCallback(() => {
console.log('Clicked with count:', count);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
<Button onClick={handleClick}>
Click me
</Button>
</div>
);
}

6. useMemo Hook#

useMemo Hook用于缓存计算结果,避免在每次渲染时都重新计算。

基本用法#

import React, { useState, useMemo } from 'react';
function App() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
// 缓存计算结果,只有当count变化时才会重新计算
const expensiveValue = useMemo(() => {
console.log('Calculating expensive value...');
let result = 0;
for (let i = 0; i < 1000000000; i++) {
result += i;
}
return result;
}, [count]);
return (
<div>
<p>Count: {count}</p>
<p>Expensive value: {expensiveValue}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter your name"
/>
</div>
);
}

7. useRef Hook#

useRef Hook用于创建一个可变的ref对象,其.current属性可以存储任意值,类似于类组件中的实例属性。

基本用法#

import React, { useRef } from 'react';
function TextInputWithFocusButton() {
// 创建一个ref对象
const inputEl = useRef(null);
// 聚焦输入框
const onButtonClick = () => {
inputEl.current.focus();
};
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>
Focus the input
</button>
</div>
);
}

8. 自定义Hook#

自定义Hook是一个函数,其名称以”use”开头,可以在其中使用其他Hook。自定义Hook允许你重用状态逻辑,而不需要复制粘贴代码。

基本用法#

import React, { useState, useEffect } from 'react';
// 自定义Hook
function useFriendStatus(friendId) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendId, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendId, handleStatusChange);
};
}, [friendId]);
return isOnline;
}
// 在组件中使用自定义Hook
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}

9. Hook的规则#

使用Hook时需要遵循以下规则:

  1. 只在顶层调用Hook:不要在循环、条件或嵌套函数中调用Hook
  2. 只在React函数组件或自定义Hook中调用Hook:不要在普通JavaScript函数中调用Hook
  3. 遵循Hook的命名约定:自定义Hook的名称必须以”use”开头

10. 常用Hook组合#

useState + useEffect#

import React, { useState, useEffect } from 'react';
function DataFetcher({ 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);
const jsonData = await response.json();
setData(jsonData);
setError(null);
} catch (err) {
setError(err.message);
setData(null);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error}</div>;
}
return <div>Data: {JSON.stringify(data)}</div>;
}

useState + useCallback#

import React, { useState, useCallback } from 'react';
function TodoList({ todos, onToggle, onDelete }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<span
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
onClick={() => onToggle(todo.id)}
>
{todo.text}
</span>
<button onClick={() => onDelete(todo.id)}>
Delete
</button>
</li>
))}
</ul>
);
}
function App() {
const [todos, setTodos] = useState([
{ id: 1, text: 'Learn React', completed: false },
{ id: 2, text: 'Learn Hooks', completed: false },
{ id: 3, text: 'Build an app', completed: false }
]);
// 缓存onToggle函数
const onToggle = useCallback((id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
}, [todos]);
// 缓存onDelete函数
const onDelete = useCallback((id) => {
setTodos(todos.filter(todo => todo.id !== id));
}, [todos]);
return (
<div>
<TodoList todos={todos} onToggle={onToggle} onDelete={onDelete} />
</div>
);
}

练习#

  1. 使用useState和useEffect创建一个计数器组件,能够显示当前时间。
  2. 使用useContext创建一个主题切换组件,能够在明/暗主题之间切换。
  3. 使用useReducer创建一个待办事项列表,支持添加、删除和标记完成功能。
  4. 创建一个自定义Hook,用于处理表单输入。

总结#

在本章节中,我们学习了React Hooks的使用方法和最佳实践,包括:

  • useState:在函数组件中添加state
  • useEffect:处理副作用操作
  • useContext:访问React的Context API
  • useReducer:管理复杂的state逻辑
  • useCallback:缓存函数
  • useMemo:缓存计算结果
  • useRef:创建可变的ref对象
  • 自定义Hook:重用状态逻辑
  • Hook的规则:只在顶层调用、只在React函数组件或自定义Hook中调用

Hooks的出现使得函数组件的功能更加强大,代码更加简洁易读。在现代React开发中,Hooks已经成为主流,推荐使用函数组件配合Hooks来构建React应用。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

React Hooks
https://firefly.cuteleaf.cn/posts/react/04-react-hooks/
作者
Lireal
发布于
2026-01-21
许可协议
CC BY-NC-SA 4.0

目录