React Hooks 是 React 16.8 引入的特性,它让函数组件能够拥有类组件的状态管理和生命周期等能力,无需编写类组件就能实现更复杂的逻辑。Hooks 解决了类组件中代码复用难、逻辑分散等问题,让代码更简洁、易维护。
下面介绍几个常见的 React Hooks 及其用法:
1. useState:管理组件状态
useState
用于在函数组件中添加状态,它返回一个状态变量和更新该状态的函数。
import { useState } from 'react';
function Counter() {
// 声明一个count状态,初始值为0
const [count, setCount] = useState(0);
return (
<div>
<p>你点击了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>
点击增加
</button>
<button onClick={() => setCount(0)}>
重置
</button>
</div>
);
}
2. useEffect:处理副作用
useEffect
可以让函数组件执行类似类组件中生命周期的操作,如数据获取、订阅、DOM 操作等。它相当于 componentDidMount
、componentDidUpdate
和 componentWillUnmount
的组合。
import { useState, useEffect } from 'react';
function UserInfo({ userId }) {
const [user, setUser] = useState(null);
// 组件挂载和userId变化时执行
useEffect(() => {
// 获取用户数据
const fetchUser = async () => {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
setUser(data);
};
fetchUser();
// 清理函数,在组件卸载或userId变化前执行
return () => {
// 比如取消请求等操作
};
}, [userId]); // 依赖项数组,只有userId变化时才会重新执行
if (!user) return <div>加载中...</div>;
return (
<div>
<h2>{user.name}</h2>
<p>年龄:{user.age}</p>
</div>
);
}
3. useContext:共享状态
useContext
用于在组件树中共享状态,避免通过 props 层层传递。
首先创建上下文:
import { createContext } from 'react';
const ThemeContext = createContext('light');
然后在组件中使用:
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
function ThemedButton() {
// 获取上下文的值
const theme = useContext(ThemeContext);
return (
<button style={{
background: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#333' : '#fff'
}}>
主题按钮
</button>
);
}
// 在父组件中提供上下文值
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}
4. useReducer:复杂状态管理
当组件状态逻辑复杂时,useReducer
比 useState
更合适,它通过 reducer 函数管理状态变化。
import { useReducer } from 'react';
// 定义reducer函数
function todoReducer(state, action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, { id: Date.now(), text: action.text, done: false }];
case 'TOGGLE_TODO':
return state.map(todo =>
todo.id === action.id ? { ...todo, done: !todo.done } : todo
);
default:
return state;
}
}
function TodoList() {
// 使用useReducer,初始状态为空数组
const [todos, dispatch] = useReducer(todoReducer, []);
const [text, setText] = useState('');
const handleAdd = () => {
if (text) {
dispatch({ type: 'ADD_TODO', text });
setText('');
}
};
return (
<div>
<input
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="输入待办事项"
/>
<button onClick={handleAdd}>添加</button>
<ul>
{todos.map(todo => (
<li
key={todo.id}
style={{ textDecoration: todo.done ? 'line-through' : 'none' }}
onClick={() => dispatch({ type: 'TOGGLE_TODO', id: todo.id })}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}
5. useRef:访问DOM或保存可变值
useRef
可以创建一个ref对象,用于访问DOM元素,也可以保存一个可变值,其变化不会触发组件重新渲染。
import { useRef, useEffect } from 'react';
function TextInputWithFocusButton() {
const inputRef = useRef(null);
const focusInput = () => {
// 通过ref访问DOM元素并调用方法
inputRef.current.focus();
};
// 保存上一次渲染时的count值
const prevCountRef = useRef();
const [count, setCount] = useState(0);
useEffect(() => {
prevCountRef.current = count;
});
const prevCount = prevCountRef.current;
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>聚焦输入框</button>
<p>当前count: {count},上一次count: {prevCount}</p>
<button onClick={() => setCount(count + 1)}>增加</button>
</div>
);
}
这些是 React 中最常用的 Hooks,合理使用它们可以让函数组件的逻辑更加清晰、易于管理和复用。此外,还有 useMemo
、useCallback
等用于性能优化的 Hooks,在实际开发中可以根据需求选择使用。