首页 > 解决方案 > 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='&copy; <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='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
              />
            </MapContainer>
        );
    }

}

标签: reactjsreduxreact-reduxleafletreact-leaflet

解决方案


推荐阅读