携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情
👨💻文档地址:ahooks.js.org/zh-CN/
👨💻github地址:github.com/alibaba/hoo…
useFavicon
Link type 属性:type 属性可设置或者返回链接文档的类型(MIME 类型) ,比如MIME-types 实例: "text/css", "text/javascript", "image/gif", 等。
useEffect 中,获取传入 URL 的类型,将值赋值给 link.type。创建或者获取 link 标签,为 link.href 赋值,向 head 标签中添加即可。
import { useEffect } from 'react';
const ImgTypeMap = {
SVG: 'image/svg+xml',
ICO: 'image/x-icon',
GIF: 'image/gif',
PNG: 'image/png',
};
// 遍历某种类型的属性,并通过 keyof 操作符提取其属性的名称
type ImgTypes = keyof typeof ImgTypeMap;
const useFavicon = (href: string) => {
useEffect(() => {
if (!href) return;
const cutUrl = href.split('.');
const imgSuffix = cutUrl[cutUrl.length - 1].toLocaleUpperCase() as ImgTypes;
const link: HTMLLinkElement =
document.querySelector("link[rel*='icon']") || document.createElement('link');
link.type = ImgTypeMap[imgSuffix];
link.href = href;
link.rel = 'shortcut icon';
document.getElementsByTagName('head')[0].appendChild(link);
}, [href]);
};
export default useFavicon;
Example
当 url 变化的时候,useFavicon 中的 useEffect 的依赖项 href 发生变化,重新执行一遍逻辑。
import React, { useState } from 'react';
import { useFavicon } from 'ahooks';
export const GOOGLE_FAVICON_URL = 'https://www.google.com/favicon.ico';
export default () => {
const [url, setUrl] = useState<string>(DEFAULT_FAVICON_URL);
useFavicon(url);
return (
<>
<button
style={{ marginRight: 16 }}
onClick={() => {
setUrl(GOOGLE_FAVICON_URL);
}}
>
icon
</button>
</>
);
};
useTitle
判断当前是否是浏览器。
const isBrowser = !!(
typeof window !== 'undefined' &&
window.document &&
window.document.createElement
);
export default isBrowser;
如果是浏览器,则将传入的 title 赋值给 document.title。
import { useEffect, useRef } from 'react';
import isBrowser from '../utils/isBrowser';
function useTitle(title: string) {
const titleRef = useRef(isBrowser ? document.title : '');
useEffect(() => {
document.title = title;
}, [title]);
}
export default useTitle;
Example
import React from 'react';
import { useTitle } from 'ahooks';
export default () => {
useTitle('Page Title');
return (
<div>
<p>Set title of the page.</p>
</div>
);
};
ahooksuseTitle的restoreOnUnmount参数,在这个例子中,我还是有点不太能理解。
useTimeout
useLatest:返回当前最新值的 Hook,可以避免闭包问题。
传入 fn 和 delay。判断 delay 是否是数字,并且要大于 0。当 delay 发生改变的时候,使用 setTimeout。同时返回 clearTimeout,清除定时器。hooks 同时也返回 clearTimeout。
export const isNumber = (value: unknown): value is number => typeof value === 'number';
import { useCallback, useEffect, useRef } from 'react';
import useLatest from '../useLatest';
import { isNumber } from '../utils';
function useTimeout(fn: () => void, delay: number | undefined) {
const fnRef = useLatest(fn);
const timerRef = useRef<number | NodeJS.Timer>();
useEffect(() => {
if (!isNumber(delay) || delay < 0) return;
timerRef.current = setTimeout(() => {
fnRef.current();
}, delay);
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current as NodeJS.Timer);
}
};
}, [delay]);
const clear = useCallback(() => {
if (timerRef.current) {
clearTimeout(timerRef.current as NodeJS.Timer);
}
}, []);
return clear;
}
export default useTimeout;
Example
import React, { useState } from 'react';
import { useTimeout } from 'ahooks';
export default () => {
const [count, setCount] = useState(0);
const [delay, setDelay] = useState<number | undefined>(1000);
return (
<div>
<p> count: {count} </p>
<p style={{ marginTop: 16 }}> 延迟秒数: {delay} </p>
<button onClick={() => setDelay((t) => (!!t ? t + 1000 : 1000))}>
延迟秒数 + 1000
</button>
</div>
);
};
传入的 delay 变大,count 的增加明显变慢。
import React, { useState } from 'react';
import { useTimeout } from 'ahooks';
export default () => {
const [count, setCount] = useState(0);
const [delay, setDelay] = useState<number | undefined>(1000);
const clear = useTimeout(() => {
setCount(count + 1);
}, delay);
return (
<div>
<button onClick={clear}>clear</button>
</div>
);
};
调用 clear,清除页面的定时器。