React Hooks-调用依赖于“一次” useEffect的状态的函数的最佳位置?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Hooks-调用依赖于“一次” useEffect的状态的函数的最佳位置?相关的知识,希望对你有一定的参考价值。
我正在尝试使用React Hooks实现Google地图,而不使用任何第三方库。我编写了允许生成脚本的代码,该脚本使用url如下所示获取Google地图。但是我不知道调用此脚本生成函数(在我们的情况下为createScriptLoadMap()
)的正确方法是什么,因为在仅被调用一次的useEffect
中调用它似乎给我一个错误:
You have included the Google Maps javascript API multiple times on this page. This may cause unexpected errors.
我想知道为什么会收到此错误以及如何解决。这是一个stackblitz链接,在该链接中,我尽力为自己的情况编写了最少的代码:
https://stackblitz.com/edit/react-hsl4dn?file=Hello.js
编辑:我也在useEffect
处进行获取请求,因此它必须是“一次” useEffect
,但我也必须一次调用createScriptLoadMap()
,此功能取决于useEffect
设置的状态不会立即生效!
是否有发生获取请求,设置mapCenter
然后执行createScriptLoadMap()
的方式?
您的useEffect
钩子仅执行一次。您最有可能收到该消息,是因为热重新加载并重新安装了Map
组件。
为了避免这种情况,只需使用您设置为window.initMap
的window属性来检查是否加载了地图脚本:
const createScriptLoadMap = () => {
if (!window.initMap) {
var index = window.document.getElementsByTagName("script")[0];
var script = window.document.createElement("script");
script.src =
"https://maps.googleapis.com/maps/api/js?key=AIzaSyDurZQBXjtSzKeieXwtFeGe-jhZu-HEGQU&libraries=drawing&callback=initMap";
script.async = true;
script.defer = true;
index.parentNode.insertBefore(script, index);
window.initMap = true;
}
};
编辑
关于在获取某些数据后如何使地图居中,还应该使用钩子和useEffect
,因为您已经具有mapCenter
状态对象。首先使用script.load
查看何时加载脚本。调用是否加载脚本的initMap
以获取google.maps.Map
对象,并保存状态以供以后使用,如果脚本已经加载,则只需分配地图对象即可。
const createScriptLoadMap = () => {
if (!window.initMap) {
var index = window.document.getElementsByTagName("script")[0];
var script = window.document.createElement("script");
script.src =
"https://maps.googleapis.com/maps/api/js?key=AIzaSyDurZQBXjtSzKeieXwtFeGe-jhZu-HEGQU&libraries=drawing&callback=initMap";
script.async = true;
script.defer = true;
script.onload = () => {
initMap();
};
index.parentNode.insertBefore(script, index);
window.initMap = true;
} else {
initMap();
}
};
然后更改initMap
函数以将google.maps.Map
对象初始化或分配给DOM #map
元素(如果我们之前已经分配了元素,则不会创建新映射):
const initMap = () => {
let googleMap = new google.maps.Map(document.getElementById("map"), {
center: { lat: 37.978534, lng: 23.743830 }, //CURRENTLY STATIC
//center: {mapCenter} //ACTUAL
zoom: 14
});
// Save the map object created for later usage
setMap(googleMap);
// axios.get(`${BASE_URL_LOCAL}/outlet/list?page=1&limit=50`).then(res => {
// let center = averageGeolocation(res.data.data.outlets);
// console.log(props.mapCenter);
// setFetchedData(res);
// setMapCenter(center) //THIS CENTER IS REQUIRED IN LINE 22
// });
// Suppose get get axios reequest after 2 seconds
setTimeout(() => {
// Center map at NY Brooklyn using state (effect for mapCenter will be triggered)
setMapCenter({ lat: 40.674282, lng: -73.943060 });
}, 2000);
};
将创建一个google.aps.Map
对象,并使用setMap
状态保存以供以后使用。现在,只要您想更新地图的中心(或任何其他地图属性/方法),只需将useEffect
钩子设置为mapCenter
状态对象,然后使用map
对象来更改地图:
const [mapCenter, setMapCenter] = useState({});
const [fetchedData, setFetchedData] = useState({});
const [map, setMap] = useState();
useEffect(() => {
createScriptLoadMap();
}, []);
useEffect(() => {
if(map) {
map.setCenter(mapCenter)
}
}, [mapCenter]);
检查我的分叉和更新的stackblitz
。您会看到地图从雅典开始,经过2秒钟的延迟(假设我们有一个异步Axios呼叫),它将地图居中到纽约布鲁克林。 (我创建了我的Google Maps API密钥用于演示,在您回复后我将其删除)。
stackblitz
在这种情况下,挂钩无法帮助您。即使从useEffect返回https://stackblitz.com/edit/react-ohtdra?file=Hello.js并从clean-up function中删除element
。因为此脚本在head
(类似样式)中创建了大量其他元素,仅删除一个元素将无济于事。
我需要说的是,在不引入React的情况下做事是不正确的,但是如果需要的话,可以。例如。在脚本标签中添加一些内容,然后再次选择此项,然后跳过head
。像这样:
createScriptLoadMap
以上是关于React Hooks-调用依赖于“一次” useEffect的状态的函数的最佳位置?的主要内容,如果未能解决你的问题,请参考以下文章
[React + GraphQL] Use useLazyQuery to manually execute a query with Apollo React Hooks