You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免自定义权限查询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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 11:46:05