一 前言
- 自定义hook是什么?
- 为什么要封装hook呢?
自定义hook,也就是hook的封装。
使用 Hook 其中一个就是要解决 class 中生命周期函数经常包含不相关的逻辑,但又把相关逻辑分离到了几个不同方法中的问题。 通过自定义 Hook,可以将组件逻辑提取到可重用的函数中。
二 介绍几个常用的hook
useRouterSearch:路由参数的获取与更改
const searchParams: any = new URLSearchParams(url);
const keys: any[] = [];
const _setKeys = () => {
keys.length = 0;
for (let b of searchParams) {
keys.push(b[0]);
}
};
_setKeys();
const setParams = (params: any) => {
for (let k in params) {
searchParams.set(k, params[k]);
}
_setKeys();
};
const getParam = (key: string) => {
return searchParams.get(key);
};
const removeParam = (key: string) => {
searchParams.delete(key);
};
const getParamsString = (): any => {
return searchParams.toString();
};
return { searchParams, setParams, getParamsString, getParam, removeParam };
};
- searchParams:获取由url?后拼接的key,value组成的对象
url:pagesize=5&page=1&orderBy=id&order=asc&selected=123465
searchParams={pagesize:5,page:1,orderBy:id,order:asc,selected:123465}
- setParams:可以根据特定的key,发生改变时, 重新编辑 URLSearchParams 并生成新的 string push到url。
- getParamsString:获取URL?后面的值
- getParam:可以传key拿value
- removeParam:传key移除某一项
业务场景:可以根据导出几个成员结合使用,生成想要的url,作为新的url去跳转。
useLocalstorage:设置本地存储与读取
export default (key: string, initialValue: any) => {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.log(error);
return initialValue;
}
});
const setValue = (value: any) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.log(error);
}
};
return [storedValue, setValue];
};
useDebounce:防抖
export default (value: any, delay: number) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};
useListenScreenSize:获取窗口宽高
首先,先给大家讲一下几个窗口尺寸(scrollWidth、clientWidth、offsetWidth)
- scrollWidth:是对象的实际内容的宽,不包边线宽度,会随对象中内容的多少改变(内容多了可能会改变对象的实际宽度)。
- clientWidth:是对象可见的宽度,不包滚动条等边线,会随窗口的显示大小改变
- offsetWidth:是对象的可见宽度,包滚动条等边线,会随窗口的显示大小改变。
const [size, setSize] = useState({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
});
const onResize = useCallback(() => {
setSize({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
});
}, []);
useEffect(() => {
window.addEventListener('resize', onResize);
return () => {
window.removeEventListener('resize', onResize);
};
}, []);
return size;
};
useFullScreen:全屏
import { useCallback, useEffect, useState } from 'react';
export default (id: string) => {
const [isFullPage, setIsFullPage] = useState<boolean>(false);
/**
* 点击触发全屏
*/
const onFullPageOpen = useCallback(() => {
const el = document.getElementById(id) as any;
let rfs = el.requestFullScreen || el.webkitRequestFullScreen || el.mozRequestFullScreen || el.msRequestFullscreen;
if (rfs) {
rfs.call(el);
setIsFullPage(true);
} else {
console.error('当前浏览器不兼容');
}
}, []);
/**
* 关闭全屏
*/
const onFullPageClose = useCallback(() => {
let el = document as any;
let cfs =
el.cancelFullScreen ||
el.mozCancelFullScreen ||
el.msExitFullscreen ||
el.webkitExitFullscreen ||
el.exitFullscreen;
if (cfs) {
cfs.call(el);
setIsFullPage(false);
} else {
console.error('当前浏览器不兼容');
}
}, []);
/**
* 监听是否是全屏状态 f11 事件
*/
useEffect(() => {
bindFullscreenListener();
return () => unBindFullscreenListener();
}, []);
const bindFullscreenListener = () => {
// 监听退出全屏事件 --- chrome 用 esc 退出全屏并不会触发 keyup 事件
document.addEventListener('webkitfullscreenchange', checkFull);
document.addEventListener('mozfullscreenchange', checkFull);
document.addEventListener('fullscreenchange', checkFull);
document.addEventListener('MSFullscreenChange', checkFull);
};
const unBindFullscreenListener = () => {
document.removeEventListener('webkitfullscreenchange', checkFull);
document.removeEventListener('mozfullscreenchange', checkFull);
document.removeEventListener('fullscreenchange', checkFull);
document.removeEventListener('MSFullscreenChange', checkFull);
};
/**
* 如果是 esc 关闭了全屏事件,显示全屏按钮,隐藏取消全屏按钮
*/
const checkFull = () => {
const el = document as any;
if (!el.webkitIsFullScreen && !el.mozFullScreen && !el.msFullscreenElement) {
setIsFullPage(false);
}
};
return { isFullPage, onFullPageOpen, onFullPageClose };
};
注意
需要注意的是hook的封装函数必须要以use开头,因为使用hook本身是有规则的,比如不能在条件语句中使用hook,不能在函数外使用hook;如果不适用use开头封装hook,则react无法自动检查该函数内使用的hook是否符合规则。
最后
这里只是分享几个可能会用到的hook。在日常开发中,大家也可以尝试着根据具体业务把逻辑提取到可重用的函数中,这样在组件中直接用调用自定义hook就会方便很多。使得在后面的开发中遇到相同业务逻辑可以直接复用,大大提高了效率。