reactjs - React Redux 如何在平移时加载地图标记而不重新渲染所有内容?
问题描述
我正在使用 react + redux 和 react-leaflet v3 + API 来加载标记以根据平移行为动态地固定在地图上。
我有它以便触发“dragend”事件并计算地图边界、缩放级别和中心,以便创建适当的参数以输入 API 端点。这样,当用户平移地图时,标记会被动态输入。
标记数据保存在 redux 存储中,API 调用通过 useEffect 监听端点变化触发。
问题是似乎所有标记在每个平移时都重新渲染,这使得应用程序变得紧张和缓慢。我希望它只渲染新标记并且不重新渲染旧标记。此外,应该简单地删除边界之外的旧标记。然而,事实并非如此。我认为只要标记有一个键,react-redux 就能够将旧数据与新数据进行比较,并且只渲染新组件。
我的标记加载是通过 createAyncThunk 完成的,如下所示:
export const getCities = createAsyncThunk("markers/getCities", async (endpoint, thunkAPI) => {
try {
const response = await axios.get(endpoint);
return response.data;
} catch (error) {
return thunkAPI.rejectWithValue({ error: error.message });
}
});
使用以下切片:
// CREATE SLICE
const markerSlice = createSlice({
name: "markers",
initialState: {
cities: [],
markerType: "cities",
endpoint: "/api/get/cities",
},
reducers: {
// some reducer code
},
extraReducers: (builder) => {
builder.addCase(getCities.pending, (state) => {
state.cities = [];
});
builder.addCase(getCities.fulfilled, (state, { payload }) => {
state.cities = payload;
});
builder.addCase(getCities.rejected,(state, action) => {
state.loading = "error";
});
}
});
我的 Map 组件是这样的(为便于阅读而简化):
import React, { useEffect } from "react";
import { MapContainer, Marker, Popup, TileLayer, useMap, useMapEvents } from "react-leaflet";
import "../../css/app.css";
import { useSelector, useDispatch, batch } from "react-redux";
import { getCities, setEndpoint } from "../features/markerSlice";
import { setLatBnd, setLngBnd, setZoom, setLat, setLng } from "../features/mapSlice";
export const LeafMap = () => {
const dispatch = useDispatch();
//marker state (marker data)
const stateMarker = useSelector(state => state.marker);
// map state (center, zoom level, bounds, etc)
const stateMap = useSelector(state => state.map);
// This calls the API to retrieve data
useEffect(() => {
dispatch(getCities(stateMarker.endpoint));
}, [stateMarker.endpoint]);
// Custom Marker Component to render markers
const GetMarkers = () => {
const markerType = stateMarker.markerType;
return stateMarker.cities.map((el, i) => (
<Marker
key={i}
position={[el.latitude, el.longitude]}
>
</Marker>
));
};
// This is a child component to MapContainer (leaflet v3) which listens to map events
function GetMapProperties() {
const map = useMap();
// listen to drag event end
useMapEvents({
dragend: () => {
// Get map info in order to create endpoint parameters for API call
const bounds = map.getBounds();
const latBnd = bounds['_northEast'].lat
const lngBnd = bounds['_northEast'].lng
const zoom = map.getZoom();
const lat = map.getCenter().lat;
const lng = map.getCenter().lng;
// update endpoint which triggers API call (via useEffect on top)
dispatch(setEndpoint({type:"trees", lat:lat, lng:lng, latbnd:latBnd, lngbnd:lngBnd}))
},
});
// render component based on if there is available data
if (stateMarker.cities.length > 0) {
return (
<MapContainer preferCanvas={true} center={[stateMap.lat, stateMap.lng]} zoom={stateMap.zoom} scrollWheelZoom={true}>
<GetMapProperties />
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<GetMarkers />
</MapContainer>
);
} else {
return (
<MapContainer center={[stateMap.lat, stateMap.lng]} zoom={stateMap.zoom} scrollWheelZoom={true}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>
);
}
}
解决方案
推荐阅读
- visual-studio-code - VS 代码 | 新窗口选择语言
- sql - 如何在 SQL where 子句中使用 case 函数?
- android - 潜在的 Firestore 离线获取数据错误
- kubernetes - Kubernetes“索引作业”不起作用
- django - 在 Django 中对 Field 类型进行模型范围的验证,即验证模型的所有 DecimalField 是否大于 0
- sql - SQL 查询计数具有相同条目的行
- go - 对为什么 hashsum、encode、print 与 Go 中的 write、hashum、encode、print 不同感到困惑?
- sql - 我可以将我的 SQL 代码(查询)作为 .sql 文档导出到我的计算机吗?
- javascript - 未捕获的 TypeError:work.filter 不是函数
- reactjs - 从一个选项卡导航到另一个具有抽屉和另一个屏幕的选项卡时,如何在反应导航中保持“返回”功能