diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 1d544ea..67f29cc 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -12,6 +12,7 @@ import { setNestedValueByPath, State } from "./utils/stateUtils"; import { WebSettingsContext, WebSetting } from "./WebSettings"; import { GenericComponent } from "./components/GenericComponent"; import { SerializedObject } from "./types/SerializedObject"; +import useLocalStorage from "./hooks/useLocalStorage"; type Action = | { type: "SET_DATA"; data: State } @@ -53,15 +54,15 @@ const App = () => { const [state, dispatch] = useReducer(reducer, null); const [serviceName, setServiceName] = useState(null); const [webSettings, setWebSettings] = useState>({}); - const [isInstantUpdate, setIsInstantUpdate] = useState(() => { - const saved = localStorage.getItem("isInstantUpdate"); - return saved !== null ? JSON.parse(saved) : false; - }); + const [isInstantUpdate, setIsInstantUpdate] = useLocalStorage( + "isInstantUpdate", + false, + ); const [showSettings, setShowSettings] = useState(false); - const [showNotification, setShowNotification] = useState(() => { - const saved = localStorage.getItem("showNotification"); - return saved !== null ? JSON.parse(saved) : false; - }); + const [showNotification, setShowNotification] = useLocalStorage( + "showNotification", + false, + ); const [notifications, setNotifications] = useState([]); const [connectionStatus, setConnectionStatus] = useState("connecting"); @@ -115,14 +116,6 @@ const App = () => { }; }, []); - // Persist isInstantUpdate and showNotification state changes to localStorage - useEffect(() => { - localStorage.setItem("isInstantUpdate", JSON.stringify(isInstantUpdate)); - }, [isInstantUpdate]); - - useEffect(() => { - localStorage.setItem("showNotification", JSON.stringify(showNotification)); - }, [showNotification]); // Adding useCallback to prevent notify to change causing a re-render of all // components const addNotification = useCallback( diff --git a/frontend/src/components/DataServiceComponent.tsx b/frontend/src/components/DataServiceComponent.tsx index be22c3c..dfe7092 100644 --- a/frontend/src/components/DataServiceComponent.tsx +++ b/frontend/src/components/DataServiceComponent.tsx @@ -1,10 +1,10 @@ -import { useEffect, useState } from "react"; import React from "react"; import { Card, Collapse } from "react-bootstrap"; import { ChevronDown, ChevronRight } from "react-bootstrap-icons"; import { GenericComponent } from "./GenericComponent"; import { LevelName } from "./NotificationsComponent"; import { SerializedObject } from "../types/SerializedObject"; +import useLocalStorage from "../hooks/useLocalStorage"; interface DataServiceProps { props: DataServiceJSON; @@ -19,15 +19,7 @@ export type DataServiceJSON = Record; export const DataServiceComponent = React.memo( ({ props, isInstantUpdate, addNotification, displayName, id }: DataServiceProps) => { // Retrieve the initial state from localStorage, default to true if not found - const [open, setOpen] = useState(() => { - const savedState = localStorage.getItem(`dataServiceComponent-${id}-open`); - return savedState !== null ? JSON.parse(savedState) : true; - }); - - // Update localStorage whenever the state changes - useEffect(() => { - localStorage.setItem(`dataServiceComponent-${id}-open`, JSON.stringify(open)); - }, [open]); + const [open, setOpen] = useLocalStorage(`dataServiceComponent-${id}-open`, true); if (displayName !== "") { return ( diff --git a/frontend/src/hooks/useLocalStorage.ts b/frontend/src/hooks/useLocalStorage.ts new file mode 100644 index 0000000..4775919 --- /dev/null +++ b/frontend/src/hooks/useLocalStorage.ts @@ -0,0 +1,18 @@ +import { useState, useEffect } from "react"; + +export default function useLocalStorage(key: string, defaultValue: unknown) { + const [value, setValue] = useState(() => { + const storedValue = localStorage.getItem(key); + if (storedValue) { + return JSON.parse(storedValue); + } + return defaultValue; + }); + + useEffect(() => { + if (value === undefined) return; + localStorage.setItem(key, JSON.stringify(value)); + }, [value, key]); + + return [value, setValue]; +}