代码之家  ›  专栏  ›  技术社区  ›  ReynierPM

在使用地理位置API和浏览器权限时,可以知道用户何时单击“允许”或“拒绝”?

  •  0
  • ReynierPM  · 技术社区  · 1 年前

    我需要知道用户在访问使用React+Typescript构建的网页时是点击了“允许”还是“拒绝”,但到目前为止我无法使其正常工作。请参阅以下代码:

    import { useEffect, useState } from "react";
    import useGeolocation from "./useGeolocation";
    
    export default function App() {
      const [locationAccess, setLocationAccess] = useState<boolean>(false);
    
      useEffect(() => {
        navigator.permissions
          .query({ name: "geolocation" })
          .then((permissionStatus) => {
            setLocationAccess(permissionStatus.state === "granted");
          });
      }, [locationAccess]);
    
      const geoLocation = useGeolocation({ locationAccess });
    
      console.log("geoLocation", geoLocation);
    
      return <></>;
    }
    

    当我第一次访问该页面,并请求您允许访问您的地理位置时,我可以看到以下对象正在返回:

    {
        "loaded": false,
        "coordinates": {
            "lat": "",
            "lng": ""
        },
        "locale": "",
        "countryCode": "",
        "error": {}
    }
    

    这很好,因为 useGeolocation 如果不允许|或拒绝访问,则返回这样的对象。现在,如果我点击“允许”,我希望立即看到以下对象被返回:

    {
        "loaded": true,
        "coordinates": {
            "lat": 28.504016,
            "lng": -82.5510363
        },
        "locale": "en-us",
        "countryCode": "US",
        "error": {}
    }
    

    但是,我必须重新加载页面才能取回值。一旦用户单击“允许”按钮,是否可以实现这一点?

    如果您需要访问代码并使用它,我已经设置了CodeSanbox here

    2 回复  |  直到 1 年前
        1
  •  2
  •   Kaiido NickSlash    1 年前

    PermissionStatus 的状态为 "prompt" ,你应该等它 onchange 事件,以实际了解它是否已经 "granted" "denied"

    因此,您需要修改代码,使其看起来像

    useEffect(() => {
      navigator.permissions
        .query({ name: "geolocation" })
        .then((permissionStatus) => {
          if (permissionStatus.state === "prompt") {
            permissionStatus.onchange = (evt) => {
              setLocationAccess(permissionStatus.state === "granted");
            };
          }
          else { // User has already saved a setting
            setLocationAccess(permissionStatus.state === "granted");
          }
        });
    }, [locationAccess]);
    
        2
  •  1
  •   Vivekajee    1 年前

    解决这一问题的一种方法是将useGeolocation钩子的逻辑移动到主组件的useEffect中,这样它就可以直接监听locationAccess状态的变化。以下是您代码的更新版本:

    import { useEffect, useState } from "react";
    import useGeolocation from "./useGeolocation";
    
    export default function App() {
      const [locationAccess, setLocationAccess] = useState<boolean>(false);
      const [geoLocation, setGeoLocation] = useState({
        loaded: false,
        coordinates: {
          lat: "",
          lng: ""
        },
        locale: "",
        countryCode: "",
        error: {}
      });
    
      useEffect(() => {
        navigator.permissions
          .query({ name: "geolocation" })
          .then((permissionStatus) => {
            setLocationAccess(permissionStatus.state === "granted");
          });
      }, [locationAccess]);
    
      useEffect(() => {
        if (locationAccess) {
          // Call the logic of useGeolocation directly
          navigator.geolocation.getCurrentPosition(
            (position) => {
              setGeoLocation({
                loaded: true,
                coordinates: {
                  lat: position.coords.latitude,
                  lng: position.coords.longitude
                },
                locale: navigator.language,
                countryCode: navigator.language.slice(3).toUpperCase(),
                error: {}
              });
            },
            (error) => {
              setGeoLocation({
                loaded: true,
                coordinates: {
                  lat: "",
                  lng: ""
                },
                locale: "",
                countryCode: "",
                error: error.message
              });
            }
          );
        }
      }, [locationAccess]);
    
      console.log("geoLocation", geoLocation);
    
      return <></>;
    }
    
    

    在这个修改中,获取地理位置的逻辑被移动到主useEffect中,它监听locationAccess状态的变化。这将导致在用户授予权限时立即更新地理位置状态。