引言
我在这里记录了自己实现了一些常用 Hooks, 包括小程序框架这种, 用来提高日常的开发速度.
单独在这里记录是因为会使用到 Taro, 直接实现包可能导致无法正常使用; 如果需要, 你可以直接复制对应 Hook 的源代码进行使用.
如果可以的话, 希望你可以保留对应的作者注释, 即便我看不到, 我也会很开心 😸
通用
useAsyncEffect
允许您直接在 useEffect 中, 直接使用 async/await 语法.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| import { useEffect, useRef } from "react"; import type { DependencyList } from "react";
type AsyncEffectCleanup = () => void;
type AsyncEffectCallback = () => Promise<AsyncEffectCleanup | void>;
const useAsyncEffect = ( asyncEffect: AsyncEffectCallback, deps: DependencyList, ): void => { const effectRef = useRef<AsyncEffectCallback>(asyncEffect);
effectRef.current = asyncEffect;
useEffect(() => { let isMounted = true;
let cleanup: AsyncEffectCleanup = () => {};
const execute = async () => { try { const result = await effectRef.current();
if (isMounted && typeof result === "function") { cleanup = result; } else if (!isMounted && typeof result === "function") { result(); } } catch (e) { if (isMounted) { console.error("useAsyncEffect 出现错误:", e); } } };
execute();
return () => { isMounted = false; cleanup(); };
}, deps); };
export default useAsyncEffect;
|
Taro
测试 Taro 版本: ^4.1.6
useLayoutHeight
动态的, 获取某些指定元素的高度, 单位为 px.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| import { useState, useLayoutEffect } from "react"; import Taro from "@tarojs/taro";
type ElementRect = { height: number } | null; type QueryResult = ElementRect[] | null;
const useLayoutHeight = (selectors: string[], dependences: any[] = []) => { const [height, setHeight] = useState(0);
const selectorsKey = JSON.stringify(selectors);
useLayoutEffect(() => { let isMounted = true;
if (!selectors || selectors.length === 0) { setHeight(0); return; }
try { const query = Taro.createSelectorQuery();
selectors.forEach((sel) => { query.selectAll(sel).boundingClientRect(); });
query.exec((res: QueryResult[]) => { if (!isMounted) return;
const totalHeight = res.reduce((acc, rects) => { const groupHeight = rects?.reduce((groupAcc, rect) => { return groupAcc + (rect?.height || 0); }, 0) || 0;
return acc + groupHeight; }, 0);
setHeight(totalHeight); });
return () => { isMounted = false; }; } catch (err) { console.error("useLayoutHeight 同步错误:", err); } }, [selectorsKey, ...dependences]);
return height; };
export default useLayoutHeight;
|
useNavInfo
获取顶部安全区的一些相关信息, 包括微信小程序胶囊的一些信息, 以及屏幕的一些信息.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| import { useState, useEffect } from "react"; import Taro from "@tarojs/taro";
interface INavInfo { statusBarHeight: number; titleBarHeight: number; titleBarWidth: number; appHeaderHeight: number; marginSides: number; capsuleWidth: number; capsuleHeight: number; capsuleLeft: number; contentHeight: number; screenHeight: number; windowHeight: number; }
const useNavInfo = (): INavInfo => { const [navInfo, setNavInfo] = useState({ statusBarHeight: 0, titleBarHeight: 0, titleBarWidth: 0, appHeaderHeight: 0, marginSides: 0, capsuleWidth: 0, capsuleHeight: 0, capsuleLeft: 0, contentHeight: 0, screenHeight: 0, windowHeight: 0, });
useEffect(() => { const { statusBarHeight, screenWidth, screenHeight, windowHeight } = Taro.getEnv() === "WEAPP" || Taro.getEnv() === "HARMONYHYBRID" ? Taro.getWindowInfo() : { statusBarHeight: 0, screenWidth: 0, screenHeight: 0, windowHeight: 0, };
const { width, height, left, top, right } = Taro.getEnv() === "WEAPP" || Taro.getEnv() === "TT" || Taro.getEnv() === "HARMONYHYBRID" ? Taro.getMenuButtonBoundingClientRect() : { width: 0, height: 0, left: 0, top: 0, right: 0 }; const titleBarHeight = height + (top - statusBarHeight!) * 2; const appHeaderHeight = statusBarHeight! + titleBarHeight; const marginSides = screenWidth - right; const titelBarWidth = screenWidth - width - marginSides * 3; const contentHeight = screenHeight - appHeaderHeight;
setNavInfo({ statusBarHeight: statusBarHeight || 0, titleBarHeight: titleBarHeight, titleBarWidth: titelBarWidth, appHeaderHeight: appHeaderHeight, marginSides: marginSides, capsuleWidth: width, capsuleHeight: height, capsuleLeft: left, contentHeight: contentHeight, screenHeight: screenHeight, windowHeight: windowHeight, }); }, []);
return navInfo; };
export default useNavInfo;
|