fix slow typing with long sessions (#4291)

This commit is contained in:
Zane
2025-08-25 09:50:00 -07:00
committed by GitHub
parent 92e4772e4f
commit 476e2ddfd4
+71 -40
View File
@@ -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 remarkGfm from 'remark-gfm';
import remarkBreaks from 'remark-breaks';
@@ -16,7 +16,14 @@ interface MarkdownContentProps {
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 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 (
<div className="relative group w-full">
<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" />}
</button>
<div className="w-full overflow-x-auto">
<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 className="w-full overflow-x-auto">{memoizedSyntaxHighlighter}</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);
useEffect(() => {
@@ -137,4 +166,6 @@ export default function MarkdownContent({ content, className = '' }: MarkdownCon
</ReactMarkdown>
</div>
);
}
});
export default MarkdownContent;