diff --git a/website/src/features/toolboxes/modules/RngSimulatorModule.jsx b/website/src/features/toolboxes/modules/RngSimulatorModule.jsx index 0c741cd..918acb2 100644 --- a/website/src/features/toolboxes/modules/RngSimulatorModule.jsx +++ b/website/src/features/toolboxes/modules/RngSimulatorModule.jsx @@ -146,7 +146,8 @@ function getToneFromDelta(value) { } export function RngSimulatorModule({ toolboxId, moduleId, context, editing = false, setEditing = () => {}, textExchangeOpen }) { - const data = context.normalizeRngSimulatorData(context.getModuleData(toolboxId, moduleId, {})); + const rawData = context.getModuleData(toolboxId, moduleId, {}); + const data = useMemo(() => context.normalizeRngSimulatorData(rawData), [context, rawData]); const textContent = context.moduleText?.rngSimulator || {}; const tabs = useMemo(() => [ { ...RNG_TABS[0], label: textContent.trackingTabLabel || RNG_TABS[0].label }, diff --git a/website/src/features/toolboxes/modules/TimerModule.jsx b/website/src/features/toolboxes/modules/TimerModule.jsx index fa18b52..b65b491 100644 --- a/website/src/features/toolboxes/modules/TimerModule.jsx +++ b/website/src/features/toolboxes/modules/TimerModule.jsx @@ -31,16 +31,20 @@ import { } from "./timerOptions.js"; export function TimerModule({ toolboxId, moduleId, context, textExchangeOpen }) { - const data = context.normalizeTimerData(context.getModuleData(toolboxId, moduleId, { activeTab: "stopwatch" })); + const rawData = context.getModuleData(toolboxId, moduleId, { activeTab: "stopwatch" }); + const data = useMemo(() => context.normalizeTimerData(rawData), [context, rawData]); const textContent = context.moduleText?.timer || {}; const activeTab = data.activeTab; const [nowMs, setNowMs] = useState(getNowMs); const countdownDraft = useDraftForm(DEFAULT_COUNTDOWN_FORM); + const clockActive = Boolean(data.stopwatch.startedAt || data.countdowns.some((countdown) => countdown.autoRefresh)); + useEffect(() => { + if (!clockActive) return undefined; const intervalId = window.setInterval(() => setNowMs(getNowMs()), 50); return () => window.clearInterval(intervalId); - }, []); + }, [clockActive]); const stopwatchElapsedMs = data.stopwatch.startedAt ? data.stopwatch.elapsedMs + Math.max(0, nowMs - data.stopwatch.startedAt) diff --git a/website/src/features/toolboxes/modules/useGoalTreeController.js b/website/src/features/toolboxes/modules/useGoalTreeController.js index f64b7d2..0024ea5 100644 --- a/website/src/features/toolboxes/modules/useGoalTreeController.js +++ b/website/src/features/toolboxes/modules/useGoalTreeController.js @@ -20,7 +20,8 @@ import { } from "./goalTreeUtils.js"; export function useGoalTreeController({ toolboxId, moduleId, context, editing, setEditing, openEditor }) { - const data = context.normalizeGoalTreeData(context.getModuleData(toolboxId, moduleId, { nodes: [] })); + const rawData = context.getModuleData(toolboxId, moduleId, { nodes: [] }); + const data = useMemo(() => context.normalizeGoalTreeData(rawData), [context, rawData]); const textContent = context.moduleText?.goalTree || {}; const treeOrientation = data.orientation || "horizontal"; const verticalView = treeOrientation === "vertical";