Skip to content

Commit ced19a6

Browse files
author
Robert Austin
authored
[Resolver] Fix useSelector usage (#76129) (#76146)
In some cases we have selectors returning thunks. The thunks need to be called inside `useSelector` in order for a rerender to be reliably triggered. `useSelector` triggers a re-render if its return value changes. By calling the thunk inside of the selector passed to `useSelector`, we will trigger re-renders when needed.
1 parent 22e872e commit ced19a6

File tree

4 files changed

+25
-17
lines changed

4 files changed

+25
-17
lines changed

x-pack/plugins/security_solution/public/resolver/view/panels/process_details.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
import { CubeForProcess } from './cube_for_process';
3232
import { ResolverEvent } from '../../../../common/endpoint/types';
3333
import { useResolverTheme } from '../assets';
34-
import { CrumbInfo } from '../../types';
34+
import { CrumbInfo, ResolverState } from '../../types';
3535

3636
const StyledDescriptionList = styled(EuiDescriptionList)`
3737
&.euiDescriptionList.euiDescriptionList--column dt.euiDescriptionList__title.desc-title {
@@ -52,7 +52,9 @@ export const ProcessDetails = memo(function ProcessDetails({
5252
}) {
5353
const processName = event.eventName(processEvent);
5454
const entityId = event.entityId(processEvent);
55-
const isProcessTerminated = useSelector(selectors.isProcessTerminated)(entityId);
55+
const isProcessTerminated = useSelector((state: ResolverState) =>
56+
selectors.isProcessTerminated(state)(entityId)
57+
);
5658
const processInfoEntry: EuiDescriptionListProps['listItems'] = useMemo(() => {
5759
const eventTime = event.eventTimestamp(processEvent);
5860
const dateTime = eventTime === undefined ? null : formatDate(eventTime);

x-pack/plugins/security_solution/public/resolver/view/panels/related_event_detail.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { ResolverEvent } from '../../../../common/endpoint/types';
1616
import * as selectors from '../../store/selectors';
1717
import { useResolverDispatch } from '../use_resolver_dispatch';
1818
import { PanelContentError } from './panel_content_error';
19-
import { CrumbInfo } from '../../types';
19+
import { CrumbInfo, ResolverState } from '../../types';
2020

2121
// Adding some styles to prevent horizontal scrollbars, per request from UX review
2222
const StyledDescriptionList = memo(styled(EuiDescriptionList)`
@@ -154,9 +154,8 @@ export const RelatedEventDetail = memo(function RelatedEventDetail({
154154
relatedEventCategory = naString,
155155
sections,
156156
formattedDate,
157-
] = useSelector(selectors.relatedEventDisplayInfoByEntityAndSelfId)(
158-
processEntityId,
159-
relatedEventId
157+
] = useSelector((state: ResolverState) =>
158+
selectors.relatedEventDisplayInfoByEntityAndSelfId(state)(processEntityId, relatedEventId)
160159
);
161160

162161
const waitCrumbs = useMemo(() => {

x-pack/plugins/security_solution/public/resolver/view/process_event_dot.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { htmlIdGenerator, EuiButton, EuiI18nNumber, EuiFlexGroup, EuiFlexItem }
1212
import { useSelector } from 'react-redux';
1313
import { NodeSubMenu, subMenuAssets } from './submenu';
1414
import { applyMatrix3 } from '../models/vector2';
15-
import { Vector2, Matrix3 } from '../types';
15+
import { Vector2, Matrix3, ResolverState } from '../types';
1616
import { SymbolIds, useResolverTheme, calculateResolverFontSize } from './assets';
1717
import { ResolverEvent, SafeResolverEvent } from '../../../common/endpoint/types';
1818
import { useResolverDispatch } from './use_resolver_dispatch';
@@ -118,19 +118,23 @@ const UnstyledProcessEventDot = React.memo(
118118
// NB: this component should be taking nodeID as a `string` instead of handling this logic here
119119
throw new Error('Tried to render a node with no ID');
120120
}
121-
const relatedEventStats = useSelector(selectors.relatedEventsStats)(nodeID);
121+
const relatedEventStats = useSelector((state: ResolverState) =>
122+
selectors.relatedEventsStats(state)(nodeID)
123+
);
122124

123125
// define a standard way of giving HTML IDs to nodes based on their entity_id/nodeID.
124126
// this is used to link nodes via aria attributes
125127
const nodeHTMLID = useCallback((id: string) => htmlIdGenerator(htmlIDPrefix)(`${id}:node`), [
126128
htmlIDPrefix,
127129
]);
128130

129-
const ariaLevel: number | null = useSelector(selectors.ariaLevel)(nodeID);
131+
const ariaLevel: number | null = useSelector((state: ResolverState) =>
132+
selectors.ariaLevel(state)(nodeID)
133+
);
130134

131135
// the node ID to 'flowto'
132-
const ariaFlowtoNodeID: string | null = useSelector(selectors.ariaFlowtoNodeID)(timeAtRender)(
133-
nodeID
136+
const ariaFlowtoNodeID: string | null = useSelector((state: ResolverState) =>
137+
selectors.ariaFlowtoNodeID(state)(timeAtRender)(nodeID)
134138
);
135139

136140
const isShowingEventActions = xScale > 0.8;
@@ -290,8 +294,8 @@ const UnstyledProcessEventDot = React.memo(
290294
? subMenuAssets.initialMenuStatus
291295
: relatedEventOptions;
292296

293-
const grandTotal: number | null = useSelector(selectors.relatedEventTotalForProcess)(
294-
event as ResolverEvent
297+
const grandTotal: number | null = useSelector((state: ResolverState) =>
298+
selectors.relatedEventTotalForProcess(state)(event as ResolverEvent)
295299
);
296300

297301
/* eslint-disable jsx-a11y/click-events-have-key-events */

x-pack/plugins/security_solution/public/resolver/view/resolver_without_providers.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { useStateSyncingActions } from './use_state_syncing_actions';
2121
import { StyledMapContainer, StyledPanel, GraphContainer } from './styles';
2222
import { entityIDSafeVersion } from '../../../common/endpoint/models/event';
2323
import { SideEffectContext } from './side_effect_context';
24-
import { ResolverProps } from '../types';
24+
import { ResolverProps, ResolverState } from '../types';
2525

2626
/**
2727
* The highest level connected Resolver component. Needs a `Provider` in its ancestry to work.
@@ -46,9 +46,12 @@ export const ResolverWithoutProviders = React.memo(
4646
// use this for the entire render in order to keep things in sync
4747
const timeAtRender = timestamp();
4848

49-
const { processNodePositions, connectingEdgeLineSegments } = useSelector(
50-
selectors.visibleNodesAndEdgeLines
51-
)(timeAtRender);
49+
const {
50+
processNodePositions,
51+
connectingEdgeLineSegments,
52+
} = useSelector((state: ResolverState) =>
53+
selectors.visibleNodesAndEdgeLines(state)(timeAtRender)
54+
);
5255
const terminatedProcesses = useSelector(selectors.terminatedProcesses);
5356
const { projectionMatrix, ref: cameraRef, onMouseDown } = useCamera();
5457

0 commit comments

Comments
 (0)