Skip to content

Commit

Permalink
Avoid unnecessary rerendering of MessageTableEntry component. (#19899)
Browse files Browse the repository at this point in the history
* Avoid excessive reexecution of `useSendTelemetry`.

* Cleaning up.

* Introducing reusable function.

* Adding tests.

* Fixing up.

* Making hook throw error when context is missing.

* Fixing test filename.

* Fixing state handling in `SetProfileModal` test uncovered by change.

* Removing console statement.

* Making `useSendTelemetry` resilient against missing context.

* Handling absent context as previously.

* Disabling linter hint.

* Avoid rerendering of `MessageTableEntry` when route changes.

* Use function introduced for retrieving current path.

---------

Co-authored-by: Linus Pahl <[email protected]>
  • Loading branch information
dennisoelkers and linuspahl authored Jul 18, 2024
1 parent 1fc7f56 commit 12b41f8
Showing 1 changed file with 33 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
import * as React from 'react';
import { useContext, useMemo } from 'react';
import { useCallback, useContext, useMemo } from 'react';
import PropTypes from 'prop-types';
import * as Immutable from 'immutable';
import styled, { css } from 'styled-components';
Expand All @@ -32,9 +32,8 @@ import type MessagesWidgetConfig from 'views/logic/widgets/MessagesWidgetConfig'
import { InputsStore } from 'stores/inputs/InputsStore';
import useSendTelemetry from 'logic/telemetry/useSendTelemetry';
import { TELEMETRY_EVENT_TYPE } from 'logic/telemetry/Constants';
import { getPathnameWithoutId } from 'util/URLUtils';
import useLocation from 'routing/useLocation';
import { TableDataCell } from 'views/components/datatable';
import { getPathnameWithoutId, currentPathnameWithoutPrefix } from 'util/URLUtils';

import MessageDetail from './MessageDetail';
import DecoratedValue from './decoration/DecoratedValue';
Expand Down Expand Up @@ -113,13 +112,10 @@ const fieldType = (fieldName, { decoration_stats: decorationStats }: {
? FieldType.Decorated
: ((fields && fields.find((f) => f.name === fieldName)) || { type: FieldType.Unknown }).type);

const _renderStrong = (children, strong = false) => {
if (strong) {
return <strong>{children}</strong>;
}

return children;
};
const Strong = ({ children, strong = false }: React.PropsWithChildren<{ strong: boolean }>) => (strong
? <strong>{children}</strong>
// eslint-disable-next-line react/jsx-no-useless-fragment
: <>{children}</>);

const MessageTableEntry = ({
config,
Expand All @@ -135,56 +131,58 @@ const MessageTableEntry = ({
const { inputs: inputsList = [] } = useStore(InputsStore);
const { streams: streamsList = [] } = useStore(StreamsStore);
const highlightMessageId = useContext(HighlightMessageContext);
const location = useLocation();
const sendTelemetry = useSendTelemetry();
const additionalContextValue = useMemo(() => ({ message }), [message]);
const allStreams = Immutable.List<Stream>(streamsList);
const streams = Immutable.Map<string, Stream>(streamsList.map((stream) => [stream.id, stream]));
const inputs = Immutable.Map<string, Input>(inputsList.map((input) => [input.id, input]));
const allStreams = useMemo(() => Immutable.List<Stream>(streamsList), [streamsList]);
const streams = useMemo(() => Immutable.Map<string, Stream>(streamsList.map((stream) => [stream.id, stream])), [streamsList]);
const inputs = useMemo(() => Immutable.Map<string, Input>(inputsList.map((input) => [input.id, input])), [inputsList]);

const _toggleDetail = () => {
const _toggleDetail = useCallback(() => {
const isSelectingText = !!window.getSelection()?.toString();

if (!isSelectingText) {
sendTelemetry(TELEMETRY_EVENT_TYPE.SEARCH_MESSAGE_TABLE_DETAILS_TOGGLED, {
app_pathname: getPathnameWithoutId(location.pathname),
app_pathname: getPathnameWithoutId(currentPathnameWithoutPrefix()),
app_section: 'widget',
app_action_value: 'widget-message-table-toggle-details',
});

toggleDetail(`${message.index}-${message.id}`);
}
};
}, [message.id, message.index, sendTelemetry, toggleDetail]);

const colSpanFixup = selectedFields.size + 1;

const selectedFieldsList = useMemo(() => selectedFields.toArray().map((selectedFieldName, idx) => {
const type = fieldType(selectedFieldName, message, fields);

return (
<TableDataCell $isNumeric={type.isNumeric()} key={selectedFieldName} data-testid={`message-summary-field-${selectedFieldName}`}>
<Strong strong={idx === 0}>
<CustomHighlighting field={selectedFieldName} value={message.fields[selectedFieldName]}>
<TypeSpecificValue value={message.fields[selectedFieldName]}
field={selectedFieldName}
type={type}
render={DecoratedValue} />
</CustomHighlighting>
</Strong>
</TableDataCell>
);
}), [fields, message, selectedFields]);

const messageFieldType = useMemo(() => fieldType(MESSAGE_FIELD, message, fields), [fields, message]);

return (
<AdditionalContext.Provider value={additionalContextValue}>
<TableBody $expanded={expanded} $highlighted={message.id === highlightMessageId}>
<FieldsRow onClick={_toggleDetail}>
{selectedFields.toArray().map((selectedFieldName, idx) => {
const type = fieldType(selectedFieldName, message, fields);

return (
<TableDataCell $isNumeric={type.isNumeric()} key={selectedFieldName} data-testid={`message-summary-field-${selectedFieldName}`}>
{_renderStrong(
<CustomHighlighting field={selectedFieldName} value={message.fields[selectedFieldName]}>
<TypeSpecificValue value={message.fields[selectedFieldName]}
field={selectedFieldName}
type={type}
render={DecoratedValue} />
</CustomHighlighting>,
idx === 0,
)}
</TableDataCell>
);
})}
{selectedFieldsList}
</FieldsRow>

<MessagePreview showMessageRow={showMessageRow}
config={config}
colSpanFixup={colSpanFixup}
messageFieldType={fieldType(MESSAGE_FIELD, message, fields)}
messageFieldType={messageFieldType}
onRowClick={_toggleDetail}
message={message} />

Expand Down

0 comments on commit 12b41f8

Please sign in to comment.