From 1b1b9a2874aea63fd2436d0e8d55b413952c4d1e Mon Sep 17 00:00:00 2001
From: deep1401 <gandhi0869@gmail.com>
Date: Wed, 26 Feb 2025 10:06:52 -0800
Subject: [PATCH] UseMemo to eliminate the usage of useEffect and correct minor
 bug which happens when setting some tasks in AutoComplete

---
 .../Experiment/DynamicPluginForm.tsx          |  8 ++-
 .../Widgets/CustomEvaluationWidget.tsx        | 72 +++++++------------
 2 files changed, 33 insertions(+), 47 deletions(-)

diff --git a/src/renderer/components/Experiment/DynamicPluginForm.tsx b/src/renderer/components/Experiment/DynamicPluginForm.tsx
index 81adccf3..a2455bad 100644
--- a/src/renderer/components/Experiment/DynamicPluginForm.tsx
+++ b/src/renderer/components/Experiment/DynamicPluginForm.tsx
@@ -422,7 +422,13 @@ function CustomAutocompleteWidget<T = any, S extends StrictRJSFSchema = RJSFSche
   // Determine default value.
   const defaultValue = _multiple ? [] : '';
   // Use the provided value or fallback to default.
-  const currentValue = value !== undefined ? value : defaultValue;
+  let currentValue = value !== undefined ? value : defaultValue;
+
+  // Check if currentValue is an array, if a string, convert it to an array.
+  const isString = typeof currentValue === 'string';
+  if (isString) {
+    currentValue = currentValue.split(',');
+  }
 
   // Map enumOptions into objects with label and value.
   const processedOptionsValues = enumOptions.map((opt) =>
diff --git a/src/renderer/components/Experiment/Widgets/CustomEvaluationWidget.tsx b/src/renderer/components/Experiment/Widgets/CustomEvaluationWidget.tsx
index 6adac389..2ffc64ca 100644
--- a/src/renderer/components/Experiment/Widgets/CustomEvaluationWidget.tsx
+++ b/src/renderer/components/Experiment/Widgets/CustomEvaluationWidget.tsx
@@ -1,12 +1,6 @@
 import React from 'react';
 import { WidgetProps } from '@rjsf/core';
-import {
-  Button,
-  Input,
-  Select,
-  Option,
-} from '@mui/joy';
-
+import { Button, Input, Select, Option } from '@mui/joy';
 
 type EvaluationField = {
   name: string;
@@ -14,55 +8,44 @@ type EvaluationField = {
   return_type: string;
 };
 
-
-const CustomEvaluationWidget = (props: WidgetProps<any>) => {
-  const { id, value, onChange, disabled, readonly } = props;
-
-
-  const parseValue = (val: any): EvaluationField[] => {
-    if (Array.isArray(val)) {
-      if (val.every(item => typeof item === "string")) {
-        // If every element is a string: join them and parse the result.
-        try {
-          const joined = val.join(',');
-          const parsed = JSON.parse(joined);
-          return Array.isArray(parsed) ? parsed : [];
-        } catch (err) {
-          console.error("Error parsing evaluation widget value:", err);
-          return [];
-        }
-      } else {
-        // If not all elements are strings, assume it's already an array of EvaluationField.
-        return val;
-      }
-    } else if (typeof val === "string") {
+const parseValue = (val: any): EvaluationField[] => {
+  if (Array.isArray(val)) {
+    if (val.every(item => typeof item === "string")) {
+      // If every element is a string: join them and parse the result.
       try {
-        return JSON.parse(val);
+        const joined = val.join(',');
+        const parsed = JSON.parse(joined);
+        return Array.isArray(parsed) ? parsed : [];
       } catch (err) {
-        console.error("Error parsing evaluation widget value string:", err);
+        console.error("Error parsing evaluation widget value:", err);
         return [];
       }
+    } else {
+      // If not all elements are strings, assume it's already an array of EvaluationField.
+      return val;
     }
-    return [];
-  };
-
-  const [evalMetrics, setEvalMetrics] = React.useState<EvaluationField[]>(parseValue(value));
+  } else if (typeof val === "string") {
+    try {
+      return JSON.parse(val);
+    } catch (err) {
+      console.error("Error parsing evaluation widget value string:", err);
+      return [];
+    }
+  }
+  return [];
+};
 
+const CustomEvaluationWidget = (props: WidgetProps<any>) => {
+  const { id, value, onChange, disabled, readonly } = props;
 
-   // Update state if a new default value is provided
-   React.useEffect(() => {
-    const parsed = parseValue(value);
-    if (JSON.stringify(parsed) !== JSON.stringify(evalMetrics) && parsed.length > 0) {
-      setEvalMetrics(parsed);
-    }
-  }, [value]);
+  // Directly derive evaluation metrics from the value prop.
+  const evalMetrics: EvaluationField[] = React.useMemo(() => parseValue(value), [value]);
 
   const handleAddField = () => {
     const updatedMetrics = [
       ...evalMetrics,
       { name: '', expression: '', return_type: 'boolean' }
     ];
-    setEvalMetrics(updatedMetrics);
     onChange(updatedMetrics);
   };
 
@@ -74,13 +57,11 @@ const CustomEvaluationWidget = (props: WidgetProps<any>) => {
     const updated = evalMetrics.map((evaluation, i) =>
       i === index ? { ...evaluation, [field]: newValue } : evaluation
     );
-    setEvalMetrics(updated);
     onChange(updated);
   };
 
   const handleRemoveField = (index: number) => {
     const updated = evalMetrics.filter((_, i) => i !== index);
-    setEvalMetrics(updated);
     onChange(updated);
   };
 
@@ -126,7 +107,6 @@ const CustomEvaluationWidget = (props: WidgetProps<any>) => {
             <Option value="number">Number</Option>
             <Option value="contains">Contains</Option>
             <Option value="isequal">IsEqual</Option>
-
           </Select>
           <Button
             onClick={() => handleRemoveField(index)}
-- 
GitLab