This is an automated email from the ASF dual-hosted git repository.

kgabryje pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 09e9cb484b chore: Convert deckgl class components to functional 
(#25177)
09e9cb484b is described below

commit 09e9cb484b7bf411f19bbf4f5f0feb24e406a46e
Author: Kamil Gabryjelski <[email protected]>
AuthorDate: Thu Sep 7 13:28:09 2023 +0200

    chore: Convert deckgl class components to functional (#25177)
---
 .../src/CategoricalDeckGLContainer.tsx             | 266 +++++++++------------
 .../src/DeckGLContainer.tsx                        | 131 +++++-----
 .../legacy-preset-chart-deckgl/src/Multi/Multi.tsx | 204 +++++++---------
 .../legacy-preset-chart-deckgl/src/TooltipRow.tsx  |  18 +-
 .../legacy-preset-chart-deckgl/src/factory.tsx     | 113 ++++-----
 .../src/layers/Geojson/Geojson.tsx                 |  65 ++---
 .../src/layers/Polygon/Polygon.tsx                 | 237 +++++++++---------
 .../src/layers/Screengrid/Screengrid.tsx           | 118 ++++-----
 8 files changed, 518 insertions(+), 634 deletions(-)

diff --git 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/CategoricalDeckGLContainer.tsx
 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/CategoricalDeckGLContainer.tsx
index 4348bf1561..fb150445f4 100644
--- 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/CategoricalDeckGLContainer.tsx
+++ 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/CategoricalDeckGLContainer.tsx
@@ -24,7 +24,7 @@
  */
 /* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */
 
-import React from 'react';
+import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
 import {
   CategoricalColorNamespace,
   Datasource,
@@ -40,7 +40,7 @@ import sandboxedEval from './utils/sandbox';
 // eslint-disable-next-line import/extensions
 import fitViewport, { Viewport } from './utils/fitViewport';
 import {
-  DeckGLContainer,
+  DeckGLContainerHandle,
   DeckGLContainerStyledWrapper,
 } from './DeckGLContainer';
 import { Point } from './types';
@@ -83,82 +83,72 @@ export type CategoricalDeckGLContainerProps = {
   setControlValue: (control: string, value: JsonValue) => void;
 };
 
-export type CategoricalDeckGLContainerState = {
-  formData?: QueryFormData;
-  viewport: Viewport;
-  categories: JsonObject;
-};
-
-export default class CategoricalDeckGLContainer extends React.PureComponent<
-  CategoricalDeckGLContainerProps,
-  CategoricalDeckGLContainerState
-> {
-  containerRef = React.createRef<DeckGLContainer>();
-
-  /*
-   * A Deck.gl container that handles categories.
-   *
-   * The container will have an interactive legend, populated from the
-   * categories present in the data.
-   */
-  constructor(props: CategoricalDeckGLContainerProps) {
-    super(props);
-    this.state = this.getStateFromProps(props);
-
-    this.getLayers = this.getLayers.bind(this);
-    this.toggleCategory = this.toggleCategory.bind(this);
-    this.showSingleCategory = this.showSingleCategory.bind(this);
-  }
-
-  UNSAFE_componentWillReceiveProps(nextProps: CategoricalDeckGLContainerProps) 
{
-    if (nextProps.payload.form_data !== this.state.formData) {
-      this.setState({ ...this.getStateFromProps(nextProps) });
-    }
-  }
+const CategoricalDeckGLContainer = (props: CategoricalDeckGLContainerProps) => 
{
+  const containerRef = useRef<DeckGLContainerHandle>(null);
 
-  // eslint-disable-next-line class-methods-use-this
-  getStateFromProps(
-    props: CategoricalDeckGLContainerProps,
-    state?: CategoricalDeckGLContainerState,
-  ) {
-    const features = props.payload.data.features || [];
-    const categories = getCategories(props.formData, features);
-
-    // the state is computed only from the payload; if it hasn't changed, do
-    // not recompute state since this would reset selections and/or the play
-    // slider position due to changes in form controls
-    if (state && props.payload.form_data === state.formData) {
-      return { ...state, categories };
-    }
-
-    const { width, height, formData } = props;
-    let { viewport } = props;
-    if (formData.autozoom) {
+  const getAdjustedViewport = useCallback(() => {
+    let viewport = { ...props.viewport };
+    if (props.formData.autozoom) {
       viewport = fitViewport(viewport, {
-        width,
-        height,
-        points: props.getPoints(features),
+        width: props.width,
+        height: props.height,
+        points: props.getPoints(props.payload.data.features || []),
       });
     }
     if (viewport.zoom < 0) {
       viewport.zoom = 0;
     }
+    return viewport;
+  }, [props]);
+
+  const [categories, setCategories] = useState<JsonObject>(
+    getCategories(props.formData, props.payload.data.features || []),
+  );
+  const [stateFormData, setStateFormData] = useState<JsonObject>(
+    props.payload.form_data,
+  );
+  const [viewport, setViewport] = useState(getAdjustedViewport());
+
+  useEffect(() => {
+    if (props.payload.form_data !== stateFormData) {
+      const features = props.payload.data.features || [];
+      const categories = getCategories(props.formData, features);
+
+      setViewport(getAdjustedViewport());
+      setStateFormData(props.payload.form_data);
+      setCategories(categories);
+    }
+  }, [getAdjustedViewport, props, stateFormData]);
 
-    return {
-      viewport,
-      selected: [],
-      lastClick: 0,
-      formData: props.payload.form_data,
-      categories,
-    };
-  }
+  const setTooltip = useCallback((tooltip: TooltipProps['tooltip']) => {
+    const { current } = containerRef;
+    if (current) {
+      current.setTooltip(tooltip);
+    }
+  }, []);
+
+  const addColor = useCallback((data: JsonObject[], fd: QueryFormData) => {
+    const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
+    const colorFn = getScale(fd.color_scheme);
+
+    return data.map(d => {
+      let color;
+      if (fd.dimension) {
+        color = hexToRGB(colorFn(d.cat_color, fd.sliceId), c.a * 255);
+
+        return { ...d, color };
+      }
+
+      return d;
+    });
+  }, []);
 
-  getLayers() {
-    const { getLayer, payload, formData: fd, onAddFilter } = this.props;
+  const getLayers = useCallback(() => {
+    const { getLayer, payload, formData: fd, onAddFilter } = props;
     let features = payload.data.features ? [...payload.data.features] : [];
 
     // Add colors from categories or fixed color
-    features = this.addColor(features, fd);
+    features = addColor(features, fd);
 
     // Apply user defined data mutator if defined
     if (fd.js_data_mutator) {
@@ -167,9 +157,8 @@ export default class CategoricalDeckGLContainer extends 
React.PureComponent<
     }
 
     // Show only categories selected in the legend
-    const cats = this.state.categories;
     if (fd.dimension) {
-      features = features.filter(d => cats[d.cat_color]?.enabled);
+      features = features.filter(d => categories[d.cat_color]?.enabled);
     }
 
     const filteredPayload = {
@@ -182,88 +171,69 @@ export default class CategoricalDeckGLContainer extends 
React.PureComponent<
         fd,
         filteredPayload,
         onAddFilter,
-        this.setTooltip,
-        this.props.datasource,
+        setTooltip,
+        props.datasource,
       ) as Layer,
     ];
-  }
-
-  // eslint-disable-next-line class-methods-use-this
-  addColor(data: JsonObject[], fd: QueryFormData) {
-    const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
-    const colorFn = getScale(fd.color_scheme);
-
-    return data.map(d => {
-      let color;
-      if (fd.dimension) {
-        color = hexToRGB(colorFn(d.cat_color, fd.sliceId), c.a * 255);
-
-        return { ...d, color };
+  }, [addColor, categories, props, setTooltip]);
+
+  const toggleCategory = useCallback(
+    (category: string) => {
+      const categoryState = categories[category];
+      const categoriesExtended = {
+        ...categories,
+        [category]: {
+          ...categoryState,
+          enabled: !categoryState.enabled,
+        },
+      };
+
+      // if all categories are disabled, enable all -- similar to nvd3
+      if (Object.values(categoriesExtended).every(v => !v.enabled)) {
+        /* eslint-disable no-param-reassign */
+        Object.values(categoriesExtended).forEach(v => {
+          v.enabled = true;
+        });
       }
-
-      return d;
-    });
-  }
-
-  toggleCategory(category: string) {
-    const categoryState = this.state.categories[category];
-    const categories = {
-      ...this.state.categories,
-      [category]: {
-        ...categoryState,
-        enabled: !categoryState.enabled,
-      },
-    };
-
-    // if all categories are disabled, enable all -- similar to nvd3
-    if (Object.values(categories).every(v => !v.enabled)) {
-      /* eslint-disable no-param-reassign */
-      Object.values(categories).forEach(v => {
-        v.enabled = true;
+      setCategories(categoriesExtended);
+    },
+    [categories],
+  );
+
+  const showSingleCategory = useCallback(
+    (category: string) => {
+      const modifiedCategories = { ...categories };
+      Object.values(modifiedCategories).forEach(v => {
+        v.enabled = false;
       });
-    }
-    this.setState({ categories });
-  }
-
-  showSingleCategory(category: string) {
-    const categories = { ...this.state.categories };
-    /* eslint-disable no-param-reassign */
-    Object.values(categories).forEach(v => {
-      v.enabled = false;
-    });
-    categories[category].enabled = true;
-    this.setState({ categories });
-  }
-
-  setTooltip = (tooltip: TooltipProps['tooltip']) => {
-    const { current } = this.containerRef;
-    if (current) {
-      current.setTooltip(tooltip);
-    }
-  };
+      modifiedCategories[category].enabled = true;
+      setCategories(modifiedCategories);
+    },
+    [categories],
+  );
+
+  return (
+    <div style={{ position: 'relative' }}>
+      <DeckGLContainerStyledWrapper
+        ref={containerRef}
+        viewport={viewport}
+        layers={getLayers()}
+        setControlValue={props.setControlValue}
+        mapStyle={props.formData.mapbox_style}
+        mapboxApiAccessToken={props.mapboxApiKey}
+        width={props.width}
+        height={props.height}
+      />
+      <Legend
+        forceCategorical
+        categories={categories}
+        format={props.formData.legend_format}
+        position={props.formData.legend_position}
+        showSingleCategory={showSingleCategory}
+        toggleCategory={toggleCategory}
+      />
+    </div>
+  );
+};
 
-  render() {
-    return (
-      <div style={{ position: 'relative' }}>
-        <DeckGLContainerStyledWrapper
-          ref={this.containerRef}
-          viewport={this.state.viewport}
-          layers={this.getLayers()}
-          setControlValue={this.props.setControlValue}
-          mapStyle={this.props.formData.mapbox_style}
-          mapboxApiAccessToken={this.props.mapboxApiKey}
-          width={this.props.width}
-          height={this.props.height}
-        />
-        <Legend
-          forceCategorical
-          categories={this.state.categories}
-          format={this.props.formData.legend_format}
-          position={this.props.formData.legend_position}
-          showSingleCategory={this.showSingleCategory}
-          toggleCategory={this.toggleCategory}
-        />
-      </div>
-    );
-  }
-}
+export default memo(CategoricalDeckGLContainer);
diff --git 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/DeckGLContainer.tsx 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/DeckGLContainer.tsx
index 29672febfb..7b8f61e18b 100644
--- 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/DeckGLContainer.tsx
+++ 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/DeckGLContainer.tsx
@@ -20,11 +20,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import React, { ReactNode } from 'react';
+import React, {
+  forwardRef,
+  memo,
+  ReactNode,
+  useCallback,
+  useEffect,
+  useImperativeHandle,
+  useState,
+} from 'react';
 import { isEqual } from 'lodash';
 import { StaticMap } from 'react-map-gl';
 import DeckGL, { Layer } from 'deck.gl/typed';
-import { JsonObject, JsonValue, styled } from '@superset-ui/core';
+import { JsonObject, JsonValue, styled, usePrevious } from '@superset-ui/core';
 import Tooltip, { TooltipProps } from './components/Tooltip';
 import 'mapbox-gl/dist/mapbox-gl.css';
 import { Viewport } from './utils/fitViewport';
@@ -43,76 +51,57 @@ export type DeckGLContainerProps = {
   onViewportChange?: (viewport: Viewport) => void;
 };
 
-export type DeckGLContainerState = {
-  lastUpdate: number | null;
-  viewState: Viewport;
-  tooltip: TooltipProps['tooltip'];
-  timer: ReturnType<typeof setInterval>;
-};
-
-export class DeckGLContainer extends React.Component<
-  DeckGLContainerProps,
-  DeckGLContainerState
-> {
-  constructor(props: DeckGLContainerProps) {
-    super(props);
-    this.tick = this.tick.bind(this);
-    this.onViewStateChange = this.onViewStateChange.bind(this);
-    // This has to be placed after this.tick is bound to this
-    this.state = {
-      timer: setInterval(this.tick, TICK),
-      tooltip: null,
-      viewState: props.viewport,
-      lastUpdate: null,
-    };
-  }
+export const DeckGLContainer = memo(
+  forwardRef((props: DeckGLContainerProps, ref) => {
+    const [tooltip, setTooltip] = useState<TooltipProps['tooltip']>(null);
+    const [lastUpdate, setLastUpdate] = useState<number | null>(null);
+    const [viewState, setViewState] = useState(props.viewport);
+    const prevViewport = usePrevious(props.viewport);
 
-  UNSAFE_componentWillReceiveProps(nextProps: DeckGLContainerProps) {
-    if (!isEqual(nextProps.viewport, this.props.viewport)) {
-      this.setState({ viewState: nextProps.viewport });
-    }
-  }
+    useImperativeHandle(ref, () => ({ setTooltip }), []);
 
-  componentWillUnmount() {
-    clearInterval(this.state.timer);
-  }
+    const tick = useCallback(() => {
+      // Rate limiting updating viewport controls as it triggers lots of 
renders
+      if (lastUpdate && Date.now() - lastUpdate > TICK) {
+        const setCV = props.setControlValue;
+        if (setCV) {
+          setCV('viewport', viewState);
+        }
+        setLastUpdate(null);
+      }
+    }, [lastUpdate, props.setControlValue, viewState]);
 
-  onViewStateChange({ viewState }: { viewState: JsonObject }) {
-    this.setState({ viewState: viewState as Viewport, lastUpdate: Date.now() 
});
-  }
+    useEffect(() => {
+      const timer = setInterval(tick, TICK);
+      return clearInterval(timer);
+    }, [tick]);
 
-  tick() {
-    // Rate limiting updating viewport controls as it triggers lotsa renders
-    const { lastUpdate } = this.state;
-    if (lastUpdate && Date.now() - lastUpdate > TICK) {
-      const setCV = this.props.setControlValue;
-      if (setCV) {
-        setCV('viewport', this.state.viewState);
+    useEffect(() => {
+      if (!isEqual(props.viewport, prevViewport)) {
+        setViewState(props.viewport);
       }
-      this.setState({ lastUpdate: null });
-    }
-  }
+    }, [prevViewport, props.viewport]);
 
-  layers() {
-    // Support for layer factory
-    if (this.props.layers.some(l => typeof l === 'function')) {
-      return this.props.layers.map(l =>
-        typeof l === 'function' ? l() : l,
-      ) as Layer[];
-    }
-
-    return this.props.layers as Layer[];
-  }
+    const onViewStateChange = useCallback(
+      ({ viewState }: { viewState: JsonObject }) => {
+        setViewState(viewState as Viewport);
+        setLastUpdate(Date.now());
+      },
+      [],
+    );
 
-  setTooltip = (tooltip: TooltipProps['tooltip']) => {
-    this.setState({ tooltip });
-  };
+    const layers = useCallback(() => {
+      // Support for layer factory
+      if (props.layers.some(l => typeof l === 'function')) {
+        return props.layers.map(l =>
+          typeof l === 'function' ? l() : l,
+        ) as Layer[];
+      }
 
-  render() {
-    const { children = null, height, width } = this.props;
-    const { viewState, tooltip } = this.state;
+      return props.layers as Layer[];
+    }, [props.layers]);
 
-    const layers = this.layers();
+    const { children = null, height, width } = props;
 
     return (
       <>
@@ -121,15 +110,15 @@ export class DeckGLContainer extends React.Component<
             controller
             width={width}
             height={height}
-            layers={layers}
+            layers={layers()}
             viewState={viewState}
             glOptions={{ preserveDrawingBuffer: true }}
-            onViewStateChange={this.onViewStateChange}
+            onViewStateChange={onViewStateChange}
           >
             <StaticMap
               preserveDrawingBuffer
-              mapStyle={this.props.mapStyle || 'light'}
-              mapboxApiAccessToken={this.props.mapboxApiAccessToken}
+              mapStyle={props.mapStyle || 'light'}
+              mapboxApiAccessToken={props.mapboxApiAccessToken}
             />
           </DeckGL>
           {children}
@@ -137,8 +126,8 @@ export class DeckGLContainer extends React.Component<
         <Tooltip tooltip={tooltip} />
       </>
     );
-  }
-}
+  }),
+);
 
 export const DeckGLContainerStyledWrapper = styled(DeckGLContainer)`
   .deckgl-tooltip > div {
@@ -146,3 +135,7 @@ export const DeckGLContainerStyledWrapper = 
styled(DeckGLContainer)`
     text-overflow: ellipsis;
   }
 `;
+
+export type DeckGLContainerHandle = typeof DeckGLContainer & {
+  setTooltip: (tooltip: ReactNode) => void;
+};
diff --git 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/Multi.tsx 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/Multi.tsx
index 5cfa02f704..540b094219 100644
--- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/Multi.tsx
+++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/Multi/Multi.tsx
@@ -19,7 +19,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import React from 'react';
+import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
 import { isEqual } from 'lodash';
 import {
   Datasource,
@@ -28,11 +28,12 @@ import {
   JsonValue,
   QueryFormData,
   SupersetClient,
+  usePrevious,
 } from '@superset-ui/core';
 import { Layer } from 'deck.gl/typed';
 
 import {
-  DeckGLContainer,
+  DeckGLContainerHandle,
   DeckGLContainerStyledWrapper,
 } from '../DeckGLContainer';
 import { getExploreLongUrl } from '../utils/explore';
@@ -52,120 +53,97 @@ export type DeckMultiProps = {
   onSelect: () => void;
 };
 
-export type DeckMultiState = {
-  subSlicesLayers: Record<number, Layer>;
-  viewport?: Viewport;
-};
-
-class DeckMulti extends React.PureComponent<DeckMultiProps, DeckMultiState> {
-  containerRef = React.createRef<DeckGLContainer>();
-
-  constructor(props: DeckMultiProps) {
-    super(props);
-    this.state = { subSlicesLayers: {} };
-    this.onViewportChange = this.onViewportChange.bind(this);
-  }
-
-  componentDidMount() {
-    const { formData, payload } = this.props;
-    this.loadLayers(formData, payload);
-  }
-
-  UNSAFE_componentWillReceiveProps(nextProps: DeckMultiProps) {
-    const { formData, payload } = nextProps;
-    const hasChanges = !isEqual(
-      this.props.formData.deck_slices,
-      nextProps.formData.deck_slices,
-    );
-    if (hasChanges) {
-      this.loadLayers(formData, payload);
-    }
-  }
-
-  onViewportChange(viewport: Viewport) {
-    this.setState({ viewport });
-  }
-
-  loadLayers(
-    formData: QueryFormData,
-    payload: JsonObject,
-    viewport?: Viewport,
-  ) {
-    this.setState({ subSlicesLayers: {}, viewport });
-    payload.data.slices.forEach(
-      (subslice: { slice_id: number } & JsonObject) => {
-        // Filters applied to multi_deck are passed down to underlying charts
-        // note that dashboard contextual information (filter_immune_slices 
and such) aren't
-        // taken into consideration here
-        const filters = [
-          ...(subslice.form_data.filters || []),
-          ...(formData.filters || []),
-          ...(formData.extra_filters || []),
-        ];
-        const subsliceCopy = {
-          ...subslice,
-          form_data: {
-            ...subslice.form_data,
-            filters,
-          },
-        };
-
-        const url = getExploreLongUrl(subsliceCopy.form_data, 'json');
+const DeckMulti = (props: DeckMultiProps) => {
+  const containerRef = useRef<DeckGLContainerHandle>();
 
-        if (url) {
-          SupersetClient.get({
-            endpoint: url,
-          })
-            .then(({ json }) => {
-              const layer = layerGenerators[subsliceCopy.form_data.viz_type](
-                subsliceCopy.form_data,
-                json,
-                this.props.onAddFilter,
-                this.setTooltip,
-                this.props.datasource,
-                [],
-                this.props.onSelect,
-              );
-              this.setState({
-                subSlicesLayers: {
-                  ...this.state.subSlicesLayers,
-                  [subsliceCopy.slice_id]: layer,
-                },
-              });
-            })
-            .catch(() => {});
-        }
-      },
-    );
-  }
+  const [viewport, setViewport] = useState<Viewport>();
+  const [subSlicesLayers, setSubSlicesLayers] = useState<Record<number, 
Layer>>(
+    {},
+  );
 
-  setTooltip = (tooltip: TooltipProps['tooltip']) => {
-    const { current } = this.containerRef;
+  const setTooltip = useCallback((tooltip: TooltipProps['tooltip']) => {
+    const { current } = containerRef;
     if (current) {
       current.setTooltip(tooltip);
     }
-  };
-
-  render() {
-    const { payload, formData, setControlValue, height, width } = this.props;
-    const { subSlicesLayers } = this.state;
-
-    const layers = Object.values(subSlicesLayers);
-
-    return (
-      <DeckGLContainerStyledWrapper
-        ref={this.containerRef}
-        mapboxApiAccessToken={payload.data.mapboxApiKey}
-        viewport={this.state.viewport || this.props.viewport}
-        layers={layers}
-        mapStyle={formData.mapbox_style}
-        setControlValue={setControlValue}
-        onViewportChange={this.onViewportChange}
-        height={height}
-        width={width}
-      />
-    );
-  }
-}
+  }, []);
+
+  const loadLayers = useCallback(
+    (formData: QueryFormData, payload: JsonObject, viewport?: Viewport) => {
+      setViewport(viewport);
+      setSubSlicesLayers({});
+      payload.data.slices.forEach(
+        (subslice: { slice_id: number } & JsonObject) => {
+          // Filters applied to multi_deck are passed down to underlying charts
+          // note that dashboard contextual information (filter_immune_slices 
and such) aren't
+          // taken into consideration here
+          const filters = [
+            ...(subslice.form_data.filters || []),
+            ...(formData.filters || []),
+            ...(formData.extra_filters || []),
+          ];
+          const subsliceCopy = {
+            ...subslice,
+            form_data: {
+              ...subslice.form_data,
+              filters,
+            },
+          };
+
+          const url = getExploreLongUrl(subsliceCopy.form_data, 'json');
+
+          if (url) {
+            SupersetClient.get({
+              endpoint: url,
+            })
+              .then(({ json }) => {
+                const layer = layerGenerators[subsliceCopy.form_data.viz_type](
+                  subsliceCopy.form_data,
+                  json,
+                  props.onAddFilter,
+                  setTooltip,
+                  props.datasource,
+                  [],
+                  props.onSelect,
+                );
+                setSubSlicesLayers(subSlicesLayers => ({
+                  ...subSlicesLayers,
+                  [subsliceCopy.slice_id]: layer,
+                }));
+              })
+              .catch(() => {});
+          }
+        },
+      );
+    },
+    [props.datasource, props.onAddFilter, props.onSelect, setTooltip],
+  );
+
+  const prevDeckSlices = usePrevious(props.formData.deck_slices);
+  useEffect(() => {
+    const { formData, payload } = props;
+    const hasChanges = !isEqual(prevDeckSlices, formData.deck_slices);
+    if (hasChanges) {
+      loadLayers(formData, payload);
+    }
+  }, [loadLayers, prevDeckSlices, props]);
+
+  const { payload, formData, setControlValue, height, width } = props;
+  const layers = Object.values(subSlicesLayers);
+
+  return (
+    <DeckGLContainerStyledWrapper
+      ref={containerRef}
+      mapboxApiAccessToken={payload.data.mapboxApiKey}
+      viewport={viewport || props.viewport}
+      layers={layers}
+      mapStyle={formData.mapbox_style}
+      setControlValue={setControlValue}
+      onViewportChange={setViewport}
+      height={height}
+      width={width}
+    />
+  );
+};
 
-export default DeckMulti;
+export default memo(DeckMulti);
diff --git 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/TooltipRow.tsx 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/TooltipRow.tsx
index 9d72f719fe..3e69258556 100644
--- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/TooltipRow.tsx
+++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/TooltipRow.tsx
@@ -23,15 +23,11 @@ type TooltipRowProps = {
   value: string;
 };
 
-export default class TooltipRow extends React.PureComponent<TooltipRowProps> {
-  render() {
-    const { label, value } = this.props;
+const TooltipRow = ({ label, value }: TooltipRowProps) => (
+  <div>
+    {label}
+    <strong>{value}</strong>
+  </div>
+);
 
-    return (
-      <div>
-        {label}
-        <strong>{value}</strong>
-      </div>
-    );
-  }
-}
+export default TooltipRow;
diff --git 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/factory.tsx 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/factory.tsx
index 4ddde91247..fb1255a2fd 100644
--- a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/factory.tsx
+++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/factory.tsx
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import React from 'react';
+import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
 import { isEqual } from 'lodash';
 import { Layer } from 'deck.gl/typed';
 import {
@@ -24,11 +24,12 @@ import {
   QueryFormData,
   JsonObject,
   HandlerFunction,
+  usePrevious,
 } from '@superset-ui/core';
 
 import {
   DeckGLContainerStyledWrapper,
-  DeckGLContainer,
+  DeckGLContainerHandle,
 } from './DeckGLContainer';
 import CategoricalDeckGLContainer from './CategoricalDeckGLContainer';
 import fitViewport, { Viewport } from './utils/fitViewport';
@@ -57,91 +58,73 @@ export interface getLayerType<T> {
 interface getPointsType {
   (data: JsonObject[]): Point[];
 }
-type deckGLComponentState = {
-  viewport: Viewport;
-  layer: Layer;
-};
 
 export function createDeckGLComponent(
   getLayer: getLayerType<unknown>,
   getPoints: getPointsType,
-): React.ComponentClass<deckGLComponentProps> {
+) {
   // Higher order component
-  class Component extends React.PureComponent<
-    deckGLComponentProps,
-    deckGLComponentState
-  > {
-    containerRef: React.RefObject<DeckGLContainer> = React.createRef();
-
-    constructor(props: deckGLComponentProps) {
-      super(props);
-
+  return memo((props: deckGLComponentProps) => {
+    const containerRef = useRef<DeckGLContainerHandle>();
+    const prevFormData = usePrevious(props.formData);
+    const prevPayload = usePrevious(props.payload);
+    const getAdjustedViewport = () => {
       const { width, height, formData } = props;
-      let { viewport } = props;
       if (formData.autozoom) {
-        viewport = fitViewport(viewport, {
+        return fitViewport(props.viewport, {
           width,
           height,
           points: getPoints(props.payload.data.features),
         }) as Viewport;
       }
+      return props.viewport;
+    };
 
-      this.state = {
-        viewport,
-        layer: this.computeLayer(props),
-      };
-      this.onViewportChange = this.onViewportChange.bind(this);
-    }
+    const [viewport, setViewport] = useState(getAdjustedViewport());
 
-    UNSAFE_componentWillReceiveProps(nextProps: deckGLComponentProps) {
-      // Only recompute the layer if anything BUT the viewport has changed
-      const nextFdNoVP = { ...nextProps.formData, viewport: null };
-      const currFdNoVP = { ...this.props.formData, viewport: null };
-      if (
-        !isEqual(nextFdNoVP, currFdNoVP) ||
-        nextProps.payload !== this.props.payload
-      ) {
-        this.setState({ layer: this.computeLayer(nextProps) });
+    const setTooltip = useCallback((tooltip: TooltipProps['tooltip']) => {
+      const { current } = containerRef;
+      if (current) {
+        current?.setTooltip(tooltip);
       }
-    }
+    }, []);
 
-    onViewportChange(viewport: Viewport) {
-      this.setState({ viewport });
-    }
+    const computeLayer = useCallback(
+      (props: deckGLComponentProps) => {
+        const { formData, payload, onAddFilter } = props;
 
-    computeLayer(props: deckGLComponentProps) {
-      const { formData, payload, onAddFilter } = props;
+        return getLayer(formData, payload, onAddFilter, setTooltip) as Layer;
+      },
+      [setTooltip],
+    );
 
-      return getLayer(formData, payload, onAddFilter, this.setTooltip) as 
Layer;
-    }
+    const [layer, setLayer] = useState(computeLayer(props));
 
-    setTooltip = (tooltip: TooltipProps['tooltip']) => {
-      const { current } = this.containerRef;
-      if (current) {
-        current?.setTooltip(tooltip);
+    useEffect(() => {
+      // Only recompute the layer if anything BUT the viewport has changed
+      const prevFdNoVP = { ...prevFormData, viewport: null };
+      const currFdNoVP = { ...props.formData, viewport: null };
+      if (!isEqual(prevFdNoVP, currFdNoVP) || prevPayload !== props.payload) {
+        setLayer(computeLayer(props));
       }
-    };
+    }, [computeLayer, prevFormData, prevPayload, props]);
 
-    render() {
-      const { formData, payload, setControlValue, height, width } = this.props;
-      const { layer, viewport } = this.state;
+    const { formData, payload, setControlValue, height, width } = props;
 
-      return (
-        <DeckGLContainerStyledWrapper
-          ref={this.containerRef}
-          mapboxApiAccessToken={payload.data.mapboxApiKey}
-          viewport={viewport}
-          layers={[layer]}
-          mapStyle={formData.mapbox_style}
-          setControlValue={setControlValue}
-          width={width}
-          height={height}
-          onViewportChange={this.onViewportChange}
-        />
-      );
-    }
-  }
-  return Component;
+    return (
+      <DeckGLContainerStyledWrapper
+        ref={containerRef}
+        mapboxApiAccessToken={payload.data.mapboxApiKey}
+        viewport={viewport}
+        layers={[layer]}
+        mapStyle={formData.mapbox_style}
+        setControlValue={setControlValue}
+        width={width}
+        height={height}
+        onViewportChange={setViewport}
+      />
+    );
+  });
 }
 
 export function createCategoricalDeckGLComponent(
diff --git 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/Geojson.tsx
 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/Geojson.tsx
index 4aa827e45b..c8c9d4863c 100644
--- 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/Geojson.tsx
+++ 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Geojson/Geojson.tsx
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import React from 'react';
+import React, { memo, useCallback, useMemo, useRef } from 'react';
 import { GeoJsonLayer } from 'deck.gl/typed';
 import geojsonExtent from '@mapbox/geojson-extent';
 import {
@@ -27,7 +27,7 @@ import {
 } from '@superset-ui/core';
 
 import {
-  DeckGLContainer,
+  DeckGLContainerHandle,
   DeckGLContainerStyledWrapper,
 } from '../../DeckGLContainer';
 import { hexToRGB } from '../../utils/colors';
@@ -164,21 +164,19 @@ export type DeckGLGeoJsonProps = {
   width: number;
 };
 
-class DeckGLGeoJson extends React.Component<DeckGLGeoJsonProps> {
-  containerRef = React.createRef<DeckGLContainer>();
-
-  setTooltip = (tooltip: TooltipProps['tooltip']) => {
-    const { current } = this.containerRef;
+const DeckGLGeoJson = (props: DeckGLGeoJsonProps) => {
+  const containerRef = useRef<DeckGLContainerHandle>();
+  const setTooltip = useCallback((tooltip: TooltipProps['tooltip']) => {
+    const { current } = containerRef;
     if (current) {
       current.setTooltip(tooltip);
     }
-  };
+  }, []);
 
-  render() {
-    const { formData, payload, setControlValue, onAddFilter, height, width } =
-      this.props;
+  const { formData, payload, setControlValue, onAddFilter, height, width } =
+    props;
 
-    let { viewport } = this.props;
+  const viewport: Viewport = useMemo(() => {
     if (formData.autozoom) {
       const points =
         payload?.data?.features?.reduce?.(
@@ -194,29 +192,36 @@ class DeckGLGeoJson extends 
React.Component<DeckGLGeoJsonProps> {
         ) || [];
 
       if (points.length) {
-        viewport = fitViewport(viewport, {
+        return fitViewport(props.viewport, {
           width,
           height,
           points,
         });
       }
     }
+    return props.viewport;
+  }, [
+    formData.autozoom,
+    height,
+    payload?.data?.features,
+    props.viewport,
+    width,
+  ]);
 
-    const layer = getLayer(formData, payload, onAddFilter, this.setTooltip);
-
-    return (
-      <DeckGLContainerStyledWrapper
-        ref={this.containerRef}
-        mapboxApiAccessToken={payload.data.mapboxApiKey}
-        viewport={viewport}
-        layers={[layer]}
-        mapStyle={formData.mapbox_style}
-        setControlValue={setControlValue}
-        height={height}
-        width={width}
-      />
-    );
-  }
-}
+  const layer = getLayer(formData, payload, onAddFilter, setTooltip);
+
+  return (
+    <DeckGLContainerStyledWrapper
+      ref={containerRef}
+      mapboxApiAccessToken={payload.data.mapboxApiKey}
+      viewport={viewport}
+      layers={[layer]}
+      mapStyle={formData.mapbox_style}
+      setControlValue={setControlValue}
+      height={height}
+      width={width}
+    />
+  );
+};
 
-export default DeckGLGeoJson;
+export default memo(DeckGLGeoJson);
diff --git 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/Polygon.tsx
 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/Polygon.tsx
index 627125c398..460c4a3b51 100644
--- 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/Polygon.tsx
+++ 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Polygon/Polygon.tsx
@@ -21,7 +21,7 @@
  */
 /* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */
 
-import React from 'react';
+import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
 import {
   HandlerFunction,
   JsonObject,
@@ -41,7 +41,7 @@ import sandboxedEval from '../../utils/sandbox';
 import getPointsFromPolygon from '../../utils/getPointsFromPolygon';
 import fitViewport, { Viewport } from '../../utils/fitViewport';
 import {
-  DeckGLContainer,
+  DeckGLContainerHandle,
   DeckGLContainerStyledWrapper,
 } from '../../DeckGLContainer';
 import { TooltipProps } from '../../components/Tooltip';
@@ -173,145 +173,134 @@ export type DeckGLPolygonProps = {
   height: number;
 };
 
-export type DeckGLPolygonState = {
-  lastClick: number;
-  viewport: Viewport;
-  formData: PolygonFormData;
-  selected: JsonObject[];
-};
-
-class DeckGLPolygon extends React.PureComponent<
-  DeckGLPolygonProps,
-  DeckGLPolygonState
-> {
-  containerRef = React.createRef<DeckGLContainer>();
-
-  constructor(props: DeckGLPolygonProps) {
-    super(props);
-
-    this.state = DeckGLPolygon.getDerivedStateFromProps(
-      props,
-    ) as DeckGLPolygonState;
-
-    this.getLayers = this.getLayers.bind(this);
-    this.onSelect = this.onSelect.bind(this);
-  }
-
-  static getDerivedStateFromProps(
-    props: DeckGLPolygonProps,
-    state?: DeckGLPolygonState,
-  ) {
-    const { width, height, formData, payload } = props;
-
-    // the state is computed only from the payload; if it hasn't changed, do
-    // not recompute state since this would reset selections and/or the play
-    // slider position due to changes in form controls
-    if (state && payload.form_data === state.formData) {
-      return null;
-    }
-
-    const features = payload.data.features || [];
+const DeckGLPolygon = (props: DeckGLPolygonProps) => {
+  const containerRef = useRef<DeckGLContainerHandle>();
 
-    let { viewport } = props;
-    if (formData.autozoom) {
+  const getAdjustedViewport = useCallback(() => {
+    let viewport = { ...props.viewport };
+    if (props.formData.autozoom) {
+      const features = props.payload.data.features || [];
       viewport = fitViewport(viewport, {
-        width,
-        height,
+        width: props.width,
+        height: props.height,
         points: features.flatMap(getPointsFromPolygon),
       });
     }
+    if (viewport.zoom < 0) {
+      viewport.zoom = 0;
+    }
+    return viewport;
+  }, [props]);
+
+  const [lastClick, setLastClick] = useState(0);
+  const [viewport, setViewport] = useState(getAdjustedViewport());
+  const [stateFormData, setStateFormData] = useState(props.payload.form_data);
+  const [selected, setSelected] = useState<JsonObject[]>([]);
+
+  useEffect(() => {
+    const { payload } = props;
+
+    if (payload.form_data !== stateFormData) {
+      setViewport(getAdjustedViewport());
+      setSelected([]);
+      setLastClick(0);
+      setStateFormData(payload.form_data);
+    }
+  }, [getAdjustedViewport, props, stateFormData, viewport]);
 
-    return {
-      viewport,
-      selected: [],
-      lastClick: 0,
-      formData: payload.form_data,
-    };
-  }
-
-  onSelect(polygon: JsonObject) {
-    const { formData, onAddFilter } = this.props;
-
-    const now = new Date().getDate();
-    const doubleClick = now - this.state.lastClick <= DOUBLE_CLICK_THRESHOLD;
-
-    // toggle selected polygons
-    const selected = [...this.state.selected];
-    if (doubleClick) {
-      selected.splice(0, selected.length, polygon);
-    } else if (formData.toggle_polygons) {
-      const i = selected.indexOf(polygon);
-      if (i === -1) {
-        selected.push(polygon);
+  const setTooltip = useCallback((tooltip: TooltipProps['tooltip']) => {
+    const { current } = containerRef;
+    if (current) {
+      current.setTooltip(tooltip);
+    }
+  }, []);
+
+  const onSelect = useCallback(
+    (polygon: JsonObject) => {
+      const { formData, onAddFilter } = props;
+
+      const now = new Date().getDate();
+      const doubleClick = now - lastClick <= DOUBLE_CLICK_THRESHOLD;
+
+      // toggle selected polygons
+      const selectedCopy = [...selected];
+      if (doubleClick) {
+        selectedCopy.splice(0, selectedCopy.length, polygon);
+      } else if (formData.toggle_polygons) {
+        const i = selectedCopy.indexOf(polygon);
+        if (i === -1) {
+          selectedCopy.push(polygon);
+        } else {
+          selectedCopy.splice(i, 1);
+        }
       } else {
-        selected.splice(i, 1);
+        selectedCopy.splice(0, 1, polygon);
       }
-    } else {
-      selected.splice(0, 1, polygon);
-    }
 
-    this.setState({ selected, lastClick: now });
-    if (formData.table_filter) {
-      onAddFilter(formData.line_column, selected, false, true);
-    }
-  }
+      setSelected(selectedCopy);
+      setLastClick(now);
+      if (formData.table_filter) {
+        onAddFilter(formData.line_column, selected, false, true);
+      }
+    },
+    [lastClick, props, selected],
+  );
 
-  getLayers() {
-    if (this.props.payload.data.features === undefined) {
+  const getLayers = useCallback(() => {
+    if (props.payload.data.features === undefined) {
       return [];
     }
 
     const layer = getLayer(
-      this.props.formData,
-      this.props.payload,
-      this.props.onAddFilter,
-      this.setTooltip,
-      this.state.selected,
-      this.onSelect,
+      props.formData,
+      props.payload,
+      props.onAddFilter,
+      setTooltip,
+      selected,
+      onSelect,
     );
 
     return [layer];
-  }
-
-  setTooltip = (tooltip: TooltipProps['tooltip']) => {
-    const { current } = this.containerRef;
-    if (current) {
-      current.setTooltip(tooltip);
-    }
-  };
-
-  render() {
-    const { payload, formData, setControlValue } = this.props;
-
-    const fd = formData;
-    const metricLabel = fd.metric ? fd.metric.label || fd.metric : null;
-    const accessor = (d: JsonObject) => d[metricLabel];
-
-    const buckets = getBuckets(formData, payload.data.features, accessor);
+  }, [
+    onSelect,
+    props.formData,
+    props.onAddFilter,
+    props.payload,
+    selected,
+    setTooltip,
+  ]);
+
+  const { payload, formData, setControlValue } = props;
+
+  const metricLabel = formData.metric
+    ? formData.metric.label || formData.metric
+    : null;
+  const accessor = (d: JsonObject) => d[metricLabel];
 
-    return (
-      <div style={{ position: 'relative' }}>
-        <DeckGLContainerStyledWrapper
-          ref={this.containerRef}
-          viewport={this.state.viewport}
-          layers={this.getLayers()}
-          setControlValue={setControlValue}
-          mapStyle={formData.mapbox_style}
-          mapboxApiAccessToken={payload.data.mapboxApiKey}
-          width={this.props.width}
-          height={this.props.height}
+  const buckets = getBuckets(formData, payload.data.features, accessor);
+
+  return (
+    <div style={{ position: 'relative' }}>
+      <DeckGLContainerStyledWrapper
+        ref={containerRef}
+        viewport={viewport}
+        layers={getLayers()}
+        setControlValue={setControlValue}
+        mapStyle={formData.mapbox_style}
+        mapboxApiAccessToken={payload.data.mapboxApiKey}
+        width={props.width}
+        height={props.height}
+      />
+
+      {formData.metric !== null && (
+        <Legend
+          categories={buckets}
+          position={formData.legend_position}
+          format={formData.legend_format}
         />
+      )}
+    </div>
+  );
+};
 
-        {formData.metric !== null && (
-          <Legend
-            categories={buckets}
-            position={formData.legend_position}
-            format={formData.legend_format}
-          />
-        )}
-      </div>
-    );
-  }
-}
-
-export default DeckGLPolygon;
+export default memo(DeckGLPolygon);
diff --git 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/Screengrid.tsx
 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/Screengrid.tsx
index 173770c6c1..7e47cc9530 100644
--- 
a/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/Screengrid.tsx
+++ 
b/superset-frontend/plugins/legacy-preset-chart-deckgl/src/layers/Screengrid/Screengrid.tsx
@@ -20,7 +20,7 @@
  */
 /* eslint no-underscore-dangle: ["error", { "allow": ["", "__timestamp"] }] */
 
-import React from 'react';
+import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
 import { ScreenGridLayer } from 'deck.gl/typed';
 import { JsonObject, JsonValue, QueryFormData, t } from '@superset-ui/core';
 import { noop } from 'lodash';
@@ -30,7 +30,7 @@ import TooltipRow from '../../TooltipRow';
 // eslint-disable-next-line import/extensions
 import fitViewport, { Viewport } from '../../utils/fitViewport';
 import {
-  DeckGLContainer,
+  DeckGLContainerHandle,
   DeckGLContainerStyledWrapper,
 } from '../../DeckGLContainer';
 import { TooltipProps } from '../../components/Tooltip';
@@ -99,93 +99,63 @@ export type DeckGLScreenGridProps = {
   onAddFilter: () => void;
 };
 
-export type DeckGLScreenGridState = {
-  viewport: Viewport;
-  formData: QueryFormData;
-};
-
-class DeckGLScreenGrid extends React.PureComponent<
-  DeckGLScreenGridProps,
-  DeckGLScreenGridState
-> {
-  containerRef = React.createRef<DeckGLContainer>();
-
-  constructor(props: DeckGLScreenGridProps) {
-    super(props);
-
-    this.state = DeckGLScreenGrid.getDerivedStateFromProps(
-      props,
-    ) as DeckGLScreenGridState;
-
-    this.getLayers = this.getLayers.bind(this);
-  }
-
-  static getDerivedStateFromProps(
-    props: DeckGLScreenGridProps,
-    state?: DeckGLScreenGridState,
-  ) {
-    // the state is computed only from the payload; if it hasn't changed, do
-    // not recompute state since this would reset selections and/or the play
-    // slider position due to changes in form controls
-    if (state && props.payload.form_data === state.formData) {
-      return null;
-    }
+const DeckGLScreenGrid = (props: DeckGLScreenGridProps) => {
+  const containerRef = useRef<DeckGLContainerHandle>();
 
+  const getAdjustedViewport = useCallback(() => {
     const features = props.payload.data.features || [];
 
     const { width, height, formData } = props;
 
-    let { viewport } = props;
     if (formData.autozoom) {
-      viewport = fitViewport(viewport, {
+      return fitViewport(props.viewport, {
         width,
         height,
         points: getPoints(features),
       });
     }
+    return props.viewport;
+  }, [props]);
 
-    return {
-      viewport,
-      formData: props.payload.form_data as QueryFormData,
-    };
-  }
+  const [stateFormData, setStateFormData] = useState(props.payload.form_data);
+  const [viewport, setViewport] = useState(getAdjustedViewport());
 
-  getLayers() {
-    const layer = getLayer(
-      this.props.formData,
-      this.props.payload,
-      noop,
-      this.setTooltip,
-    );
-
-    return [layer];
-  }
+  useEffect(() => {
+    if (props.payload.form_data !== stateFormData) {
+      setViewport(getAdjustedViewport());
+      setStateFormData(props.payload.form_data);
+    }
+  }, [getAdjustedViewport, props.payload.form_data, stateFormData]);
 
-  setTooltip = (tooltip: TooltipProps['tooltip']) => {
-    const { current } = this.containerRef;
+  const setTooltip = useCallback((tooltip: TooltipProps['tooltip']) => {
+    const { current } = containerRef;
     if (current) {
       current.setTooltip(tooltip);
     }
-  };
-
-  render() {
-    const { formData, payload, setControlValue } = this.props;
-
-    return (
-      <div>
-        <DeckGLContainerStyledWrapper
-          ref={this.containerRef}
-          viewport={this.state.viewport}
-          layers={this.getLayers()}
-          setControlValue={setControlValue}
-          mapStyle={formData.mapbox_style}
-          mapboxApiAccessToken={payload.data.mapboxApiKey}
-          width={this.props.width}
-          height={this.props.height}
-        />
-      </div>
-    );
-  }
-}
+  }, []);
+
+  const getLayers = useCallback(() => {
+    const layer = getLayer(props.formData, props.payload, noop, setTooltip);
+
+    return [layer];
+  }, [props.formData, props.payload, setTooltip]);
+
+  const { formData, payload, setControlValue } = props;
+
+  return (
+    <div>
+      <DeckGLContainerStyledWrapper
+        ref={containerRef}
+        viewport={viewport}
+        layers={getLayers()}
+        setControlValue={setControlValue}
+        mapStyle={formData.mapbox_style}
+        mapboxApiAccessToken={payload.data.mapboxApiKey}
+        width={props.width}
+        height={props.height}
+      />
+    </div>
+  );
+};
 
-export default DeckGLScreenGrid;
+export default memo(DeckGLScreenGrid);


Reply via email to