From b1e6663c66a3957818e32c0d086b017367c80efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Mon, 8 Jul 2024 15:06:22 +0200 Subject: [PATCH 1/8] frontend: introduces useRenderCount hook The useRenderCount hook contains all the necessary logic to count the re-render events. This reduces duplication and code complexity. --- frontend/src/components/AsyncMethodComponent.tsx | 8 +++----- frontend/src/components/ButtonComponent.tsx | 13 ++++--------- frontend/src/components/DictComponent.tsx | 13 ++++--------- frontend/src/components/EnumComponent.tsx | 13 ++++--------- frontend/src/components/ImageComponent.tsx | 11 ++++------- frontend/src/components/ListComponent.tsx | 13 ++++--------- frontend/src/components/MethodComponent.tsx | 11 +++-------- frontend/src/components/NumberComponent.tsx | 9 ++++----- frontend/src/components/SliderComponent.tsx | 13 ++++--------- frontend/src/components/StringComponent.tsx | 13 ++++--------- frontend/src/hooks/useRenderCount.ts | 11 +++++++++++ 11 files changed, 49 insertions(+), 79 deletions(-) create mode 100644 frontend/src/hooks/useRenderCount.ts diff --git a/frontend/src/components/AsyncMethodComponent.tsx b/frontend/src/components/AsyncMethodComponent.tsx index 41c5904..19f4f91 100644 --- a/frontend/src/components/AsyncMethodComponent.tsx +++ b/frontend/src/components/AsyncMethodComponent.tsx @@ -3,6 +3,7 @@ import { runMethod } from "../socket"; import { Form, Button, InputGroup, Spinner } from "react-bootstrap"; import { DocStringComponent } from "./DocStringComponent"; import { LevelName } from "./NotificationsComponent"; +import { useRenderCount } from "../hooks/useRenderCount"; interface AsyncMethodProps { fullAccessPath: string; @@ -30,14 +31,13 @@ export const AsyncMethodComponent = React.memo((props: AsyncMethodProps) => { return null; } - const renderCount = useRef(0); + const renderCount = useRenderCount(); const formRef = useRef(null); const [spinning, setSpinning] = useState(false); const name = fullAccessPath.split(".").at(-1)!; const parentPath = fullAccessPath.slice(0, -(name.length + 1)); useEffect(() => { - renderCount.current++; let message: string; if (runningTask === null) { @@ -66,9 +66,7 @@ export const AsyncMethodComponent = React.memo((props: AsyncMethodProps) => { return (
- {process.env.NODE_ENV === "development" && ( -
Render count: {renderCount.current}
- )} + {process.env.NODE_ENV === "development" &&
Render count: {renderCount}
}
diff --git a/frontend/src/components/ButtonComponent.tsx b/frontend/src/components/ButtonComponent.tsx index 97f0ce0..f23bee5 100644 --- a/frontend/src/components/ButtonComponent.tsx +++ b/frontend/src/components/ButtonComponent.tsx @@ -1,8 +1,9 @@ -import React, { useEffect, useRef } from "react"; +import React, { useEffect } from "react"; import { ToggleButton } from "react-bootstrap"; import { DocStringComponent } from "./DocStringComponent"; import { LevelName } from "./NotificationsComponent"; import { SerializedObject } from "../types/SerializedObject"; +import { useRenderCount } from "../hooks/useRenderCount"; interface ButtonComponentProps { fullAccessPath: string; @@ -29,11 +30,7 @@ export const ButtonComponent = React.memo((props: ButtonComponentProps) => { } = props; // const buttonName = props.mapping ? (value ? props.mapping[0] : props.mapping[1]) : name; - const renderCount = useRef(0); - - useEffect(() => { - renderCount.current++; - }); + const renderCount = useRenderCount(); useEffect(() => { addNotification(`${fullAccessPath} changed to ${value}.`); @@ -51,9 +48,7 @@ export const ButtonComponent = React.memo((props: ButtonComponentProps) => { return (
- {process.env.NODE_ENV === "development" && ( -
Render count: {renderCount.current}
- )} + {process.env.NODE_ENV === "development" &&
Render count: {renderCount}
} ; @@ -15,18 +16,12 @@ interface DictComponentProps { export const DictComponent = React.memo((props: DictComponentProps) => { const { value, docString, isInstantUpdate, addNotification, id } = props; - const renderCount = useRef(0); + const renderCount = useRenderCount(); const valueArray = Object.values(value); - useEffect(() => { - renderCount.current++; - }, [props]); - return (
- {process.env.NODE_ENV === "development" && ( -
Render count: {renderCount.current}
- )} + {process.env.NODE_ENV === "development" &&
Render count: {renderCount}
} {valueArray.map((item) => { return ( diff --git a/frontend/src/components/EnumComponent.tsx b/frontend/src/components/EnumComponent.tsx index b674c2c..5ddf26d 100644 --- a/frontend/src/components/EnumComponent.tsx +++ b/frontend/src/components/EnumComponent.tsx @@ -1,8 +1,9 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect } from "react"; import { InputGroup, Form, Row, Col } from "react-bootstrap"; import { DocStringComponent } from "./DocStringComponent"; import { LevelName } from "./NotificationsComponent"; import { SerializedObject } from "../types/SerializedObject"; +import { useRenderCount } from "../hooks/useRenderCount"; export interface EnumSerialization { type: "Enum" | "ColouredEnum"; @@ -40,12 +41,8 @@ export const EnumComponent = React.memo((props: EnumComponentProps) => { }); }; } - const renderCount = useRef(0); const [enumValue, setEnumValue] = useState(value); - - useEffect(() => { - renderCount.current++; - }); + const renderCount = useRenderCount(); useEffect(() => { setEnumValue(() => { @@ -56,9 +53,7 @@ export const EnumComponent = React.memo((props: EnumComponentProps) => { return (
- {process.env.NODE_ENV === "development" && ( -
Render count: {renderCount.current}
- )} + {process.env.NODE_ENV === "development" &&
Render count: {renderCount}
} diff --git a/frontend/src/components/ImageComponent.tsx b/frontend/src/components/ImageComponent.tsx index b076213..97c733d 100644 --- a/frontend/src/components/ImageComponent.tsx +++ b/frontend/src/components/ImageComponent.tsx @@ -1,8 +1,9 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect, useState } from "react"; import { Card, Collapse, Image } from "react-bootstrap"; import { DocStringComponent } from "./DocStringComponent"; import { ChevronDown, ChevronRight } from "react-bootstrap-icons"; import { LevelName } from "./NotificationsComponent"; +import { useRenderCount } from "../hooks/useRenderCount"; interface ImageComponentProps { fullAccessPath: string; @@ -18,13 +19,9 @@ export const ImageComponent = React.memo((props: ImageComponentProps) => { const { fullAccessPath, value, docString, format, addNotification, displayName, id } = props; - const renderCount = useRef(0); + const renderCount = useRenderCount(); const [open, setOpen] = useState(true); - useEffect(() => { - renderCount.current++; - }); - useEffect(() => { addNotification(`${fullAccessPath} changed.`); }, [props.value]); @@ -43,7 +40,7 @@ export const ImageComponent = React.memo((props: ImageComponentProps) => { {process.env.NODE_ENV === "development" && ( -

Render count: {renderCount.current}

+

Render count: {renderCount}

)} {format === "" && value === "" ? (

No image set in the backend.

diff --git a/frontend/src/components/ListComponent.tsx b/frontend/src/components/ListComponent.tsx index 7d00041..3801ea7 100644 --- a/frontend/src/components/ListComponent.tsx +++ b/frontend/src/components/ListComponent.tsx @@ -1,8 +1,9 @@ -import React, { useEffect, useRef } from "react"; +import React from "react"; import { DocStringComponent } from "./DocStringComponent"; import { GenericComponent } from "./GenericComponent"; import { LevelName } from "./NotificationsComponent"; import { SerializedObject } from "../types/SerializedObject"; +import { useRenderCount } from "../hooks/useRenderCount"; interface ListComponentProps { value: SerializedObject[]; @@ -15,17 +16,11 @@ interface ListComponentProps { export const ListComponent = React.memo((props: ListComponentProps) => { const { value, docString, isInstantUpdate, addNotification, id } = props; - const renderCount = useRef(0); - - useEffect(() => { - renderCount.current++; - }, [props]); + const renderCount = useRenderCount(); return (
- {process.env.NODE_ENV === "development" && ( -
Render count: {renderCount.current}
- )} + {process.env.NODE_ENV === "development" &&
Render count: {renderCount}
} {value.map((item) => { return ( diff --git a/frontend/src/components/MethodComponent.tsx b/frontend/src/components/MethodComponent.tsx index db23b8a..46e4d98 100644 --- a/frontend/src/components/MethodComponent.tsx +++ b/frontend/src/components/MethodComponent.tsx @@ -3,6 +3,7 @@ import { runMethod } from "../socket"; import { Button, Form } from "react-bootstrap"; import { DocStringComponent } from "./DocStringComponent"; import { LevelName } from "./NotificationsComponent"; +import { useRenderCount } from "../hooks/useRenderCount"; interface MethodProps { fullAccessPath: string; @@ -21,7 +22,7 @@ export const MethodComponent = React.memo((props: MethodProps) => { return null; } - const renderCount = useRef(0); + const renderCount = useRenderCount(); const formRef = useRef(null); const triggerNotification = () => { @@ -37,15 +38,9 @@ export const MethodComponent = React.memo((props: MethodProps) => { triggerNotification(); }; - useEffect(() => { - renderCount.current++; - }); - return (
- {process.env.NODE_ENV === "development" && ( -
Render count: {renderCount.current}
- )} + {process.env.NODE_ENV === "development" &&
Render count: {renderCount}
}