diff --git a/docs/examples.json b/docs/examples.json index d0392162e..ccaf59dc8 100644 --- a/docs/examples.json +++ b/docs/examples.json @@ -260,6 +260,16 @@ "relPath": "Map/MapAndRNNavigation.js", "name": "MapAndRNNavigation" }, + { + "metadata": { + "title": "Map (un-)mount", + "tags": [], + "docs": "\nShowing and hiding the the map should not lead to increased memory consumption, use this example to check it on the profiler.\n" + }, + "fullPath": "example/src/examples/Map/MapUnMount.tsx", + "relPath": "Map/MapUnMount.tsx", + "name": "MapUnMount" + }, { "metadata": { "title": "Offline Example", diff --git a/example/src/examples/Map/MapUnMount.tsx b/example/src/examples/Map/MapUnMount.tsx new file mode 100644 index 000000000..1d4882181 --- /dev/null +++ b/example/src/examples/Map/MapUnMount.tsx @@ -0,0 +1,51 @@ +import React, { useState, useEffect } from 'react'; +import Mapbox from '@rnmapbox/maps'; +import { Button } from '@rneui/base'; + +import sheet from '../../styles/sheet'; +import { ExampleWithMetadata } from '../common/ExampleMetadata'; // exclude-from-doc + +const MapUnMount = () => { + const [isMounted, setIsMounted] = useState(true); + + useEffect(() => { + Mapbox.locationManager.start(); + + return (): void => { + Mapbox.locationManager.stop(); + }; + }, []); + + return ( + <> + <Button + onPress={() => setIsMounted((mounted) => !mounted)} + title={isMounted ? 'unmount MapView' : 'mount MapView'} + /> + {isMounted ? ( + <Mapbox.MapView + styleURL={Mapbox.StyleURL.Dark} + style={sheet.matchParent} + testID={'show-map'} + > + <Mapbox.Camera followZoomLevel={12} followUserLocation /> + + <Mapbox.UserLocation /> + </Mapbox.MapView> + ) : null} + </> + ); +}; + +export default MapUnMount; + +/* end-example-doc */ + +const metadata: ExampleWithMetadata['metadata'] = { + title: 'Map (un-)mount', + tags: [], + docs: ` +Showing and hiding the the map should not lead to increased memory consumption, use this example to check it on the profiler. +`, +}; +MapUnMount.metadata = metadata; diff --git a/example/src/examples/Map/index.js b/example/src/examples/Map/index.js index 2efafc53f..bb89c7d92 100644 --- a/example/src/examples/Map/index.js +++ b/example/src/examples/Map/index.js @@ -6,6 +6,7 @@ export { default as PointInMapView } from './PointInMapView'; export { default as ShowAndHideLayer } from './ShowAndHideLayer'; export { default as ShowClick } from './ShowClick'; export { default as ShowMap } from './ShowMap'; +export { default as MapUnMount } from './MapUnMount'; export { default as ShowMapLocalStyle } from './ShowMapLocalStyle'; export { default as ShowRegionDidChange } from './ShowRegionDidChange'; export { default as SourceLayerVisibility } from './SourceLayerVisibility'; diff --git a/ios/RNMBX/RNMBXMapView.swift b/ios/RNMBX/RNMBXMapView.swift index 34248c843..5aa9db7d4 100644 --- a/ios/RNMBX/RNMBXMapView.swift +++ b/ios/RNMBX/RNMBXMapView.swift @@ -154,7 +154,23 @@ class RNMBXCameraChanged : RNMBXEvent, RCTEvent { } @objc(RNMBXMapView) -open class RNMBXMapView: UIView { +open class RNMBXMapView: UIView, RCTInvalidating { + + public func invalidate() { + self.removeAllFeaturesFromMap(reason: .ViewRemoval) + +#if RNMBX_11 + cancelables.forEach { $0.cancel() } + cancelables.removeAll() +#endif + + _mapView.gestures.delegate = nil + _mapView.removeFromSuperview() + _mapView = nil + + self.removeFromSuperview() + } + var imageManager: ImageManager = ImageManager() var tapDelegate: IgnoreRNMBXMakerViewGestureDelegate? = nil