33 React.js 中的自定义 Hooks

在上一篇文章中,我们讨论了 React 中的常用 Hooks,例如 use <!-- more --> StateuseEffectuseContext。这些 Hooks 为我们提供了状态管理和副作用处理的基本能力,但在实际开发中,我们常常会面临一些特定的需求,这时就可以考虑创建自定义 Hooks。自定义 Hooks 允许我们将组件逻辑提取为可重用的函数,为代码的结构和可维护性提供了很大的帮助。

什么是自定义 Hooks?

自定义 Hooks 是一个普通的 JavaScript 函数,其名称以 use 开头,并且可以调用其他的 Hooks。它们允许我们将组件逻辑提取成独立的函数,以便在多个组件之间共享。

如何创建自定义 Hooks?

创建自定义 Hooks 并不复杂。以下是一个简单的示例,展示如何创建一个用于获取窗口尺寸的自定义 Hook。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { useState, useEffect } from 'react';

function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});

useEffect(() => {
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
};

window.addEventListener('resize', handleResize);

// 清理事件监听器
return () => window.removeEventListener('resize', handleResize);
}, []);

return windowSize;
}

使用自定义 Hooks

有了 useWindowSize 自定义 Hook 后,我们可以在任何组件中使用它,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from 'react';
import useWindowSize from './useWindowSize';

function DisplaySize() {
const { width, height } = useWindowSize();

return (
<div>
<h1>窗口尺寸</h1>
<p>宽度: {width}px</p>
<p>高度: {height}px</p>
</div>
);
}

在上面的例子中,当窗口大小改变时,DisplaySize 组件会自动更新显示的宽度和高度。

进阶自定义 Hooks 的使用

接受参数的自定义 Hooks

其实,自定义 Hooks 还可以接受参数,以便于我们更加灵活地使用。例如,创建一个 countdown 自定义 Hook:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { useState, useEffect } from 'react';

function useCountdown(initialCount) {
const [count, setCount] = useState(initialCount);

useEffect(() => {
if (count === 0) return;

const interval = setInterval(() => {
setCount(prevCount => prevCount - 1);
}, 1000);

return () => clearInterval(interval);
}, [count]);

return count;
}

使用这个 countdown Hook 的组件:

1
2
3
4
5
6
7
8
9
10
11
12
import React from 'react';
import useCountdown from './useCountdown';

function CountdownTimer() {
const count = useCountdown(10); // 从 10 开始倒计时

return (
<div>
<h1>倒计时: {count}</h1>
</div>
);
}

改善逻辑重用

使用自定义 Hooks 的另一个重要优势是能够减少逻辑的重复。如果有多个组件需要实现相同的功能,比如表单输入的控制、数据获取等场景,就可以将其逻辑提取出来,形成自定义 Hooks。例如,我们可以创建一个用于处理表单输入的自定义 Hook useFormInput

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { useState } from 'react';

function useFormInput(initialValue) {
const [value, setValue] = useState(initialValue);

const handleChange = (event) => {
setValue(event.target.value);
};

return {
value,
onChange: handleChange,
};
}

使用这个 useFormInput Hook 的组件示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React from 'react';
import useFormInput from './useFormInput';

function MyForm() {
const name = useFormInput('');
const email = useFormInput('');

const handleSubmit = (event) => {
event.preventDefault();
console.log('Name:', name.value);
console.log('Email:', email.value);
};

return (
<form onSubmit={handleSubmit}>
<div>
<label>
姓名:
<input type="text" {...name} />
</label>
</div>
<div>
<label>
邮箱:
<input type="email" {...email} />
</label>
</div>
<button type="submit">提交</button>
</form>
);
}

结束语

通过使用自定义 Hooks,我们可以使组件的逻辑更加清晰、可重用性更高。在下一篇文章中,我们将结合实战项目,进行项目需求分析,帮助您更好地将所学的知识应用到实际的开发中。希望您能够继续关注此次 React.js 从零教程的系列,期待与您在实战中相见!