“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 16 天,点击查看活动详情”
1. 简介
在之前的学习中我们一直都是以函数式组件来开发的,函数式组件又是以Hook使用 state 以及其他的 React 特性,我们之前学习了挺多内置Hook的,但是在实际开发中我们可能会遇到这样的场景,将组件逻辑提取到可重用的函数中来自定义 Hook。
2. 代码案例
在两个函数之间重复复用逻辑时,我们会把它提取到第三个函数中。而组件和 Hook 都是函数,所以也同样适用这种方式,自定义 Hook 是一个函数,其名称以 “
use” 开头,函数内部可以调用其他的 Hook
1. 自定义一个滚动距离顶部的hook
- 通过监听scroll方法来获取
document.documentElement.scrollTop值,赋予状态Y值,并返回
import {useState} from "react";
export function useWindowScroll() {
const [y, setY] = useState(0)
window.addEventListener('scroll', () => {
const h = document.documentElement.scrollTop
setY(h)
})
return [y]
}
- 使用自定义hook
通过直接导入hook使用,并且打印Y就可以看到hook被触发了
import {useWindowScroll} from "../hooks/useWindowScroll";
export default function demo02() {
// 使用自定义hook
const [y] = useWindowScroll()
return (
<>
<div className="box">
<div className="box-center">{y}</div>
</div>
</>
)
}
2. 自定义hook,监听数据,自动存储同步到localStorage
- 在该hook中我们看到,可以在自定义中使用我们的内置Hook
import {useEffect, useState} from "react";
/**
* 只要message 变化, 就自动同步到本地
*/
export function useLocalStorage(key: string, defaultValue: string) {
const [message, setMessage] = useState(defaultValue)
useEffect(() => {
window.localStorage.setItem(key, message)
}, [message, key])
return [message, setMessage]
}
- 使用Hook
因为自定义的HookuseLocalStorage 是返回了一个数组数据,我们接受也是以以数组形式来接受,并且使用方法与内置Hook useState一样,通过调用setMessage之后触发了自定义Hook之中的useEffect把数据存储到localStorage中
import {useLocalStorage} from "../hooks/useLocalStorage";
export default function demo02() {
// 使用自定义hook
const [message, setMessage] = useLocalStorage('name', "")
return (
<>
<div className="box">
{message}
<button onClick={() => setMessage('张飞')}>修改message</button>
</div>
</>
)
}
3. 总结
- 自定义 Hook 是一个函数,其名称以 “
use” 开头,函数内部可以调用其他的 Hook - 自定义 Hook 必须以 “
use” 开头 必须如此。这个约定非常重要。不遵循的话,由于无法判断某个函数是否包含对其内部 Hook 的调用,React 将无法自动检查你的 Hook 是否违反了 Hook 的规则。 - 在两个组件中使用相同的 Hook 不会共享 state ,自定义 Hook 是一种重用状态逻辑的机制(例如设置为订阅并存储当前值),所以每次使用自定义 Hook 时,其中的所有 state 和副作用都是完全隔离的。