From 12b41f8b1e8f32f1bb168772b4934890cdc33669 Mon Sep 17 00:00:00 2001 From: Dennis Oelkers Date: Thu, 18 Jul 2024 11:58:29 +0200 Subject: [PATCH] Avoid unnecessary rerendering of `MessageTableEntry` component. (#19899) * 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 --- .../messagelist/MessageTableEntry.tsx | 68 +++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/graylog2-web-interface/src/views/components/messagelist/MessageTableEntry.tsx b/graylog2-web-interface/src/views/components/messagelist/MessageTableEntry.tsx index b39cbde0e943..441e3788d666 100644 --- a/graylog2-web-interface/src/views/components/messagelist/MessageTableEntry.tsx +++ b/graylog2-web-interface/src/views/components/messagelist/MessageTableEntry.tsx @@ -15,7 +15,7 @@ * . */ 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'; @@ -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'; @@ -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 {children}; - } - - return children; -}; +const Strong = ({ children, strong = false }: React.PropsWithChildren<{ strong: boolean }>) => (strong + ? {children} + // eslint-disable-next-line react/jsx-no-useless-fragment + : <>{children}); const MessageTableEntry = ({ config, @@ -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(streamsList); - const streams = Immutable.Map(streamsList.map((stream) => [stream.id, stream])); - const inputs = Immutable.Map(inputsList.map((input) => [input.id, input])); + const allStreams = useMemo(() => Immutable.List(streamsList), [streamsList]); + const streams = useMemo(() => Immutable.Map(streamsList.map((stream) => [stream.id, stream])), [streamsList]); + const inputs = useMemo(() => Immutable.Map(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 ( + + + + + + + + ); + }), [fields, message, selectedFields]); + + const messageFieldType = useMemo(() => fieldType(MESSAGE_FIELD, message, fields), [fields, message]); + return ( - {selectedFields.toArray().map((selectedFieldName, idx) => { - const type = fieldType(selectedFieldName, message, fields); - - return ( - - {_renderStrong( - - - , - idx === 0, - )} - - ); - })} + {selectedFieldsList}