From 6d196b4506e002552b6d9258d2c639c33f86e7b9 Mon Sep 17 00:00:00 2001 From: Marek Libra Date: Thu, 23 May 2024 11:26:40 +0200 Subject: [PATCH] fix: Avoid infinite loop in the NotificationsSidebarItem title counter Signed-off-by: Marek Libra --- .changeset/little-cooks-approve.md | 5 +++ .../src/hooks/useTitleCounter.ts | 31 ++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) create mode 100644 .changeset/little-cooks-approve.md diff --git a/.changeset/little-cooks-approve.md b/.changeset/little-cooks-approve.md new file mode 100644 index 0000000000..d4088208ae --- /dev/null +++ b/.changeset/little-cooks-approve.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications': patch +--- + +Fixes performance issue with Notifications title counter. diff --git a/plugins/notifications/src/hooks/useTitleCounter.ts b/plugins/notifications/src/hooks/useTitleCounter.ts index d794678ea6..0793cd58d6 100644 --- a/plugins/notifications/src/hooks/useTitleCounter.ts +++ b/plugins/notifications/src/hooks/useTitleCounter.ts @@ -13,38 +13,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; +import throttle from 'lodash/throttle'; + +const getPrefix = (value: number) => (value === 0 ? '' : `(${value}) `); + +const cleanTitle = (currentTitle: string) => + currentTitle.replace(/^\(\d+\)\s/, ''); + +const throttledSetTitle = throttle((shownTitle: string) => { + document.title = shownTitle; +}, 100); /** @public */ export function useTitleCounter() { const [title, setTitle] = useState(document.title); const [count, setCount] = useState(0); - const titleTimer = useRef(undefined); - - const getPrefix = (value: number) => { - return value === 0 ? '' : `(${value}) `; - }; - - const cleanTitle = (currentTitle: string) => { - return currentTitle.replace(/^\(\d+\)\s/, ''); - }; useEffect(() => { const baseTitle = cleanTitle(title); const shownTitle = `${getPrefix(count)}${baseTitle}`; if (document.title !== shownTitle) { - window.clearTimeout(titleTimer.current); - document.title = shownTitle; - // Need to do this in timeout as the React Helmet overrides the title after this effect - titleTimer.current = window.setTimeout(() => { - document.title = shownTitle; - }, 50); + throttledSetTitle(shownTitle); } return () => { - window.clearTimeout(titleTimer.current); document.title = cleanTitle(title); }; - }, [title, count]); + }, [count, title]); useEffect(() => { const titleElement = document.querySelector('title');