fix slow typing with long sessions (#4291)
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef, memo, useMemo } from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
import remarkBreaks from 'remark-breaks';
|
import remarkBreaks from 'remark-breaks';
|
||||||
@@ -16,7 +16,14 @@ interface MarkdownContentProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CodeBlock = ({ language, children }: { language: string; children: string }) => {
|
// Memoized CodeBlock component to prevent re-rendering when props haven't changed
|
||||||
|
const CodeBlock = memo(function CodeBlock({
|
||||||
|
language,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
language: string;
|
||||||
|
children: string;
|
||||||
|
}) {
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
const timeoutRef = useRef<number | null>(null);
|
const timeoutRef = useRef<number | null>(null);
|
||||||
|
|
||||||
@@ -43,6 +50,44 @@ const CodeBlock = ({ language, children }: { language: string; children: string
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Memoize the SyntaxHighlighter component to prevent re-rendering
|
||||||
|
// Only re-render if language or children change
|
||||||
|
const memoizedSyntaxHighlighter = useMemo(() => {
|
||||||
|
// For very large code blocks, consider truncating or lazy loading
|
||||||
|
const isLargeCodeBlock = children.length > 10000; // 10KB threshold
|
||||||
|
|
||||||
|
if (isLargeCodeBlock) {
|
||||||
|
console.log(`Large code block detected (${children.length} chars), consider optimization`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SyntaxHighlighter
|
||||||
|
style={oneDark}
|
||||||
|
language={language}
|
||||||
|
PreTag="div"
|
||||||
|
customStyle={{
|
||||||
|
margin: 0,
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: '100%',
|
||||||
|
}}
|
||||||
|
codeTagProps={{
|
||||||
|
style: {
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
wordBreak: 'break-all',
|
||||||
|
overflowWrap: 'break-word',
|
||||||
|
fontFamily: 'var(--font-sans)',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
// Performance optimizations for SyntaxHighlighter
|
||||||
|
showLineNumbers={false} // Disable line numbers for better performance
|
||||||
|
wrapLines={false} // Disable line wrapping for better performance
|
||||||
|
lineProps={undefined} // Don't add extra props to each line
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
);
|
||||||
|
}, [language, children]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative group w-full">
|
<div className="relative group w-full">
|
||||||
<button
|
<button
|
||||||
@@ -54,47 +99,31 @@ const CodeBlock = ({ language, children }: { language: string; children: string
|
|||||||
>
|
>
|
||||||
{copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
|
{copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
|
||||||
</button>
|
</button>
|
||||||
<div className="w-full overflow-x-auto">
|
<div className="w-full overflow-x-auto">{memoizedSyntaxHighlighter}</div>
|
||||||
<SyntaxHighlighter
|
|
||||||
style={oneDark}
|
|
||||||
language={language}
|
|
||||||
PreTag="div"
|
|
||||||
customStyle={{
|
|
||||||
margin: 0,
|
|
||||||
width: '100%',
|
|
||||||
maxWidth: '100%',
|
|
||||||
}}
|
|
||||||
codeTagProps={{
|
|
||||||
style: {
|
|
||||||
whiteSpace: 'pre-wrap',
|
|
||||||
wordBreak: 'break-all',
|
|
||||||
overflowWrap: 'break-word',
|
|
||||||
fontFamily: 'var(--font-sans)',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</SyntaxHighlighter>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
const MarkdownCode = React.forwardRef(function MarkdownCode(
|
|
||||||
{ inline, className, children, ...props }: CodeProps,
|
|
||||||
ref: React.Ref<HTMLElement>
|
|
||||||
) {
|
|
||||||
const match = /language-(\w+)/.exec(className || '');
|
|
||||||
return !inline && match ? (
|
|
||||||
<CodeBlock language={match[1]}>{String(children).replace(/\n$/, '')}</CodeBlock>
|
|
||||||
) : (
|
|
||||||
<code ref={ref} {...props} className="break-all bg-inline-code whitespace-pre-wrap font-sans">
|
|
||||||
{children}
|
|
||||||
</code>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function MarkdownContent({ content, className = '' }: MarkdownContentProps) {
|
const MarkdownCode = memo(
|
||||||
|
React.forwardRef(function MarkdownCode(
|
||||||
|
{ inline, className, children, ...props }: CodeProps,
|
||||||
|
ref: React.Ref<HTMLElement>
|
||||||
|
) {
|
||||||
|
const match = /language-(\w+)/.exec(className || '');
|
||||||
|
return !inline && match ? (
|
||||||
|
<CodeBlock language={match[1]}>{String(children).replace(/\n$/, '')}</CodeBlock>
|
||||||
|
) : (
|
||||||
|
<code ref={ref} {...props} className="break-all bg-inline-code whitespace-pre-wrap font-sans">
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const MarkdownContent = memo(function MarkdownContent({
|
||||||
|
content,
|
||||||
|
className = '',
|
||||||
|
}: MarkdownContentProps) {
|
||||||
const [processedContent, setProcessedContent] = useState(content);
|
const [processedContent, setProcessedContent] = useState(content);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -137,4 +166,6 @@ export default function MarkdownContent({ content, className = '' }: MarkdownCon
|
|||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
export default MarkdownContent;
|
||||||
|
|||||||
Reference in New Issue
Block a user