fix(embedded): move dataMask store.subscribe into an effect

Per codeant review on #39893: subscribing to the Redux store from inside
the render body of EmbededLazyDashboardPage registered a new listener on
every render with no cleanup, leaking subscriptions and double-emitting
observeDataMask events on each store update. StrictMode's dev-mode
double-mount made the leak immediately visible.

Move the subscription into a useEffect keyed on emitDataMasks, returning
the Redux unsubscribe so React tears the listener down on unmount.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Code
2026-05-05 21:46:16 -07:00
parent 893a780846
commit 04dcd888f8

View File

@@ -18,7 +18,7 @@
*/
import 'src/public-path';
import { lazy, StrictMode, Suspense } from 'react';
import { lazy, StrictMode, Suspense, useEffect } from 'react';
import { createRoot, type Root } from 'react-dom/client';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { Global } from '@emotion/react';
@@ -68,18 +68,19 @@ const LazyDashboardPage = lazy(
const EmbededLazyDashboardPage = () => {
const uiConfig = useUiConfig();
const emitDataMasks = uiConfig?.emitDataMasks;
// Emit data mask changes to the parent window
if (uiConfig?.emitDataMasks) {
// Emit data mask changes to the parent window. Subscribing inside an effect
// (rather than during render) ensures the unsubscribe runs on unmount,
// including StrictMode's dev-mode double-mount cycle.
useEffect(() => {
if (!emitDataMasks) return undefined;
log('setting up Switchboard event emitter');
let previousDataMask = store.getState().dataMask;
store.subscribe(() => {
const currentState = store.getState();
const currentDataMask = currentState.dataMask;
// Only emit if the dataMask has changed
return store.subscribe(() => {
const currentDataMask = store.getState().dataMask;
if (previousDataMask !== currentDataMask) {
Switchboard.emit('observeDataMask', {
...currentDataMask,
@@ -88,7 +89,7 @@ const EmbededLazyDashboardPage = () => {
previousDataMask = currentDataMask;
}
});
}
}, [emitDataMasks]);
return <LazyDashboardPage idOrSlug={bootstrapData.embedded!.dashboard_id} />;
};