创建一个Reactive UsePosition()挂钩以获取和跟踪浏览器坐标

图片


如果简短


在本文中,我们将创建一个usePosition()反应性挂钩来跟踪浏览器的地理位置。 在watchPosition() ,此钩子将使用本机浏览器对象navigator.geolocationgetCurrentPosition()watchPosition()方法。 我在GitHubNPM 发布了该钩子的最终版本。


为什么原则上创建usePosition()钩子


React中钩子的重要优点之一是能够在一个位置(在钩子中)隔离逻辑相关的代码片段,同时避免了例如在componentDidMount()方法中混合逻辑上不相关的代码片段的需要。


假设我们要获取浏览器坐标( latitudelongitude ),并在接收到坐标后,从第三方服务请求天气预报或该区域的当前温度。 React中的这两个功能(获取坐标和请求温度)的代码通常放在一个componentDidMount()方法中。 在这种情况下,通常会自行“清除” componentWillUnmount()方法,调用clearWatch()方法停止监视浏览器位置。 这种方法增加了方法的规模,将代码的逻辑连接部分分成多个部分(分别订阅和取消订阅,以监视浏览器的位置),并将代码的逻辑弱连接部分组合为一种方法(获取坐标和温度)。 读取代码非常困难,调试和支持也很困难。


接下来,我们将尝试将与获取浏览器坐标相关的功能转移到单独的usePosition()挂钩中,以避免上面列出的困难。


我们将如何使用usePosition()挂钩


让我们“相反”,在实现钩子本身之前,让我们计划一下如何使用它。 这将帮助我们确定钩子接口(它将接受什么以及返回什么)。


获取坐标并将其显示在屏幕上的最简单示例如下所示:


 import React from 'react'; //    . import { usePosition } from './usePosition'; export const UsePositionDemo = () => { //    ( ) . const { latitude, longitude, error } = usePosition(); //       (   ). return ( <> latitude: {latitude}, longitude: {longitude}, error: {error} </> ); }; 

使用usePosition()钩子仅需一行,我们就可以使用longitude坐标进行操作。 这里甚至没有显式使用过useState()useEffect()挂钩。 跟踪坐标的订阅以及删除订阅者都封装在一个usePosition()挂钩中。 此外,重绘React组件的魔力将为我们做一切。 开始时,坐标将为nullundefined 。 一旦收到坐标,组件将被重绘,我们将在屏幕上看到它们。


usePosition()实现usePosition()


我们的usePosition()挂钩是一个常规的JavaScript函数,如下所示:


 //  . export const usePosition = () => { //    . } 

我们将使用useState()挂钩来内部存储坐标,并使用useEffect()来订阅和取消订阅跟踪坐标。 为此,我们必须导入它们。


 import { useState, useEffect } from 'react'; export const usePosition = () => { //     . } 

我们将创建状态变量,其中将存储坐标或获取坐标时出错(例如,如果用户拒绝共享其位置)。


 import { useState, useEffect } from 'react'; export const usePosition = () => { const [position, setPosition] = useState({}); const [error, setError] = useState(null); //  ... } 

同样在此阶段,我们可以返回挂钩中期望的变量。 到目前为止,这些变量没有什么用,但是我们会尽快修复。


 import { useState, useEffect } from 'react'; export const usePosition = () => { const [position, setPosition] = useState({}); const [error, setError] = useState(null); // other code goes here... return { ...position, error }; } 

现在,实现的关键时刻就是获得坐标。


 import { useState, useEffect } from 'react'; export const usePosition = () => { const [position, setPosition] = useState({}); const [error, setError] = useState(null); //     ,    .. useEffect(() => { const geo = navigator.geolocation; if (!geo) { setError('   '); return; } //     . watcher = geo.watchPosition(onChange, onError); //  ,       //    ,    . return () => geo.clearWatch(watcher); }, []); return {...position, error}; } 

useEffect()挂钩中,我们首先检查浏览器是否支持坐标检测功能。 如果不支持该功能,我们将退出并显示错误。 否则,我们订阅使用onChange onChange()onError()更改浏览器的地理位置(我们将在下面添加其代码)。 请注意,从useEffect()挂钩中,我们返回一个匿名函数,如果该组件从显示中删除,该函数将被执行。 在此匿名功能中,我们取消订阅监视,以免阻塞内存。 因此,订阅和取消订阅跟踪的整个逻辑都在一个usePosition()挂钩中。


让我们添加缺少的回调:


 import { useState, useEffect } from 'react'; export const usePosition = () => { const [position, setPosition] = useState({}); const [error, setError] = useState(null); const onChange = ({latitude, longitude}) => { //        position,   //    ,    . setPosition({latitude, longitude}); }; const onError = (error) => { setError(error.message); }; useEffect(() => { const geo = navigator.geolocation; if (!geo) { setError('   '); return; } //     . watcher = geo.watchPosition(onChange, onError); //  ,       //    ,    . return () => geo.clearWatch(watcher); }, []); return {...position, error}; } 

usePosition()挂钩可以使用了。


最后


您可以找到该钩子及其更详细实现的演示,并能够在GitHub上设置跟踪参数。


希望本文对您有所帮助。 编码成功!

Source: https://habr.com/ru/post/zh-CN458614/


All Articles