perf scroll components (#2676)

* perf: add scroll list && virtualist (#2665)

* perf: chatHistorySlider add virtualList

* perf: dataCard add scroll

* fix: ts

* perf: scroll list components

* perf: hook refresh

---------

Co-authored-by: papapatrick <109422393+Patrickill@users.noreply.github.com>
This commit is contained in:
Archer
2024-09-11 19:53:49 +08:00
committed by GitHub
parent 5101c7a6dc
commit 6331f4b845
17 changed files with 413 additions and 335 deletions

View File

@@ -9,8 +9,6 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import { useUserStore } from '@/web/support/user/useUserStore';
import { AppListItemType } from '@fastgpt/global/core/app/type';
import { useI18n } from '@/web/context/I18n';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
import { useContextSelector } from 'use-context-selector';
import { ChatContext } from '@/web/core/chat/context/chatContext';
@@ -52,19 +50,19 @@ const ChatHistorySlider = ({
const { userInfo } = useUserStore();
const {
histories,
onChangeChatId,
chatId: activeChatId,
isLoading
isLoading,
ScrollList,
historyList,
histories
} = useContextSelector(ChatContext, (v) => v);
const concatHistory = useMemo(() => {
const formatHistories: HistoryItemType[] = histories.map((item) => ({
id: item.chatId,
title: item.title,
customTitle: item.customTitle,
top: item.top
}));
const formatHistories: HistoryItemType[] = historyList.map((data) => {
const item = data.data;
return { id: item.chatId, title: item.title, customTitle: item.customTitle, top: item.top };
});
const newChat: HistoryItemType = {
id: activeChatId,
title: t('common:core.chat.New Chat')
@@ -72,7 +70,7 @@ const ChatHistorySlider = ({
const activeChat = histories.find((item) => item.chatId === activeChatId);
return !activeChat ? [newChat].concat(formatHistories) : formatHistories;
}, [activeChatId, histories, t]);
}, [activeChatId, histories, historyList, t]);
// custom title edit
const { onOpenModal, EditModal: EditTitleModal } = useEditTitle({
@@ -175,20 +173,19 @@ const ChatHistorySlider = ({
)}
</Flex>
<Box flex={'1 0 0'} h={0} px={[2, 5]} overflow={'overlay'}>
<ScrollList flex={'1 0 0'} h={0} px={[2, 5]} overflow={'overlay'}>
{/* chat history */}
<>
{concatHistory.map((item, i) => (
<Flex
position={'relative'}
key={item.id || `${i}`}
key={item.id}
alignItems={'center'}
py={2.5}
px={4}
h={'44px'}
cursor={'pointer'}
userSelect={'none'}
borderRadius={'md'}
mb={2}
fontSize={'sm'}
_hover={{
bg: 'myGray.50',
@@ -207,6 +204,9 @@ const ChatHistorySlider = ({
onChangeChatId(item.id);
}
})}
{...(i !== concatHistory.length - 1 && {
mb: '8px'
})}
>
<MyIcon
name={item.id === activeChatId ? 'core/chat/chatFill' : 'core/chat/chatLight'}
@@ -283,7 +283,7 @@ const ChatHistorySlider = ({
</Flex>
))}
</>
</Box>
</ScrollList>
{/* exec */}
{!isPc && isUserChatPage && (

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useState } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import NextHead from '@/components/common/NextHead';
import { useRouter } from 'next/router';
import { delChatRecordById, getChatHistories, getInitChatInfo } from '@/web/core/chat/api';
@@ -53,14 +53,17 @@ const Chat = ({
const { setLastChatAppId } = useChatStore();
const {
loadHistories,
setHistories: setRecordHistories,
loadHistories: loadRecordHistories,
histories: recordHistories,
onUpdateHistory,
onClearHistories,
onDelHistory,
isOpenSlider,
onCloseSlider,
forbidLoadChat,
onChangeChatId
onChangeChatId,
onUpdateHistoryTitle
} = useContextSelector(ChatContext, (v) => v);
const {
ChatBoxRef,
@@ -148,8 +151,7 @@ const Chat = ({
if (completionChatId !== chatId && controller.signal.reason !== 'leave') {
onChangeChatId(completionChatId, true);
}
loadHistories();
onUpdateHistoryTitle({ chatId: completionChatId, newTitle });
// update chat window
setChatData((state) => ({
...state,
@@ -158,7 +160,7 @@ const Chat = ({
return { responseText, responseData, isNewChat: forbidLoadChat.current };
},
[appId, chatId, forbidLoadChat, loadHistories, onChangeChatId]
[chatId, appId, onUpdateHistoryTitle, forbidLoadChat, onChangeChatId]
);
return (
@@ -283,14 +285,6 @@ const Render = (props: Props) => {
}
);
const { data: histories = [], runAsync: loadHistories } = useRequest2(
() => (appId ? getChatHistories({ appId }) : Promise.resolve([])),
{
manual: false,
refreshDeps: [appId]
}
);
// 初始化聊天框
useMount(async () => {
// pc: redirect to latest model chat
@@ -324,8 +318,9 @@ const Render = (props: Props) => {
}
});
const providerParams = useMemo(() => ({ appId }), [appId]);
return (
<ChatContextProvider histories={histories} loadHistories={loadHistories}>
<ChatContextProvider params={providerParams}>
<Chat {...props} myApps={myApps} />
</ChatContextProvider>
);

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useRef, useState } from 'react';
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { useRouter } from 'next/router';
import { Box, Flex, Drawer, DrawerOverlay, DrawerContent } from '@chakra-ui/react';
import { streamFetch } from '@/web/common/api/fetch';
@@ -75,6 +75,7 @@ const OutLink = ({ appName, appIntro, appAvatar }: Props) => {
const outLinkUid: string = authToken || localUId;
const {
onUpdateHistoryTitle,
loadHistories,
onUpdateHistory,
onClearHistories,
@@ -140,7 +141,7 @@ const OutLink = ({ appName, appIntro, appAvatar }: Props) => {
if (completionChatId !== chatId) {
onChangeChatId(completionChatId, true);
}
loadHistories();
onUpdateHistoryTitle({ chatId: completionChatId, newTitle });
// update chat window
setChatData((state) => ({
@@ -168,9 +169,9 @@ const OutLink = ({ appName, appIntro, appAvatar }: Props) => {
shareId,
chatData.app.type,
outLinkUid,
onUpdateHistoryTitle,
forbidLoadChat,
onChangeChatId,
loadHistories
onChangeChatId
]
);
@@ -354,16 +355,12 @@ const Render = (props: Props) => {
const { localUId } = useShareChatStore();
const outLinkUid: string = authToken || localUId;
const { data: histories = [], runAsync: loadHistories } = useRequest2(
() => (shareId && outLinkUid ? getChatHistories({ shareId, outLinkUid }) : Promise.resolve([])),
{
manual: false,
refreshDeps: [shareId, outLinkUid]
}
);
const contextParams = useMemo(() => {
return { shareId, outLinkUid };
}, [shareId, outLinkUid]);
return (
<ChatContextProvider histories={histories} loadHistories={loadHistories}>
<ChatContextProvider params={contextParams}>
<OutLink {...props} />;
</ChatContextProvider>
);

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import NextHead from '@/components/common/NextHead';
import { delChatRecordById, getChatHistories, getTeamChatInfo } from '@/web/core/chat/api';
import { useRouter } from 'next/router';
@@ -58,6 +58,7 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
const [chatData, setChatData] = useState<InitChatResponse>(defaultChatData);
const {
onUpdateHistoryTitle,
loadHistories,
onUpdateHistory,
onClearHistories,
@@ -114,7 +115,7 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
if (completionChatId !== chatId) {
onChangeChatId(completionChatId, true);
}
loadHistories();
onUpdateHistoryTitle({ chatId: completionChatId, newTitle });
// update chat window
setChatData((state) => ({
@@ -125,15 +126,15 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
return { responseText, responseData, isNewChat: forbidLoadChat.current };
},
[
chatData.app.type,
chatId,
customVariables,
appId,
teamId,
teamToken,
chatData.app.type,
onUpdateHistoryTitle,
forbidLoadChat,
onChangeChatId,
loadHistories
onChangeChatId
]
);
@@ -302,19 +303,6 @@ const Render = (props: Props) => {
}
);
const { data: histories = [], runAsync: loadHistories } = useRequest2(
async () => {
if (teamId && appId && teamToken) {
return getChatHistories({ teamId, appId, teamToken: teamToken });
}
return [];
},
{
manual: false,
refreshDeps: [appId, teamId, teamToken]
}
);
// 初始化聊天框
useEffect(() => {
(async () => {
@@ -330,8 +318,12 @@ const Render = (props: Props) => {
})();
}, [appId, loadMyApps, myApps, router, t, toast]);
const contextParams = useMemo(() => {
return { teamId, appId, teamToken };
}, [teamId, appId, teamToken]);
return (
<ChatContextProvider histories={histories} loadHistories={loadHistories}>
<ChatContextProvider params={contextParams}>
<Chat {...props} myApps={myApps} />
</ChatContextProvider>
);