我对React完全陌生,并试图弄清楚这一点,同时尽可能保持简单。
我有一个名为RestaurantMapWrapper
的包装器功能组件,它应该是:
- 从名为
usePosition
的钩子中获取地理位置数据 - 将经度和纬度数据传递到一个名为
useYelpHook
的钩子中,该钩子使用传入的纬度和经度数据检索餐馆的数据 - 渲染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 };
};
useYelpook的useEffect
在每次组件渲染时运行,并由依赖项触发。您应该将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 }];
}
注意使用Memo和删除initialLoc