我正在建立一个与反应,TS,Mapbox,反应-mapbox-gl和RecoilJS的应用程序。
这是我正在使用的Dashboard组件:
import React from "react";
import PageTemplate from "../../components/PageTemplate/PageTemplate";
import ReactMapboxGl from "react-mapbox-gl";
import { CGOIncidentsMapConfig } from "./Map/CGOIncidents";
import { zoomSuscriberState, clickSuscriberState } from "../../contexts/MapContext";
import { useRecoilValue } from "recoil";
import { MapEvent } from "react-mapbox-gl/lib/map-events";
const Map = ReactMapboxGl({
accessToken: process.env.REACT_APP_MAPBOX_TOKEN ?? "",
});
const getEventHandle: (subscribers: MapEvent[]) => MapEvent = (subscribers) => (map, evt) => {
console.log(subscribers);
for (const event of subscribers) {
event(map, evt);
}
};
const Dashboard: React.FC = () => {
const zoomSuscribers = useRecoilValue(zoomSuscriberState);
const clickSuscribers = useRecoilValue(clickSuscriberState);
console.log(zoomSuscribers);
console.log(clickSuscribers);
return (
<PageTemplate>
<Map
style="mapbox://styles/mapbox/light-v10"
containerStyle={{
height: "100%",
width: "100%",
}}
center={[-3.7, 40.44]}
zoom={[5]}
onZoom={getEventHandle(zoomSuscribers)}
onClick={getEventHandle(clickSuscribers)}
>
<CGOIncidentsMapConfig />
</Map>
</PageTemplate>
);
};
export default Dashboard;这是简化的CGOIncidentsMapConfig组件:
export const CGOIncidentsMapConfig: React.FC = () => {
const [popupCoordinates, setPopupCoordinates] = useState<number[]>([-0.13235092163085938, 51.518250335096376]);
const [isPopupVisible, setPopupVisible] = useState<boolean>(false);
const [popopContainer, setPopupContainer] = useState("");
const [leyend, setLeyend] = useState<{
title: string;
elements: {
title: string;
color: string;
}[];
}>(LEYENDS.PROVINCES);
const onZoomMapEvent: MapEvent = (map) => {
console.log("ZIIIM", map.getZoom());
};
const onMouseEnterEvent = (e: MapLayerMouseEvent) => {
const map = e.target;
map.getCanvas().style.cursor = "pointer";
};
const onMouseLeaveEvent = (e: MapLayerMouseEvent) => {
const map = e.target;
map.getCanvas().style.cursor = "";
};
const dismissPopup = () => {
setPopupVisible(false);
console.log("CIIM");
};
const setZoomSuscribers = useSetRecoilState(zoomSuscriberState);
const setClickSuscribers = useSetRecoilState(clickSuscriberState);
useEffect(() => {
setZoomSuscribers((oldZoomSubscribers) => [...oldZoomSubscribers, onZoomMapEvent]);
setClickSuscribers((oldClickSubscribers) => [...oldClickSubscribers, dismissPopup]);
console.log("updated recoil");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
console.log(isPopupVisible);
return (
<Fragment>
<Source id={CGO_INCIDENTS_SOURCE_ID} tileJsonSource={CGO_INCIDENTS_SOURCE_OPTIONS} />
<Layer
id={CGO_INCIDENTS_LAYER_LAYOUT.id}
type={CGO_INCIDENTS_LAYER_LAYOUT.type}
sourceId={CGO_INCIDENTS_LAYER_LAYOUT.source}
sourceLayer={CGO_INCIDENTS_LAYER_LAYOUT["source-layer"]}
paint={CGO_INCIDENTS_LAYER_LAYOUT.paint}
onClick={onClickEvent}
onMouseEnter={onMouseEnterEvent}
onMouseLeave={onMouseLeaveEvent}
/>
{isPopupVisible && (
<Popup coordinates={popupCoordinates} onClick={dismissPopup}>
{popopContainer}
</Popup>
)}
<Leyend title={leyend.title} elements={leyend.elements} />
</Fragment>
);
};这是我的MapContext文件,我在其中创建原子:
import { MapEvent } from "react-mapbox-gl/lib/map-events";
import { atom } from "recoil";
export const zoomSuscriberState = atom<MapEvent[]>({ key: "zoomSuscriberState", default: [] });
export const clickSuscriberState = atom<MapEvent[]>({ key: "clickSuscriberState", default: [] });正如您所看到的,我想要做的只是使用RecoilJS为onClick和onZoom事件创建一个订阅者模式。我的想法是将每个Mapbox层分离到不同的组件中。
当执行getEventHandler返回的函数时,内部的console.log只为zoomSuscribers或clickSuscribers显示一个空数组,但我在Dashboard组件的console.log中看到的是,这两个原子都有一个由CGOIncidentsMapConfig组件解决的回调函数。这些原子在第一次呈现Dashboard时为空,并在呈现CGOIncidentsMapConfig组件后实现。看起来RecoilJS像预期的那样同时更新了atoms和Dashboard组件。
为什么getEventHandler函数中的console.log只打印一个空数组?因此,订阅者不能正确地执行事件。
提前谢谢。
发布于 2021-05-18 22:37:48
这是因为您调用的是getEventHandle函数,而不是将其传递给Map组件。
更改以下行:
onZoom={getEventHandle(zoomSuscribers)}
onClick={getEventHandle(clickSuscribers)}至
onZoom={() => getEventHandle(zoomSuscribers)}
onClick={() => getEventHandle(clickSuscribers)}发布于 2021-05-19 19:17:34
我解决了!
使用useRecoilCallback解决方案
import React from "react";
import PageTemplate from "../../components/PageTemplate/PageTemplate";
import ReactMapboxGl from "react-mapbox-gl";
import { CGOIncidentsMapConfig } from "./Map/CGOIncidents";
import { zoomSuscriberState, clickSuscriberState } from "../../contexts/MapContext";
import { useRecoilCallback, useRecoilValue } from "recoil";
import { MapEvent } from "react-mapbox-gl/lib/map-events";
const Map = ReactMapboxGl({
accessToken: process.env.REACT_APP_MAPBOX_TOKEN ?? "",
});
const Dashboard: React.FC = () => {
const onZoom: MapEvent = useRecoilCallback(({ snapshot }) => async (map, evt) => {
const subs = await snapshot.getPromise(zoomSuscriberState);
for (const event of subs) {
event(map, evt);
}
});
const onClick: MapEvent = useRecoilCallback(({ snapshot }) => async (map, evt) => {
const subs = await snapshot.getPromise(clickSuscriberState);
for (const event of subs) {
event(map, evt);
}
});
return (
<PageTemplate>
<Map
style="mapbox://styles/mapbox/light-v10"
containerStyle={{
height: "100%",
width: "100%",
}}
center={[-3.7, 40.44]}
zoom={[5]}
onZoom={onZoom}
onClick={onClick}
>
<CGOIncidentsMapConfig />
</Map>
</PageTemplate>
);
};
export default Dashboard;https://stackoverflow.com/questions/67583005
复制相似问题