1

因为我的应用程序在两个不同的组件中处理移动和桌面视图,所以我需要使用useContext API在它们之间分配状态/道具。

我有一个地图组件,在从移动设备移动到桌面设备时,地图会刷新,反之亦然。

根据有关 React 备忘录的 React 文档:

如果您的组件在给定相同的 props 的情况下呈现相同的结果,您可以将其包装在对 React.memo 的调用中,以便在某些情况下通过记忆结果来提高性能。这意味着 React 将跳过渲染组件,并重用上次渲染的结果。

所以一开始我的想法是“为什么我不记住zoom地图的当前道具?” 因为当一个不同的断点被命中(从移动或桌面和 vv 中)它会导致重新渲染。

但后来我在上一段的正下方读到了这个:

React.memo 仅检查 prop 更改。如果你封装在 React.memo 中的函数组件在其实现中有一个 useState 或 useContext Hook,它仍然会在状态或上下文发生变化时重新渲染。

然而在那之下有这个!

默认情况下,它只会对 props 对象中的复杂对象进行浅层比较。如果要控制比较,还可以提供自定义比较函数作为第二个参数。

此方法仅作为性能优化存在。不要依赖它来“阻止”渲染,因为这可能会导致错误。

所以我还是尝试了它,但首先我使用地图方法获取当前缩放,然后通过useContext本地存储将其保存,因此当一个人进入移动设备或桌面时,至少用户将获得在地图上输入的最后一个缩放。

从桌面到移动

如您所见,有轻微的滞后。

所以这是我的实现: Map 函数:

function currentMapViewPropsAreEqual(prevProps, nextProps) {
  return (
    prevProps.currentMapView === nextProps.currentMapView &&
    prevProps.Map === nextProps.Map &&
    prevProps.TileLayer === nextProps.TileLayer
  );
}

function MyMap({ currentMapView, Map, TileLayer }) {
  var [animate, setAnimate] = useState(false);
  var [userLocation, setUserLocation] = useState(null);
    
  var handleWaypointsOnMapRef = useRef(handleWaypointsOnMap);

  var mapRef = useRef();
  var mapRefForRoutingMachine = useRef();
  var { state } = userState();
  var { dispatch } = userDispatch();
  var {
    currentMap,
    isRoutingVisible,
    removeRoutingMachine,
    isLengthOfMarkersLessThanTwo,
    markers
  } = state;

  useEffect(() => {
    handleWaypointsOnMapRef.current = handleWaypointsOnMap;
  }); // update after each render
    
  function handleOnViewportChanged(e) {
    var { current = {} } = mapRef;
    var { leafletElement: map } = current;

    map.on('zoomend', function() {
      var zoom = map.getZoom();

      dispatch({
        type: 'setMapZoom',
        payload: {
          currentMapView: zoom
        }
      });
    });
  }

  function handleOnLocationFound(e) {
    var { current = {} } = mapRef;
    var { leafletElement: map } = current;
    map.setZoom(currentMapView);

    var latlng = e.latlng;
    var radius = e.accuracy;
    var circle = L.circle(latlng, radius);
    circle.addTo(map);
  }

  return (
    <Map
      preferCanvas={true}
      id="myMap"
      animate={animate}
      zoom={currentMapView}
      ref={mapRef}
      onViewportChanged={handleOnViewportChanged}
      onClick={e => handleWaypointsOnMap(e)}
    >
      <TileLayer
        url={`https://api.mapbox.com/styles/v1/${process.env.MAPBOX_USERNAME}/${
          process.env.MAPBOX_STYLE_ID
        }/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.MAPBOX_ACCESS_TOKEN}`}
        attribution='Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery &copy; <a href="https://www.mapbox.com/">Mapbox</a>'
      />

      {mapRef && (
        <Routing
          isRoutingVisible={isRoutingVisible}
          ref={mapRefForRoutingMachine}
          markers={markers}
          stringify={stringify}
          isLengthOfMarkersLessThanTwo={isLengthOfMarkersLessThanTwo}
          removeRoutingMachine={removeRoutingMachine}
          userLocation={userLocation}
        />
      )}
    </Map>
  );
}

var MemoizedMyMap = React.memo(MyMap, currentMapViewPropsAreEqual);

这是仪表板,所以你可以看到我将实际Map作为道具传递给zoom属性:

import { Map, TileLayer } from 'react-leaflet';

import { userState, userDispatch } from '../components/Context/UserContext.jsx';

const MyMap = dynamic(() => import('../components/Map/MyMap.jsx'), {
  ssr: false
});

var Dashboard = ({ props }) => {
  var { state } = userState();
  var { dispatch } = userDispatch();
  var { currentMapView } = state;
  return (
    <>

              <MyMap Map={Map} TileLayer={TileLayer} currentMapView={currentMapView} />
            
    </>
  );
};

那么有没有人知道如何在遍历移动设备和桌面之间的断点时保持地图道具/状态完好无损。

4

0 回答 0