mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 17:00:15 +01:00
♻️ refactor: SidePanel Context to Optimize on ChatView Rerender (#8509)
This commit is contained in:
parent
0b1b0af741
commit
dfef7c31d2
5 changed files with 180 additions and 139 deletions
31
client/src/Providers/SidePanelContext.tsx
Normal file
31
client/src/Providers/SidePanelContext.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import React, { createContext, useContext, useMemo } from 'react';
|
||||
import type { EModelEndpoint } from 'librechat-data-provider';
|
||||
import { useChatContext } from './ChatContext';
|
||||
|
||||
interface SidePanelContextValue {
|
||||
endpoint?: EModelEndpoint | null;
|
||||
}
|
||||
|
||||
const SidePanelContext = createContext<SidePanelContextValue | undefined>(undefined);
|
||||
|
||||
export function SidePanelProvider({ children }: { children: React.ReactNode }) {
|
||||
const { conversation } = useChatContext();
|
||||
|
||||
/** Context value only created when endpoint changes */
|
||||
const contextValue = useMemo<SidePanelContextValue>(
|
||||
() => ({
|
||||
endpoint: conversation?.endpoint,
|
||||
}),
|
||||
[conversation?.endpoint],
|
||||
);
|
||||
|
||||
return <SidePanelContext.Provider value={contextValue}>{children}</SidePanelContext.Provider>;
|
||||
}
|
||||
|
||||
export function useSidePanelContext() {
|
||||
const context = useContext(SidePanelContext);
|
||||
if (!context) {
|
||||
throw new Error('useSidePanelContext must be used within SidePanelProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
|
@ -24,4 +24,5 @@ export * from './ToolCallsMapContext';
|
|||
export * from './SetConvoContext';
|
||||
export * from './SearchContext';
|
||||
export * from './BadgeRowContext';
|
||||
export * from './SidePanelContext';
|
||||
export { default as BadgeRowProvider } from './BadgeRowContext';
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ import { FileSources, LocalStorageKeys } from 'librechat-data-provider';
|
|||
import type { ExtendedFile } from '~/common';
|
||||
import { useDeleteFilesMutation } from '~/data-provider';
|
||||
import DragDropWrapper from '~/components/Chat/Input/Files/DragDropWrapper';
|
||||
import { EditorProvider, SidePanelProvider } from '~/Providers';
|
||||
import Artifacts from '~/components/Artifacts/Artifacts';
|
||||
import { SidePanelGroup } from '~/components/SidePanel';
|
||||
import { useSetFilesToDelete } from '~/hooks';
|
||||
import { EditorProvider } from '~/Providers';
|
||||
import store from '~/store';
|
||||
|
||||
export default function Presentation({ children }: { children: React.ReactNode }) {
|
||||
|
|
@ -59,6 +59,7 @@ export default function Presentation({ children }: { children: React.ReactNode }
|
|||
|
||||
return (
|
||||
<DragDropWrapper className="relative flex w-full grow overflow-hidden bg-presentation">
|
||||
<SidePanelProvider>
|
||||
<SidePanelGroup
|
||||
defaultLayout={defaultLayout}
|
||||
fullPanelCollapse={fullCollapse}
|
||||
|
|
@ -75,6 +76,7 @@ export default function Presentation({ children }: { children: React.ReactNode }
|
|||
{children}
|
||||
</main>
|
||||
</SidePanelGroup>
|
||||
</SidePanelProvider>
|
||||
</DragDropWrapper>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import { useMediaQuery, useLocalStorage, useLocalize } from '~/hooks';
|
|||
import useSideNavLinks from '~/hooks/Nav/useSideNavLinks';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import NavToggle from '~/components/Nav/NavToggle';
|
||||
import { useSidePanelContext } from '~/Providers';
|
||||
import { cn, getEndpointField } from '~/utils';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import Nav from './Nav';
|
||||
|
||||
const defaultMinSize = 20;
|
||||
|
|
@ -43,13 +43,13 @@ const SidePanel = ({
|
|||
interfaceConfig: TInterfaceConfig;
|
||||
}) => {
|
||||
const localize = useLocalize();
|
||||
const { endpoint } = useSidePanelContext();
|
||||
const [isHovering, setIsHovering] = useState(false);
|
||||
const [newUser, setNewUser] = useLocalStorage('newUser', true);
|
||||
const { data: endpointsConfig = {} as TEndpointsConfig } = useGetEndpointsQuery();
|
||||
|
||||
const isSmallScreen = useMediaQuery('(max-width: 767px)');
|
||||
const { conversation } = useChatContext();
|
||||
const { endpoint } = conversation ?? {};
|
||||
|
||||
const { data: keyExpiry = { expiresAt: undefined } } = useUserKeyQuery(endpoint ?? '');
|
||||
|
||||
const defaultActive = useMemo(() => {
|
||||
|
|
|
|||
|
|
@ -22,14 +22,15 @@ interface SidePanelProps {
|
|||
const defaultMinSize = 20;
|
||||
const defaultInterface = getConfigDefaults().interface;
|
||||
|
||||
const SidePanelGroup = ({
|
||||
const SidePanelGroup = memo(
|
||||
({
|
||||
defaultLayout = [97, 3],
|
||||
defaultCollapsed = false,
|
||||
fullPanelCollapse = false,
|
||||
navCollapsedSize = 3,
|
||||
artifacts,
|
||||
children,
|
||||
}: SidePanelProps) => {
|
||||
}: SidePanelProps) => {
|
||||
const { data: startupConfig } = useGetStartupConfig();
|
||||
const interfaceConfig = useMemo(
|
||||
() => startupConfig?.interface ?? defaultInterface,
|
||||
|
|
@ -87,6 +88,18 @@ const SidePanelGroup = ({
|
|||
|
||||
const minSizeMain = useMemo(() => (artifacts != null ? 15 : 30), [artifacts]);
|
||||
|
||||
/** Memoized close button handler to prevent re-creating it */
|
||||
const handleClosePanel = useCallback(() => {
|
||||
setIsCollapsed(() => {
|
||||
localStorage.setItem('fullPanelCollapse', 'true');
|
||||
setFullCollapse(true);
|
||||
setCollapsedSize(0);
|
||||
setMinSize(0);
|
||||
return false;
|
||||
});
|
||||
panelRef.current?.collapse();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ResizablePanelGroup
|
||||
|
|
@ -135,19 +148,13 @@ const SidePanelGroup = ({
|
|||
<button
|
||||
aria-label="Close right side panel"
|
||||
className={`nav-mask ${!isCollapsed ? 'active' : ''}`}
|
||||
onClick={() => {
|
||||
setIsCollapsed(() => {
|
||||
localStorage.setItem('fullPanelCollapse', 'true');
|
||||
setFullCollapse(true);
|
||||
setCollapsedSize(0);
|
||||
setMinSize(0);
|
||||
return false;
|
||||
});
|
||||
panelRef.current?.collapse();
|
||||
}}
|
||||
onClick={handleClosePanel}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export default memo(SidePanelGroup);
|
||||
SidePanelGroup.displayName = 'SidePanelGroup';
|
||||
|
||||
export default SidePanelGroup;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue