From 48cf79e6f103141bf3154909a44943a2caa1b066 Mon Sep 17 00:00:00 2001 From: SethBurkart123 Date: Thu, 28 Mar 2024 07:13:22 +1100 Subject: [PATCH] performance improvements to shortcuts and tab container components --- src/interface/components/TabbedContainer.tsx | 32 ++-- src/interface/pages/Shortcuts.tsx | 150 +++++++++---------- 2 files changed, 88 insertions(+), 94 deletions(-) diff --git a/src/interface/components/TabbedContainer.tsx b/src/interface/components/TabbedContainer.tsx index 9e1b3f5e..9aa3ed3e 100644 --- a/src/interface/components/TabbedContainer.tsx +++ b/src/interface/components/TabbedContainer.tsx @@ -54,7 +54,7 @@ const TabbedContainer: React.FC = ({ tabs }) => { }; return ( - <> + <>
= ({ tabs }) => {
- - {tabs.map((tab, index) => ( -
- {tab.content} -
- ))} -
-
- + + {tabs.map((tab, index) => ( +
+ {tab.content} +
+ ))} +
+ + ); }; diff --git a/src/interface/pages/Shortcuts.tsx b/src/interface/pages/Shortcuts.tsx index 167ecd82..5771d369 100644 --- a/src/interface/pages/Shortcuts.tsx +++ b/src/interface/pages/Shortcuts.tsx @@ -1,50 +1,44 @@ -import { useState, memo } from "react"; +import { useState, memo, useCallback } from "react"; import Switch from "../components/Switch"; import { useSettingsContext } from "../SettingsContext"; import { motion, AnimatePresence } from "framer-motion"; import { CustomShortcut } from "../types/AppProps"; -function formatUrl (inputUrl: string) { - // Regular expression to check if the URL starts with http://, https://, or ftp:// +function formatUrl(inputUrl: string) { const protocolRegex = /^(http:\/\/|https:\/\/|ftp:\/\/)/; - - // Check if the URL starts with one of the protocols - if (protocolRegex.test(inputUrl)) { - return inputUrl; // The URL is fine as is - } else { - return `https://${inputUrl}`; // Prepend https:// to the URL - } + return protocolRegex.test(inputUrl) ? inputUrl : `https://${inputUrl}`; } -function Shortcuts() { +const Shortcuts = memo(() => { const { settingsState, setSettingsState } = useSettingsContext(); - const switchChange = (shortcutName: string, isOn: boolean): void => { - const updatedShortcuts = settingsState.shortcuts.map((shortcut) => { - if (shortcut.name === shortcutName) { - return { ...shortcut, enabled: isOn }; - } - return shortcut; - }); - - setSettingsState({ ...settingsState, shortcuts: updatedShortcuts }); - }; - const [newTitle, setNewTitle] = useState(""); + const [isFormVisible, setFormVisible] = useState(false); const [newURL, setNewURL] = useState(""); - const isValidTitle = (title: string): boolean => title.trim() !== ""; - const isValidURL = (url: string): boolean => { + const switchChange = useCallback((shortcutName: string, isOn: boolean) => { + setSettingsState((prevState) => { + const updatedShortcuts = prevState.shortcuts.map((shortcut) => + shortcut.name === shortcutName ? { ...shortcut, enabled: isOn } : shortcut + ); + return { ...prevState, shortcuts: updatedShortcuts }; + }); + }, [setSettingsState]); + + const isValidTitle = useCallback((title: string) => title.trim() !== "", []); + + const isValidURL = useCallback((url: string) => { const pattern = new RegExp("^(https?:\\/\\/)?[\\w.-]+[\\w.-]+(/[\\w.-]*)*$", "i"); return pattern.test(url); - }; + }, []); - const addNewCustomShortcut = (): void => { + const addNewCustomShortcut = useCallback(() => { if (isValidTitle(newTitle) && isValidURL(newURL)) { const newShortcut: CustomShortcut = { name: newTitle.trim(), url: formatUrl(newURL).trim(), icon: newTitle[0] }; const updatedCustomShortcuts = [...settingsState.customshortcuts, newShortcut]; - setSettingsState({ ...settingsState, customshortcuts: updatedCustomShortcuts }); + setSettingsState(prevState => ({ ...prevState, updatedCustomShortcuts })); + setNewTitle(""); setNewURL(""); @@ -53,18 +47,18 @@ function Shortcuts() { // Replace with a more user-friendly way to display errors console.error("Please enter a valid title and URL."); } - }; + }, [newTitle, newURL, isValidTitle, isValidURL, setSettingsState]); - const deleteCustomShortcut = (index: number): void => { - const updatedCustomShortcuts = settingsState.customshortcuts.filter((_, i) => i !== index); - setSettingsState({ ...settingsState, customshortcuts: updatedCustomShortcuts }); - }; + const deleteCustomShortcut = useCallback((index: number) => { + setSettingsState((prevState) => ({ + ...prevState, + customshortcuts: prevState.customshortcuts.filter((_, i) => i !== index), + })); + }, [setSettingsState]); - const [isFormVisible, setFormVisible] = useState(false); - - const toggleForm = () => { - setFormVisible(!isFormVisible); - }; + const toggleForm = useCallback(() => { + setFormVisible((isVisible) => !isVisible); + }, []); return (
@@ -77,48 +71,48 @@ function Shortcuts() { transition={{ type: "spring", damping: 20 }} > {isFormVisible && -
- setNewTitle(e.target.value)} - /> - setNewURL(e.target.value)} - /> - - Add - -
+
+ setNewTitle(e.target.value)} + /> + setNewURL(e.target.value)} + /> + + Add + +
} - {!isFormVisible && ( - - )} + {!isFormVisible && ( + + )} {/* Shortcuts Section */} {settingsState.shortcuts ? ( @@ -149,6 +143,6 @@ function Shortcuts() { )}
); -} +}); -export default memo(Shortcuts); \ No newline at end of file +export default Shortcuts; \ No newline at end of file