chore: Convert class components to functional components#3441
Merged
Conversation
Signed-off-by: Ihor Dykhta <ihordykhta@Ihors-MacBook-Pro.local>
Contributor
There was a problem hiding this comment.
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) withuseEffecthooks anduseState/useRef/useMemo/useCallback. - Drop
react-lifecycles-compat'spolyfill,PropTypes,createSelector, andReact.memowrappers where present. - Convert
this.props/this.stateaccess 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; getDerivedStateFromProps → useEffect; 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
setMapRefCallbackis recreated on every render. React invokes callback refs whenever their identity changes, calling the previous ref withnulland the new one with the instance. As a result, on every re-render this will: (1) execute theif (mapRef.current && mapRefInstance)branch which clearsmapRef.current, then (2) re-enter theif (map && mapRef.current !== map)branch and re-attach newstyle.loadanderrorhandlers — leaking listeners. WrapsetMapRefCallbackinuseCallback(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.loadanderrorlisteners installed on the map close overloadMapStyleJson/loadMapStyleError, which themselves close over theloadCustomMapStyleActionprop 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 componentthis.props.loadCustomMapStylewas 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.
added 2 commits
May 16, 2026 21:24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.