React useSyncExternalStore 封装 useWindowSize、useURLParams
- useWindowSize
// useWindowSize.ts
import { useRef, useCallback, useSyncExternalStore } from "react";
export function useWindowSize() {
const cachedValueRef = useRef({
width: window.innerWidth,
height: window.innerHeight,
}); // 用于缓存 getSnapshot 的返回值
const getSnapshot = useCallback(() => {
// 解决每次调用都返回了一个新对象,造成无限循环
const windowObj = {
width: window.innerWidth,
height: window.innerHeight,
};
if (JSON.stringify(cachedValueRef.current) !== JSON.stringify(windowObj)) {
cachedValueRef.current = windowObj;
}
return cachedValueRef.current;
}, []);
const subscribe = useCallback((callback: () => void) => {
window.addEventListener("resize", callback);
return () => window.removeEventListener("resize", callback);
}, []);
const { width, height } = useSyncExternalStore(subscribe, getSnapshot);
return { width, height };
}
- useURLParams
// useURLParams.ts
import { useSyncExternalStore, useCallback } from "react";
export function useURLParams<T>(
key: string,
initialValue: T,
useReplace: boolean = false // 是否使用 replaceState
): [T, (value: T) => void] {
// 获取 URL 参数的值,若没有则使用初始值
const getSnapshot = useCallback(() => {
try {
const urlParams = new URLSearchParams(window.location.search);
const storedValue = urlParams.get(key);
return storedValue ? (JSON.parse(storedValue) as T) : initialValue;
} catch (e) {
return initialValue;
}
}, [key, initialValue]);
// 订阅 URL 的变化
const subscribe = useCallback((onStoreChange: () => void) => {
// 使用 popstate 事件来监听 URL 变化
window.addEventListener("popstate", onStoreChange);
return () => window.removeEventListener("popstate", onStoreChange);
}, []);
const storedValue = useSyncExternalStore(subscribe, getSnapshot);
// 更新 URL 参数
const setStoredValue = useCallback(
(value: T) => {
try {
const newValue = JSON.stringify(value);
const urlParams = new URLSearchParams(window.location.search);
// 更新 URL 参数
urlParams.set(key, newValue);
const newUrl = `${window.location.pathname}?${urlParams.toString()}`;
if (useReplace) {
// 使用 replaceState 替换当前的历史记录条目
window.history.replaceState({}, "", newUrl);
} else {
// 使用 pushState 添加新的历史记录条目
window.history.pushState({}, "", newUrl);
}
// 触发 popstate 事件,通知其他页面更新
window.dispatchEvent(new Event("popstate"));
} catch (e) {
console.error("Failed to set URL param", e);
}
},
[key, useReplace]
);
return [storedValue, setStoredValue];
}
本文来自博客园,作者:苏沐~,转载请注明原文链接:https://www.cnblogs.com/sumu80/p/18946650

浙公网安备 33010602011771号