Skip to content

chore: Convert class components to functional components#3441

Merged
igorDykhta merged 3 commits into
masterfrom
igr/iter-convert-to-func-comp
May 19, 2026
Merged

chore: Convert class components to functional components#3441
igorDykhta merged 3 commits into
masterfrom
igr/iter-convert-to-func-comp

Conversation

@igorDykhta

@igorDykhta igorDykhta commented May 16, 2026

Copy link
Copy Markdown
Collaborator

Here's the list of components updated in this adaptation of PR #3137:

src/components/src/effects/effect-panel.tsx — Converted from class to functional component. Removed PropTypes, added ActionHandler<> type wrappers, replaced class methods with useCallback hooks.

src/components/src/notification-panel.tsx — Converted from class to functional component. Removed React.memo wrapper workaround, changed return type from React.ComponentClass to React.FC.

src/components/src/notification-panel/notification-item.tsx — Converted from class to functional component. Replaced class state with useState, replaced componentDidMount with useEffect.

src/components/src/modals/add-map-style-modal.tsx — Converted from class to functional component. Replaced getDerivedStateFromProps with useEffect, replaced this._map with useRef, removed react-lifecycles-compat polyfill.

src/components/src/modals/data-table-modal.tsx — Converted from class to functional component. Replaced createSelector (reselect) with useMemo, replaced class methods with useCallback, replaced instance cache with useRef, removed @ts-expect-error on withTheme.

src/components/src/modals/export-data-modal.tsx — Converted from class to functional component. Replaced componentDidMount with useEffect, replaced class method _onSelectDataset with a local function.

Signed-off-by: Ihor Dykhta <ihordykhta@Ihors-MacBook-Pro.local>
@igorDykhta igorDykhta marked this pull request as ready for review May 16, 2026 17:50
Copilot AI review requested due to automatic review settings May 16, 2026 17:50
@igorDykhta igorDykhta self-assigned this May 16, 2026
@igorDykhta igorDykhta added the 3.3 Kepler.gl 3.3 release label May 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors several React class components to functional components using hooks, continuing the work proposed in stale PR #3137. The conversions cover notification, modal, and effect panel components.

Changes:

  • Replace class lifecycle methods (componentDidMount, getDerivedStateFromProps) with useEffect hooks and useState/useRef/useMemo/useCallback.
  • Drop react-lifecycles-compat's polyfill, PropTypes, createSelector, and React.memo wrappers where present.
  • Convert this.props/this.state access into destructured props and local state.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/components/src/notification-panel/notification-item.tsx Class → function with useState/useEffect for isExpanded.
src/components/src/notification-panel.tsx Class → React.FC; removed React.memo wrapper and displayName.
src/components/src/modals/export-data-modal.tsx Class → function; componentDidMount replaced by a useEffect with prop deps.
src/components/src/modals/data-table-modal.tsx Class → function; createSelector selectors replaced by useMemo and cache moved to useRef.
src/components/src/modals/add-map-style-modal.tsx Class → function; getDerivedStateFromPropsuseEffect; ref handling restructured with useRef.
src/components/src/effects/effect-panel.tsx Class → React.FC with useCallback handlers; types switched to ActionHandler.
Comments suppressed due to low confidence (2)

src/components/src/modals/add-map-style-modal.tsx:166

  • The ref callback setMapRefCallback is recreated on every render. React invokes callback refs whenever their identity changes, calling the previous ref with null and the new one with the instance. As a result, on every re-render this will: (1) execute the if (mapRef.current && mapRefInstance) branch which clears mapRef.current, then (2) re-enter the if (map && mapRef.current !== map) branch and re-attach new style.load and error handlers — leaking listeners. Wrap setMapRefCallback in useCallback (or use a stable function) so the ref identity is stable across renders.
    const setMapRefCallback = (mapRefInstance: MapRef | null) => {
      if (mapRef.current && mapRefInstance) {
        const map = mapRefInstance.getMap();
        if (map && mapRef.current !== map) {
          mapRef.current.off('style.load', nop);
          mapRef.current.off('error', nop);
          mapRef.current = null;
        }
      }

      const map = mapRefInstance && mapRefInstance.getMap();
      if (map && mapRef.current !== map) {
        mapRef.current = map;

        map.on('style.load', () => {
          const style = map.getStyle();
          loadMapStyleJson(style);
        });

        map.on('error', () => {
          loadMapStyleError();
        });
      }
    };

src/components/src/modals/add-map-style-modal.tsx:165

  • The style.load and error listeners installed on the map close over loadMapStyleJson/loadMapStyleError, which themselves close over the loadCustomMapStyleAction prop captured at the time the ref callback ran. If that prop changes later (e.g. a new dispatch binding), the listeners will continue invoking the stale reference. In the class component this.props.loadCustomMapStyle was always read fresh. Consider stabilizing these handlers via a ref-stored latest-callback pattern, or attaching listeners that read from a ref.
    const loadMapStyleJson = (style: any) => {
      loadCustomMapStyleAction({style, error: false});
    };

    const loadMapStyleError = () => {
      loadCustomMapStyleAction({error: true});
    };

    const setMapRefCallback = (mapRefInstance: MapRef | null) => {
      if (mapRef.current && mapRefInstance) {
        const map = mapRefInstance.getMap();
        if (map && mapRef.current !== map) {
          mapRef.current.off('style.load', nop);
          mapRef.current.off('error', nop);
          mapRef.current = null;
        }
      }

      const map = mapRefInstance && mapRefInstance.getMap();
      if (map && mapRef.current !== map) {
        mapRef.current = map;

        map.on('style.load', () => {
          const style = map.getStyle();
          loadMapStyleJson(style);
        });

        map.on('error', () => {
          loadMapStyleError();
        });
      }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/components/src/modals/export-data-modal.tsx Outdated
Comment thread src/components/src/notification-panel.tsx
Comment thread src/components/src/notification-panel/notification-item.tsx
Comment thread src/components/src/modals/add-map-style-modal.tsx
Ihor Dykhta added 2 commits May 16, 2026 21:24
Signed-off-by: Ihor Dykhta <ihordykhta@Ihors-MacBook-Pro.local>
Signed-off-by: Ihor Dykhta <ihordykhta@Ihors-MacBook-Pro.local>
@igorDykhta igorDykhta requested review from ilyabo and lixun910 May 18, 2026 15:27

@lixun910 lixun910 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@igorDykhta igorDykhta merged commit 80882a2 into master May 19, 2026
8 checks passed
@igorDykhta igorDykhta deleted the igr/iter-convert-to-func-comp branch May 19, 2026 20:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3.3 Kepler.gl 3.3 release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants