【问题标题】:Catch block isn't catching the error thrown in my custom react hookCatch 块没有捕捉到我的自定义反应钩子中抛出的错误
【发布时间】:2020-12-21 23:21:04
【问题描述】:

我有一个使用用户位置的应用。使用 Expo 的位置库,这就是我的代码的结构。

在主屏幕中,我创建了一个回调函数并包含在 useCallback HOC 中。

const userLocationCallback = useCallback(async (location) => {
    // if we don't have any locations....fetch them and then sort them
    if (!businessLocations || businessLocations.length <= 0) {
        // todo check for wifi connectivity or data
        let fetchedLocations = await fetchAllLocations();
        sortByClosestLocation(location, fetchedLocations, updateLocations)
        if (fetchedLocations.length >= 5) {
            setListOfClosest(getFirstFromList(5, businessLocations))
        }
    } else {
        sortByClosestLocation(location, businessLocations, updateLocations)
        if (businessLocations.length >= 5) {
            setListOfClosest(getFirstFromList(5, businessLocations))
        }
    }
}, [businessLocations, locationServicesOn, permissionGranted]);

每次更新时都会使用用户的位置调用此代码。这段代码中唯一真正重要的部分是对 await fetchAllLocations 的调用。这是对返回 JSON 的服务器的 api 调用。

这是自定义钩子的代码:

export default (
    shouldTrackLocation,
    timeBetweenUpdates,
    callback,
    locationServicesOn,
    permissionGranted) => {

    const [locationError, setLocationError] = useState(null);

    let time = 0;

    useEffect(() => {

        let subscriber;
        const startWatching = async () => {
            try {
                subscriber = await watchPositionAsync({
                        accuracy: Accuracy.BestForNavigation,
                        // timeInterval and distanceInterval seem to have no effect, but you must have distanceInterval === 0
                        timeInterval: 10000,
                        distanceInterval: 0
                    }, (location) => {
                        if (time === 0 || new Date().getTime() >= time + timeBetweenUpdates) {

                            callback(location).catch(e => {
                                console.log("Location Error: ", "caught the error here")
                                throw e;
                            });
                            time = new Date().getTime();
                        }
                    }
                );
            } catch (e) {
                console.log("Location Error: ", "caught error in catch block")
                setLocationError(e);
            }
        };

        if (shouldTrackLocation && locationServicesOn && permissionGranted) {
            startWatching().catch(err => {
                console.log(err);
                subscriber?.remove();
                subscriber = null
            })
        } else {
            subscriber?.remove();
            subscriber = null;
        }

        return () => {
            subscriber?.remove();
        }
    }, [shouldTrackLocation, callback, locationServicesOn, permissionGranted]);

    return [locationError];
} 

我定义了一个函数startWatching,它使用了expo-location的函数watchPositionAsync。此处相关的代码部分是回调函数(传递给 watchPositionAsync 的第二个参数)。回调函数是我在顶部显示的代码——我在 useCallback 中包装的代码。从主屏幕(定义回调函数的地方)我这样调用钩子:

const [locationError] = useCurrentLocation(
        screenIsFocused,
        3000,
        userLocationCallback,
        locationServicesOn,
        permissionGranted,
    );

这就是问题所在。如果回调函数产生错误,我想捕捉它。但是,我正在进行 api 调用,如果服务器关闭并且回调由于它关闭而引发错误,那么为什么它没有显示在 startWatching 函数的 catch 块中?

如您所见,我尝试通过将 .catch(e => ....) 附加到调用末尾来立即捕获它。那行得通,但是当我在该块内抛出错误时,它永远不会碰到我试图调用setLocationError(e)的下面的catch块。

我似乎无法理解我的错误流程。如果应用程序无法连接到服务器,我想做点什么。帮助我理解为什么会跳过 catch 块。

【问题讨论】:

  • 那么,您基本上是在问,如果出现网络错误或其他情况,您如何处理服务器端可能发生的错误?
  • 不,我正在尝试处理客户端上的错误。如果服务器关闭,获取数据的 api 调用将失败,因为客户端将无法连接到服务器。如果我在我创建的 startWatching 函数中添加 callback(location).catch(e => console.log(e)) ,我能够在发生这种情况时捕获错误。但该错误永远不会传播到后续的 catch 块。
  • 好的,同样的事情。我会为你的情况添加一个答案

标签: react-native error-handling async-await react-hooks


【解决方案1】:

对于您的具体情况,您可以修改您的自定义,如下所示:

  export default (
        shouldTrackLocation,
        timeBetweenUpdates,
        callback,
        locationServicesOn,
        permissionGranted) => {
    
        const [locationError, setLocationError] = useState(null);
    
        let time = 0;
    
        const innerLocationCallback = useCallback(async (location) => {       
            try {
                if (time === 0 || new Date().getTime() >= time + timeBetweenUpdates) {
                    callback(location);
                    time = new Date().getTime();
                }
            }
            catch (e) {
                setLocationError(e);
            }
        }, []);
    
    
        useEffect(() => {
            let subscriber;
            const startWatching = async () => {
                try {
                    subscriber = await watchPositionAsync({
                            accuracy: Accuracy.BestForNavigation,
                            timeInterval: 10000,
                            distanceInterval: 0
                        }, innerLocationCallback
                    );
                } catch (e) {
                    console.log("Location Error: ", "caught error in catch block")
                    setLocationError(e);
                }
            };
    
            if (shouldTrackLocation && locationServicesOn && permissionGranted) {
                startWatching().catch(err => {
                    console.log(err);
                    subscriber?.remove();
                    subscriber = null
                })
            } else {
                subscriber?.remove();
                subscriber = null;
            }
    
            return () => {
                subscriber?.remove();
            }
        }, [shouldTrackLocation, callback, locationServicesOn, permissionGranted]);
    
        return [locationError];
    }

我不想提前对您的代码进行重大更改,因为它有点过于复杂。 但就我个人而言,我不会这样称呼我的外部回调。如果这对你有用,我可以稍后改进我的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-02
    • 2021-07-25
    • 1970-01-01
    • 2016-01-26
    相关资源
    最近更新 更多