首页 > 解决方案 > 如何一次调用一个 API 挂钩?

问题描述

我对 React 完全陌生,并试图弄清楚这一点,同时仍使其尽可能简单。

我有一个名为的包装器功能组件RestaurantMapWrapper,它应该:

  1. 从名为usePosition.
  2. 将经度和纬度数据传递到一个名为 的钩子useYelpHook中,该钩子使用传入的纬度和经度数据检索餐馆数据。
  3. 渲染 yelp 数据(自动,无需用户输入)。

问题是usePosition没有及时获得位置,所以useYelpHook没有什么可处理的。如果我设置pos为默认值,则useYelpHook永远不会再次调用。

如何确保在渲染前useYelpHook等待?usePosition这是否与一个钩子是异步的有关?

export function RestaurantMapWrapper(props) {
    const { latitude, longitude, timestamp, accuracy, error, isLoadingMap } = usePosition();
    const pos = { lat: latitude, lng: longitude }; //ends up being undefined since neither have been retreived yet
    const [{ data, isLoading }, setLoc] = useYelpHook(pos); //is there somewhere I could call setLoc?

    return <div>JSON.stringify({data})</div>;
export const useYelpHook = (initialLoc) => {
    const API_KEY = 'my api key';
    const config = {
        headers: { Authorization: `Bearer ${API_KEY}` },
        params: {
            term: 'food',
            latitude: '0',
            longitude: '0',
            radius: '',
            sort_by: 'rating'
        }
    }

    const [data, setData] = useState({ businesses: [] });
    const [loc, setLoc] = useState(initialLoc);
    const [isLoading, setIsLoading] = useState(true);
 useEffect(() => {
        config.params.latitude = loc.lat;
        config.params.longitude = loc.lng;

        const fetchData = async () => {
            setIsLoading(true);
            const result = await axios(`${'https://cors-anywhere.herokuapp.com/'}https://api.yelp.com/v3/businesses/search`, config);
            setData(result.data);
            setIsLoading(false);
        };

        fetchData();
    }, [loc])

    return [{ data, isLoading }, setLoc];
}
import { useState, useEffect } from 'react';

const defaultSettings = {
    enableHighAccuracy: false,
    timeout: Infinity,
    maximumAge: 0,
};

export const usePosition = (settings = defaultSettings) => {
    const [position, setPosition] = useState({});
    const [error, setError] = useState(null);
    const [isLoadingMap, setIsLoadingMap] = useState(true);

    const onChange = ({ coords, timestamp }) => {
        setPosition({
            latitude: coords.latitude,
            longitude: coords.longitude,
            accuracy: coords.accuracy,
            timestamp,
        });
    };

    const onError = (error) => {
        setError(error.message);
    };

    useEffect(() => {
        setIsLoadingMap(true);
        const geo = navigator.geolocation;
        if (!geo) {
            setError('Geolocation is not supported');
            return;
        }
        geo.getCurrentPosition(onChange, onError, settings);
        setIsLoadingMap(false);

    }, [settings]);

    return { ...position, error, isLoadingMap };
};

标签: reactjsreact-hooks

解决方案


useEffect每次组件呈现并由依赖项触发时,useYelpHook都会运行。您应该将 loc 直接传递到,useYelpHook useEffect而不是保存其初始状态。

export function RestaurantMapWrapper(props) {
    const { latitude, longitude, timestamp, accuracy, error, isLoadingMap } = usePosition();
    const pos = useMemo(() => ({ lat: latitude, lng: longitude }), [latitude, longitude]); //ends up being undefined since neither have been retrieved yet
    const [{ data, isLoading }] = useYelpHook(pos);

    return <div>JSON.stringify({data})</div>;
const API_KEY = 'my api key';
const config = {
    headers: { Authorization: `Bearer ${API_KEY}` },
    params: {
        term: 'food',
        latitude: '0',
        longitude: '0',
        radius: '',
        sort_by: 'rating'
    }
}
export const useYelpHook = (loc) => {


    const [data, setData] = useState({ businesses: [] });
    //const [loc, setLoc] = useState(initialLoc);
    const [isLoading, setIsLoading] = useState(true);
 useEffect(() => {
        /* return if loc is invalid */
        config.params.latitude = loc.lat;
        config.params.longitude = loc.lng;

        const fetchData = async () => {
            setIsLoading(true);
            const result = await axios(`${'https://cors-anywhere.herokuapp.com/'}https://api.yelp.com/v3/businesses/search`, config);
            setData(result.data);
            setIsLoading(false);
        };

        fetchData();
    }, [loc])

    return [{ data, isLoading }];
}

注意 useMemo 和 initialLoc 的删除


推荐阅读