From 4fa5c14734573011befd7973fb686419f103c8c2 Mon Sep 17 00:00:00 2001 From: Jing Hua Date: Sun, 5 Mar 2023 22:59:31 +0800 Subject: [PATCH] feat: performance optimisation fixes partially #9 and #16 --- src/App.tsx | 12 +- .../Chat/ChatContent/ChatContent.tsx | 23 +- .../Chat/ChatContent/Message/Message.tsx | 85 +++-- .../ChatContent/Message/MessageContent.tsx | 324 +++++++++--------- .../ChatContent/Message/NewMessageButton.tsx | 108 +++--- .../Chat/ChatContent/Message/RoleSelector.tsx | 20 +- src/components/ConfigMenu/ConfigMenu.tsx | 15 +- src/components/Menu/ChatHistoryList.tsx | 22 +- src/components/Menu/Menu.tsx | 1 - src/components/Menu/MenuOptions/Config.tsx | 6 +- src/components/Menu/NewChat.tsx | 10 - src/components/MobileBar/MobileBar.tsx | 16 +- src/hooks/useAddChat.ts | 12 +- src/hooks/useInitialiseNewChat.ts | 8 +- src/hooks/useSaveToLocalStorage.ts | 15 +- src/hooks/useSubmit.ts | 58 ++-- src/hooks/useUpdateChats.ts | 25 -- 17 files changed, 350 insertions(+), 410 deletions(-) delete mode 100644 src/hooks/useUpdateChats.ts diff --git a/src/App.tsx b/src/App.tsx index 46bd5ee..6ae955b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,38 +6,30 @@ import Menu from './components/Menu'; import ConfigMenu from './components/ConfigMenu'; import useSaveToLocalStorage from '@hooks/useSaveToLocalStorage'; -import useUpdateCharts from '@hooks/useUpdateChats'; import useInitialiseNewChat from '@hooks/useInitialiseNewChat'; import { ChatInterface } from '@type/chat'; function App() { useSaveToLocalStorage(); - useUpdateCharts(); const initialiseNewChat = useInitialiseNewChat(); - const [setChats, setMessages, setCurrentChatIndex] = useStore((state) => [ - state.setChats, - state.setMessages, - state.setCurrentChatIndex, - ]); + const setChats = useStore((state) => state.setChats); + const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex); useEffect(() => { - // localStorage.removeItem('chats'); const storedChats = localStorage.getItem('chats'); if (storedChats) { try { const chats: ChatInterface[] = JSON.parse(storedChats); if (chats.length > 0) { setChats(chats); - setMessages(chats[0].messages); setCurrentChatIndex(0); } else { initialiseNewChat(); } } catch (e: unknown) { setChats([]); - setMessages([]); setCurrentChatIndex(-1); console.log(e); } diff --git a/src/components/Chat/ChatContent/ChatContent.tsx b/src/components/Chat/ChatContent/ChatContent.tsx index e7e96ca..a93f611 100644 --- a/src/components/Chat/ChatContent/ChatContent.tsx +++ b/src/components/Chat/ChatContent/ChatContent.tsx @@ -1,4 +1,4 @@ -import React, { createRef, useState } from 'react'; +import React from 'react'; import ScrollToBottom from 'react-scroll-to-bottom'; import useStore from '@store/store'; @@ -11,11 +11,15 @@ import CrossIcon from '@icon/CrossIcon'; import useSubmit from '@hooks/useSubmit'; const ChatContent = () => { - const [messages, inputRole, setError] = useStore((state) => [ - state.messages, - state.inputRole, - state.setError, - ]); + const inputRole = useStore((state) => state.inputRole); + const setError = useStore((state) => state.setError); + const messages = useStore((state) => + state.chats ? state.chats[state.currentChatIndex].messages : [] + ); + const stickyIndex = useStore((state) => + state.chats ? state.chats[state.currentChatIndex].messages.length : 0 + ); + const { handleSubmit, error } = useSubmit(); return ( @@ -38,7 +42,12 @@ const ChatContent = () => { ))} - + {error !== '' && (
diff --git a/src/components/Chat/ChatContent/Message/Message.tsx b/src/components/Chat/ChatContent/Message/Message.tsx index f7cdc5d..872cad7 100644 --- a/src/components/Chat/ChatContent/Message/Message.tsx +++ b/src/components/Chat/ChatContent/Message/Message.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import useStore from '@store/store'; import Avatar from './Avatar'; import MessageContent from './MessageContent'; @@ -14,50 +13,48 @@ import RoleSelector from './RoleSelector'; // }; const backgroundStyle = ['dark:bg-gray-800', 'bg-gray-50 dark:bg-[#444654]']; -const Message = ({ - role, - content, - messageIndex, - sticky = false, -}: { - role: Role; - content: string; - messageIndex: number; - sticky?: boolean; -}) => { - const stickyIndex = useStore((state) => state.messages.length); - - return ( -
-
- -
- - +const Message = React.memo( + ({ + role, + content, + messageIndex, + sticky = false, + }: { + role: Role; + content: string; + messageIndex: number; + sticky?: boolean; + }) => { + return ( +
+
+ +
+ + +
-
- ); -}; + ); + } +); export default Message; diff --git a/src/components/Chat/ChatContent/Message/MessageContent.tsx b/src/components/Chat/ChatContent/Message/MessageContent.tsx index 21c6e7b..70f1e3f 100644 --- a/src/components/Chat/ChatContent/Message/MessageContent.tsx +++ b/src/components/Chat/ChatContent/Message/MessageContent.tsx @@ -17,7 +17,7 @@ import DownChevronArrow from '@icon/DownChevronArrow'; import useSubmit from '@hooks/useSubmit'; -import { MessageInterface } from '@type/chat'; +import { ChatInterface } from '@type/chat'; import PopupModal from '@components/PopupModal'; @@ -56,158 +56,168 @@ const MessageContent = ({ ); }; -const ContentView = ({ - role, - content, - setIsEdit, - messageIndex, -}: { - role: string; - content: string; - setIsEdit: React.Dispatch>; - messageIndex: number; -}) => { - const { handleSubmit, error } = useSubmit(); +const ContentView = React.memo( + ({ + role, + content, + setIsEdit, + messageIndex, + }: { + role: string; + content: string; + setIsEdit: React.Dispatch>; + messageIndex: number; + }) => { + const { handleSubmit } = useSubmit(); - const [isDelete, setIsDelete] = useState(false); - const [copied, setCopied] = useState(false); + const [isDelete, setIsDelete] = useState(false); + const [copied, setCopied] = useState(false); + const currentChatIndex = useStore((state) => state.currentChatIndex); + const setChats = useStore((state) => state.setChats); + const lastMessageIndex = useStore((state) => + state.chats ? state.chats[state.currentChatIndex].messages.length - 1 : 0 + ); - const [messages, setMessages] = useStore((state) => [ - state.messages, - state.setMessages, - ]); + const handleDelete = () => { + const updatedChats: ChatInterface[] = JSON.parse( + JSON.stringify(useStore.getState().chats) + ); + updatedChats[currentChatIndex].messages.splice(messageIndex, 1); + setChats(updatedChats); + }; - const handleDelete = () => { - const updatedMessages = JSON.parse(JSON.stringify(messages)); - updatedMessages.splice(messageIndex, 1); - setMessages(updatedMessages); - }; + const handleMove = (direction: 'up' | 'down') => { + const updatedChats: ChatInterface[] = JSON.parse( + JSON.stringify(useStore.getState().chats) + ); + const updatedMessages = updatedChats[currentChatIndex].messages; + const temp = updatedMessages[messageIndex]; + if (direction === 'up') { + updatedMessages[messageIndex] = updatedMessages[messageIndex - 1]; + updatedMessages[messageIndex - 1] = temp; + } else { + updatedMessages[messageIndex] = updatedMessages[messageIndex + 1]; + updatedMessages[messageIndex + 1] = temp; + } + setChats(updatedChats); + }; - const handleMove = (direction: 'up' | 'down') => { - const updatedMessages = JSON.parse(JSON.stringify(messages)); - const temp = updatedMessages[messageIndex]; - if (direction === 'up') { - updatedMessages[messageIndex] = updatedMessages[messageIndex - 1]; - updatedMessages[messageIndex - 1] = temp; - } else { - updatedMessages[messageIndex] = updatedMessages[messageIndex + 1]; - updatedMessages[messageIndex + 1] = temp; - } - setMessages(updatedMessages); - }; + const handleRefresh = () => { + const updatedChats: ChatInterface[] = JSON.parse( + JSON.stringify(useStore.getState().chats) + ); + const updatedMessages = updatedChats[currentChatIndex].messages; + updatedMessages.splice(updatedMessages.length - 1, 1); + setChats(updatedChats); + handleSubmit(); + }; - const handleRefresh = () => { - const updatedMessages = JSON.parse(JSON.stringify(messages)); - updatedMessages.splice(updatedMessages.length - 1, 1); - setMessages(updatedMessages); - handleSubmit(); - }; + return ( + <> +
+ {children}; + let highlight; - return ( - <> -
- {children}; - let highlight; + const match = /language-(\w+)/.exec(className || ''); + const lang = match && match[1]; + if (lang) + highlight = hljs.highlight(children.toString(), { + language: lang, + }); + else highlight = hljs.highlightAuto(children.toString()); - const match = /language-(\w+)/.exec(className || ''); - const lang = match && match[1]; - if (lang) - highlight = hljs.highlight(children.toString(), { - language: lang, - }); - else highlight = hljs.highlightAuto(children.toString()); - - return ( -
-
- {highlight.language} - -
-
- -
+
+ {highlight.language} + +
+
+ +
+ +
-
- ); - }, - p({ className, children, ...props }) { - return

{children}

; - }, - }} - > - {content} - -
-
- {isDelete || ( - <> - {role === 'assistant' && messageIndex === messages?.length - 1 && ( - - )} - {messageIndex !== 0 && ( - handleMove('up')} /> - )} - {messageIndex !== messages?.length - 1 && ( - handleMove('down')} /> - )} + ); + }, + p({ className, children, ...props }) { + return

{children}

; + }, + }} + > + {content} + +
+
+ {isDelete || ( + <> + {role === 'assistant' && messageIndex === lastMessageIndex && ( + + )} + {messageIndex !== 0 && ( + handleMove('up')} /> + )} + {messageIndex !== lastMessageIndex && ( + handleMove('down')} /> + )} - - - - )} - {isDelete && ( - <> - - - - )} -
- - ); -}; + + + + )} + {isDelete && ( + <> + + + + )} +
+ + ); + } +); const MessageButton = ({ onClick, @@ -286,11 +296,9 @@ const EditView = ({ messageIndex: number; sticky?: boolean; }) => { - const [messages, setMessages, inputRole] = useStore((state) => [ - state.messages, - state.setMessages, - state.inputRole, - ]); + const inputRole = useStore((state) => state.inputRole); + const setChats = useStore((state) => state.setChats); + const currentChatIndex = useStore((state) => state.currentChatIndex); const [_content, _setContent] = useState(content); const [isModalOpen, setIsModalOpen] = useState(false); @@ -319,9 +327,10 @@ const EditView = ({ const handleSave = () => { if (_content === '') return; - const updatedMessages: MessageInterface[] = JSON.parse( - JSON.stringify(messages) + const updatedChats: ChatInterface[] = JSON.parse( + JSON.stringify(useStore.getState().chats) ); + const updatedMessages = updatedChats[currentChatIndex].messages; if (sticky) { updatedMessages.push({ role: inputRole, content: _content }); _setContent(''); @@ -330,26 +339,29 @@ const EditView = ({ updatedMessages[messageIndex].content = _content; setIsEdit(false); } - setMessages(updatedMessages); + setChats(updatedChats); }; const { handleSubmit } = useSubmit(); const handleSaveAndSubmit = () => { if (_content == '') return; - const updatedMessages: MessageInterface[] = JSON.parse( - JSON.stringify(messages) + const updatedChats: ChatInterface[] = JSON.parse( + JSON.stringify(useStore.getState().chats) ); + const updatedMessages = updatedChats[currentChatIndex].messages; if (sticky) { updatedMessages.push({ role: inputRole, content: _content }); _setContent(''); - setMessages(updatedMessages); resetTextAreaHeight(); } else { updatedMessages[messageIndex].content = _content; - const _updatedMessages = updatedMessages.slice(0, messageIndex + 1); - setMessages(_updatedMessages); + updatedChats[currentChatIndex].messages = updatedMessages.slice( + 0, + messageIndex + 1 + ); setIsEdit(false); } + setChats(updatedChats); handleSubmit(); }; diff --git a/src/components/Chat/ChatContent/Message/NewMessageButton.tsx b/src/components/Chat/ChatContent/Message/NewMessageButton.tsx index b0ab6fd..ef36c5a 100644 --- a/src/components/Chat/ChatContent/Message/NewMessageButton.tsx +++ b/src/components/Chat/ChatContent/Message/NewMessageButton.tsx @@ -3,72 +3,62 @@ import useStore from '@store/store'; import PlusIcon from '@icon/PlusIcon'; -import { ChatInterface, MessageInterface } from '@type/chat'; +import { ChatInterface } from '@type/chat'; import { defaultSystemMessage } from '@constants/chat'; -const NewMessageButton = ({ messageIndex }: { messageIndex: number }) => { - const [ - messages, - chats, - setMessages, - currentChatIndex, - setChats, - setCurrentChatIndex, - ] = useStore((state) => [ - state.messages, - state.chats, - state.setMessages, - state.currentChatIndex, - state.setChats, - state.setCurrentChatIndex, - ]); +const NewMessageButton = React.memo( + ({ messageIndex }: { messageIndex: number }) => { + const setChats = useStore((state) => state.setChats); + const currentChatIndex = useStore((state) => state.currentChatIndex); + const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex); - const addChat = () => { - if (chats) { - const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats)); - let titleIndex = 1; - let title = `New Chat ${titleIndex}`; + const addChat = () => { + const chats = useStore.getState().chats; + if (chats) { + const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats)); + let titleIndex = 1; + let title = `New Chat ${titleIndex}`; - while (chats.some((chat) => chat.title === title)) { - titleIndex += 1; - title = `New Chat ${titleIndex}`; + while (chats.some((chat) => chat.title === title)) { + titleIndex += 1; + title = `New Chat ${titleIndex}`; + } + + updatedChats.unshift({ + title, + messages: [{ role: 'system', content: defaultSystemMessage }], + }); + setChats(updatedChats); + setCurrentChatIndex(0); } + }; - updatedChats.unshift({ - title, - messages: [{ role: 'system', content: defaultSystemMessage }], - }); - setChats(updatedChats); - setMessages(updatedChats[0].messages); - setCurrentChatIndex(0); - } - }; + const addMessage = () => { + if (currentChatIndex === -1) { + addChat(); + } else { + const updatedChats: ChatInterface[] = JSON.parse( + JSON.stringify(useStore.getState().chats) + ); + updatedChats[currentChatIndex].messages.splice(messageIndex + 1, 0, { + content: '', + role: 'user', + }); + setChats(updatedChats); + } + }; - const addMessage = () => { - if (currentChatIndex === -1) { - addChat(); - } else { - const updatedMessages: MessageInterface[] = JSON.parse( - JSON.stringify(messages) - ); - updatedMessages.splice(messageIndex + 1, 0, { - content: '', - role: 'user', - }); - setMessages(updatedMessages); - } - }; - - return ( -
-
- + return ( +
+
+ +
-
- ); -}; + ); + } +); export default NewMessageButton; diff --git a/src/components/Chat/ChatContent/Message/RoleSelector.tsx b/src/components/Chat/ChatContent/Message/RoleSelector.tsx index ad445cd..3806b03 100644 --- a/src/components/Chat/ChatContent/Message/RoleSelector.tsx +++ b/src/components/Chat/ChatContent/Message/RoleSelector.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import useStore from '@store/store'; import DownChevronArrow from '@icon/DownChevronArrow'; -import { MessageInterface, Role, roles } from '@type/chat'; +import { ChatInterface, Role, roles } from '@type/chat'; const RoleSelector = ({ role, @@ -13,11 +13,9 @@ const RoleSelector = ({ messageIndex: number; sticky?: boolean; }) => { - const [messages, setMessages, setInputRole] = useStore((state) => [ - state.messages, - state.setMessages, - state.setInputRole, - ]); + const setInputRole = useStore((state) => state.setInputRole); + const setChats = useStore((state) => state.setChats); + const currentChatIndex = useStore((state) => state.currentChatIndex); const [dropDown, setDropDown] = useState(false); @@ -46,11 +44,12 @@ const RoleSelector = ({ className='px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white cursor-pointer' onClick={() => { if (!sticky) { - const updatedMessages: MessageInterface[] = JSON.parse( - JSON.stringify(messages) + const updatedChats: ChatInterface[] = JSON.parse( + JSON.stringify(useStore.getState().chats) ); - updatedMessages[messageIndex].role = r; - setMessages(updatedMessages); + updatedChats[currentChatIndex].messages[messageIndex].role = + r; + setChats(updatedChats); } else { setInputRole(r); } @@ -66,5 +65,4 @@ const RoleSelector = ({
); }; - export default RoleSelector; diff --git a/src/components/ConfigMenu/ConfigMenu.tsx b/src/components/ConfigMenu/ConfigMenu.tsx index d8eaf66..96346f4 100644 --- a/src/components/ConfigMenu/ConfigMenu.tsx +++ b/src/components/ConfigMenu/ConfigMenu.tsx @@ -5,15 +5,12 @@ import CrossIcon2 from '@icon/CrossIcon2'; import { validateApiKey } from '@api/customApi'; const ConfigMenu = () => { - const [apiKey, setApiKey, apiFree, setApiFree, openConfig, setOpenConfig] = - useStore((state) => [ - state.apiKey, - state.setApiKey, - state.apiFree, - state.setApiFree, - state.openConfig, - state.setOpenConfig, - ]); + const apiKey = useStore((state) => state.apiKey); + const setApiKey = useStore((state) => state.setApiKey); + const apiFree = useStore((state) => state.apiFree); + const setApiFree = useStore((state) => state.setApiFree); + const openConfig = useStore((state) => state.openConfig); + const setOpenConfig = useStore((state) => state.setOpenConfig); const [_apiKey, _setApiKey] = useState(apiKey || ''); const [error, setError] = useState(false); diff --git a/src/components/Menu/ChatHistoryList.tsx b/src/components/Menu/ChatHistoryList.tsx index ce65250..859120b 100644 --- a/src/components/Menu/ChatHistoryList.tsx +++ b/src/components/Menu/ChatHistoryList.tsx @@ -10,11 +10,8 @@ import CrossIcon from '@icon/CrossIcon'; import useInitialiseNewChat from '@hooks/useInitialiseNewChat'; const ChatHistoryList = () => { - const [chats, setCurrentChatIndex, setMessages] = useStore((state) => [ - state.chats, - state.setCurrentChatIndex, - state.setMessages, - ]); + const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex); + const chats = useStore((state) => state.chats); return (
@@ -27,7 +24,6 @@ const ChatHistoryList = () => { chatIndex={index} onClick={() => { setCurrentChatIndex(index); - setMessages(chats[index].messages); }} /> ))} @@ -66,14 +62,9 @@ const ChatHistory = ({ onClick?: React.MouseEventHandler; }) => { const initialiseNewChat = useInitialiseNewChat(); - const [chats, setChats, currentChatIndex, setMessages, setCurrentChatIndex] = - useStore((state) => [ - state.chats, - state.setChats, - state.currentChatIndex, - state.setMessages, - state.setCurrentChatIndex, - ]); + const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex); + const setChats = useStore((state) => state.setChats); + const currentChatIndex = useStore((state) => state.currentChatIndex); const [isDelete, setIsDelete] = useState(false); const [isEdit, setIsEdit] = useState(false); @@ -83,7 +74,7 @@ const ChatHistory = ({ const handleTick = (e: React.MouseEvent) => { e.stopPropagation(); - const updatedChats = JSON.parse(JSON.stringify(chats)); + const updatedChats = JSON.parse(JSON.stringify(useStore.getState().chats)); if (isEdit) { updatedChats[chatIndex].title = _title; setChats(updatedChats); @@ -92,7 +83,6 @@ const ChatHistory = ({ updatedChats.splice(chatIndex, 1); if (updatedChats.length > 0) { setCurrentChatIndex(0); - setMessages(updatedChats[0].messages); setChats(updatedChats); } else { initialiseNewChat(); diff --git a/src/components/Menu/Menu.tsx b/src/components/Menu/Menu.tsx index 4640bd7..e2cc1ed 100644 --- a/src/components/Menu/Menu.tsx +++ b/src/components/Menu/Menu.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import useStore from '@store/store'; import NewChat from './NewChat'; import ChatHistoryList from './ChatHistoryList'; diff --git a/src/components/Menu/MenuOptions/Config.tsx b/src/components/Menu/MenuOptions/Config.tsx index 4dd7d3e..1f72cb8 100644 --- a/src/components/Menu/MenuOptions/Config.tsx +++ b/src/components/Menu/MenuOptions/Config.tsx @@ -4,10 +4,8 @@ import useStore from '@store/store'; import PersonIcon from '@icon/PersonIcon'; const Config = () => { - const [apiFree, setOpenConfig] = useStore((state) => [ - state.apiFree, - state.setOpenConfig, - ]); + const apiFree = useStore((state) => state.apiFree); + const setOpenConfig = useStore((state) => state.setOpenConfig); return ( { - const [chats, setChats, setCurrentChatIndex, setMessages] = useStore( - (state) => [ - state.chats, - state.setChats, - state.setCurrentChatIndex, - state.setMessages, - ] - ); - const addChat = useAddChat(); return ( diff --git a/src/components/MobileBar/MobileBar.tsx b/src/components/MobileBar/MobileBar.tsx index da84f9c..29812ec 100644 --- a/src/components/MobileBar/MobileBar.tsx +++ b/src/components/MobileBar/MobileBar.tsx @@ -5,10 +5,12 @@ import PlusIcon from '@icon/PlusIcon'; import useAddChat from '@hooks/useAddChat'; const MobileBar = () => { - const [chats, currentChatIndex] = useStore((state) => [ - state.chats, - state.currentChatIndex, - ]); + const chatTitle = useStore((state) => + state.chats && state.chats.length > 0 + ? state.chats[state.currentChatIndex].title + : 'New Chat' + ); + const addChat = useAddChat(); return ( @@ -42,11 +44,7 @@ const MobileBar = () => { -

- {chats && chats.length > 0 - ? chats[currentChatIndex]?.title - : 'New Chat'} -

+

{chatTitle}

diff --git a/src/hooks/useAddChat.ts b/src/hooks/useAddChat.ts index f020971..f1fe6bf 100644 --- a/src/hooks/useAddChat.ts +++ b/src/hooks/useAddChat.ts @@ -4,16 +4,11 @@ import { defaultSystemMessage } from '@constants/chat'; import { ChatInterface } from '@type/chat'; const useAddChat = () => { - const [chats, setChats, setCurrentChatIndex, setMessages] = useStore( - (state) => [ - state.chats, - state.setChats, - state.setCurrentChatIndex, - state.setMessages, - ] - ); + const setChats = useStore((state) => state.setChats); + const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex); const addChat = () => { + const chats = useStore.getState().chats; if (chats) { const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats)); let titleIndex = 1; @@ -29,7 +24,6 @@ const useAddChat = () => { messages: [{ role: 'system', content: defaultSystemMessage }], }); setChats(updatedChats); - setMessages(updatedChats[0].messages); setCurrentChatIndex(0); } }; diff --git a/src/hooks/useInitialiseNewChat.ts b/src/hooks/useInitialiseNewChat.ts index 2be3986..25fe721 100644 --- a/src/hooks/useInitialiseNewChat.ts +++ b/src/hooks/useInitialiseNewChat.ts @@ -4,11 +4,8 @@ import { MessageInterface } from '@type/chat'; import { defaultSystemMessage } from '@constants/chat'; const useInitialiseNewChat = () => { - const [setChats, setMessages, setCurrentChatIndex] = useStore((state) => [ - state.setChats, - state.setMessages, - state.setCurrentChatIndex, - ]); + const setChats = useStore((state) => state.setChats); + const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex); const initialiseNewChat = () => { const message: MessageInterface = { @@ -21,7 +18,6 @@ const useInitialiseNewChat = () => { messages: [message], }, ]); - setMessages([message]); setCurrentChatIndex(0); }; diff --git a/src/hooks/useSaveToLocalStorage.ts b/src/hooks/useSaveToLocalStorage.ts index ee98b41..8c0da3f 100644 --- a/src/hooks/useSaveToLocalStorage.ts +++ b/src/hooks/useSaveToLocalStorage.ts @@ -1,12 +1,19 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useRef } from 'react'; import useStore from '@store/store'; const useSaveToLocalStorage = () => { - const chats = useStore((state) => state.chats); + const chatsRef = useRef(useStore.getState().chats); useEffect(() => { - if (chats) localStorage.setItem('chats', JSON.stringify(chats)); - }, [chats]); + const unsubscribe = useStore.subscribe((state) => { + if (chatsRef && chatsRef.current !== state.chats) { + chatsRef.current = state.chats; + localStorage.setItem('chats', JSON.stringify(state.chats)); + } + }); + + return unsubscribe; + }, []); }; export default useSaveToLocalStorage; diff --git a/src/hooks/useSubmit.ts b/src/hooks/useSubmit.ts index 7980ef5..29703c9 100644 --- a/src/hooks/useSubmit.ts +++ b/src/hooks/useSubmit.ts @@ -1,48 +1,45 @@ import React from 'react'; import useStore from '@store/store'; -import { MessageInterface } from '@type/chat'; +import { ChatInterface } from '@type/chat'; import { getChatCompletionStream as getChatCompletionStreamFree } from '@api/freeApi'; import { getChatCompletionStream as getChatCompletionStreamCustom } from '@api/customApi'; import { parseEventSource } from '@api/helper'; const useSubmit = () => { - const [ - error, - setError, - apiFree, - apiKey, - setMessages, - setGenerating, - generating, - ] = useStore((state) => [ - state.error, - state.setError, - state.apiFree, - state.apiKey, - state.setMessages, - state.setGenerating, - state.generating, - ]); + const error = useStore((state) => state.error); + const setError = useStore((state) => state.setError); + const apiFree = useStore((state) => state.apiFree); + const apiKey = useStore((state) => state.apiKey); + const setGenerating = useStore((state) => state.setGenerating); + const generating = useStore((state) => state.generating); + const currentChatIndex = useStore((state) => state.currentChatIndex); + const setChats = useStore((state) => state.setChats); const handleSubmit = async () => { - if (generating) return; - const messages = useStore.getState().messages; + const chats = useStore.getState().chats; + if (generating || !chats) return; - const updatedMessages: MessageInterface[] = JSON.parse( - JSON.stringify(messages) - ); + const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats)); - updatedMessages.push({ role: 'assistant', content: '' }); + updatedChats[currentChatIndex].messages.push({ + role: 'assistant', + content: '', + }); - setMessages(updatedMessages); + setChats(updatedChats); setGenerating(true); let stream; try { if (apiFree) { - stream = await getChatCompletionStreamFree(messages); + stream = await getChatCompletionStreamFree( + chats[currentChatIndex].messages + ); } else if (apiKey) { - stream = await getChatCompletionStreamCustom(apiKey, messages); + stream = await getChatCompletionStreamCustom( + apiKey, + chats[currentChatIndex].messages + ); } if (stream) { @@ -65,11 +62,12 @@ const useSubmit = () => { } }, ''); - const updatedMessages: MessageInterface[] = JSON.parse( - JSON.stringify(useStore.getState().messages) + const updatedChats: ChatInterface[] = JSON.parse( + JSON.stringify(useStore.getState().chats) ); + const updatedMessages = updatedChats[currentChatIndex].messages; updatedMessages[updatedMessages.length - 1].content += resultString; - setMessages(updatedMessages); + setChats(updatedChats); } } } diff --git a/src/hooks/useUpdateChats.ts b/src/hooks/useUpdateChats.ts deleted file mode 100644 index 6b9023e..0000000 --- a/src/hooks/useUpdateChats.ts +++ /dev/null @@ -1,25 +0,0 @@ -import React, { useEffect } from 'react'; -import useStore from '@store/store'; -import { ChatInterface, MessageInterface } from '@type/chat'; - -const useUpdateCharts = () => { - const [chats, messages, setChats, currentChatIndex] = useStore((state) => [ - state.chats, - state.messages, - state.setChats, - state.currentChatIndex, - ]); - - useEffect(() => { - if (currentChatIndex !== -1 && chats && chats.length > 0) { - const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats)); - const updatedMessages: MessageInterface[] = JSON.parse( - JSON.stringify(messages) - ); - updatedChats[currentChatIndex].messages = updatedMessages; - setChats(updatedChats); - } - }, [messages]); -}; - -export default useUpdateCharts;