React Hooks 系列:自定义 Hook 的解析笔记
React 自定义 Hook 是一种用于在函数组件中复用逻辑的强大工具。通过自定义 Hook,你可以将组件中的状态逻辑提取出来,使其可以在多个组件中共享。自定义 Hook 的命名通常以 use
开头,以便 React 能够识别它是一个 Hook。
1. 自定义 Hook 的基本概念
自定义 Hook 本质上是一个 JavaScript 函数,它可以使用 React 的内置 Hook(如 useState
、useEffect
等)来封装一些可复用的逻辑。自定义 Hook 的返回值可以是任何类型的数据,通常是一个对象或数组,供组件使用。
2. 创建自定义 Hook
假设我们有一个需求:在多个组件中需要监听窗口的大小变化。我们可以将这个逻辑提取到一个自定义 Hook 中。
import { useState, useEffect } from 'react';
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener('resize', handleResize);
// 清除事件监听器
return () => window.removeEventListener('resize', handleResize);
}, []); // 空数组表示只在组件挂载和卸载时执行
return windowSize;
}
3. 使用自定义 Hook
在组件中使用自定义 Hook 非常简单,只需要像调用普通函数一样调用它即可。
function MyComponent() {
const size = useWindowSize();
return (
<div>
<p>Width: {size.width}px</p>
<p>Height: {size.height}px</p>
</div>
);
}
4. 自定义 Hook 的优势
- 逻辑复用:自定义 Hook 可以将组件中的逻辑提取出来,避免重复代码。
- 代码组织:通过自定义 Hook,可以将复杂的逻辑拆分成更小的、可管理的部分。
- 易于测试:自定义 Hook 可以单独测试,而不需要依赖于组件的渲染。
5. 自定义 Hook 的规则
- 命名规则:自定义 Hook 的名称必须以
use
开头,这样 React 才能识别它是一个 Hook。 - 调用位置:自定义 Hook 只能在 React 函数组件或其他自定义 Hook 中调用,不能在普通 JavaScript 函数或类组件中调用。
- 条件调用:不能在条件语句或循环中调用 Hook,必须保证每次渲染时 Hook 的调用顺序一致。
6. 更多自定义 Hook 示例
6.1 使用 useState
和 useEffect
实现计时器
import { useState, useEffect } from 'react';
function useTimer(initialTime = 0) {
const [time, setTime] = useState(initialTime);
const [isRunning, setIsRunning] = useState(false);
useEffect(() => {
let interval;
if (isRunning) {
interval = setInterval(() => {
setTime((prevTime) => prevTime + 1);
}, 1000);
}
return () => clearInterval(interval);
}, [isRunning]);
return {
time,
isRunning,
start: () => setIsRunning(true),
stop: () => setIsRunning(false),
reset: () => setTime(initialTime),
};
}
6.2 使用 useReducer
实现复杂状态管理
import { useReducer } from 'react';
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 useCounter(initialState = { count: 0 }) {
const [state, dispatch] = useReducer(reducer, initialState);
return {
count: state.count,
increment: () => dispatch({ type: 'increment' }),
decrement: () => dispatch({ type: 'decrement' }),
};
}
7. 总结
自定义 Hook 是 React 中一种强大的工具,可以帮助你更好地组织和复用代码。通过自定义 Hook,你可以将组件中的逻辑提取出来,使其更加模块化和可维护。记住,自定义 Hook 的命名必须以 use
开头,并且只能在 React 函数组件或其他自定义 Hook 中调用。