如何避免自定义权限查询Hook重复渲染,仅按需更新?
解决自定义权限Hook的持续重渲染问题
原Hook出现持续重渲染的根本原因是useEffect的依赖数组错误地包含了permission状态。每次通过setPermission更新状态后,permission值变化会触发useEffect重新执行,再次调用navigator.permissions.query并更新状态,形成无限循环。
修正后的Hook实现
以下代码解决了无限循环问题,同时实现了权限变化的监听,并可按需控制状态更新时机:
/** * @param {PermissionName} name 要检查的权限名称,可选值包括: * "geolocation" | "notifications" | "persistent-storage" | "push" | "screen-wake-lock" | "xr-spatial-tracking" | "camera"; * @returns {PermissionStatus | undefined} 当前权限状态 */ export const useCurrentDevicePermissions = (name: PermissionName): PermissionStatus | undefined => { const [permission, setPermission] = useState<PermissionStatus>(); useEffect(() => { let cleanup: (() => void) | undefined; navigator.permissions.query({ name }) .then(status => { // 初始获取权限时直接更新状态 setPermission(status); const handlePermissionChange = () => { // 仅当状态变为granted或denied时更新组件状态 if (status.state === 'granted' || status.state === 'denied') { setPermission(status); } }; status.addEventListener('change', handlePermissionChange); cleanup = () => status.removeEventListener('change', handlePermissionChange); }); return () => cleanup?.(); }, [name]); // 仅当权限名称变化时重新执行副作用 return permission; };
关键优化点
- 修正依赖数组:将
useEffect的依赖改为[name],确保只有权限名称变更时才重新查询权限,彻底打破无限循环。 - 事件监听替代重复查询:利用
PermissionStatus的change事件监听权限变化,无需重复调用查询接口,性能更优。 - 按需控制状态更新:在事件回调中添加状态判断,仅当权限状态变为
granted或denied时更新组件状态(若需要监听prompt状态,可移除该判断)。 - 清理副作用:添加事件监听的移除逻辑,避免组件卸载后出现内存泄漏。
使用方式
保持原有调用方式即可:
const cameraPermissionState = useCurrentDevicePermissions('camera' as PermissionName);
内容的提问来源于stack exchange,提问作者nyphur
相关产品推荐
相关产品推荐

