feat: optimize LongInput component with memoization and local state management

This commit is contained in:
ecwu
2025-01-26 21:39:23 +00:00
parent d51c283e55
commit 3b17ca791b

View File

@@ -1,7 +1,8 @@
import { themeChange } from "theme-change"; import { themeChange } from "theme-change";
import { useRef } from "react"; import { useRef, useCallback } from "react";
import { useContext, useEffect, useState, Dispatch } from "react"; import { useContext, useEffect, useState, Dispatch } from "react";
import React from "react";
import { clearTotalCost, getTotalCost } from "@/utils/totalCost"; import { clearTotalCost, getTotalCost } from "@/utils/totalCost";
import { ChatStore, TemplateChatStore, TemplateTools } from "@/types/chatstore"; import { ChatStore, TemplateChatStore, TemplateTools } from "@/types/chatstore";
import { models } from "@/types/models"; import { models } from "@/types/models";
@@ -179,46 +180,70 @@ const SelectModel = (props: { help: string }) => {
); );
}; };
const LongInput = (props: { const LongInput = React.memo(
field: "systemMessageContent" | "toolsString"; (props: {
label: string; field: "systemMessageContent" | "toolsString";
help: string; label: string;
}) => { help: string;
const { chatStore, setChatStore } = useContext(AppChatStoreContext); }) => {
return ( const { chatStore, setChatStore } = useContext(AppChatStoreContext);
<div> const textareaRef = useRef<HTMLTextAreaElement>(null);
<Label htmlFor="name" className="text-right"> const [localValue, setLocalValue] = useState(chatStore[props.field]);
{props.label}{" "}
<Dialog>
<DialogTrigger asChild>
<Button variant="ghost" size="icon">
<InfoIcon />
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>{props.label} Help</DialogTitle>
</DialogHeader>
{props.help}
</DialogContent>
</Dialog>
</Label>
<Textarea // Update height when value changes
className="h-24 w-full" useEffect(() => {
value={chatStore[props.field]} if (textareaRef.current) {
onBlur={async (event: any) => { autoHeight(textareaRef.current);
chatStore[props.field] = event.target.value; }
await setChatStore({ ...chatStore }); }, [localValue]);
autoHeight(event.target);
}} // Sync local value with chatStore when it changes externally
onKeyPress={(event: any) => { useEffect(() => {
autoHeight(event.target); setLocalValue(chatStore[props.field]);
}} }, [chatStore[props.field]]);
/>
</div> const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
); setLocalValue(event.target.value);
}; };
const handleBlur = () => {
if (localValue !== chatStore[props.field]) {
chatStore[props.field] = localValue;
setChatStore({ ...chatStore });
}
};
return (
<div>
<Label htmlFor="name" className="text-right">
{props.label}{" "}
<Dialog>
<DialogTrigger asChild>
<Button variant="ghost" size="icon">
<InfoIcon />
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>{props.label} Help</DialogTitle>
</DialogHeader>
{props.help}
</DialogContent>
</Dialog>
</Label>
<Textarea
ref={textareaRef}
mockOnChange={false}
className="h-24 w-full"
value={localValue}
onChange={handleChange}
onBlur={handleBlur}
/>
</div>
);
}
);
const InputField = (props: { const InputField = (props: {
field: field: