improve render performance (#265)

This commit is contained in:
josc146
2023-11-02 21:26:30 +08:00
parent 838da652ae
commit d36f6ea245
4 changed files with 50 additions and 29 deletions
+7 -4
View File
@@ -1,4 +1,4 @@
import { memo, useEffect, useRef, useState } from 'react'
import { memo, useEffect, useMemo, useRef, useState } from 'react'
import PropTypes from 'prop-types'
import Browser from 'webextension-polyfill'
import InputBox from '../InputBox'
@@ -292,6 +292,8 @@ function ConversationCard(props) {
}
}
const retryFn = useMemo(() => getRetryFn(session), [session])
return (
<div className="gpt-inner">
<div
@@ -500,8 +502,9 @@ function ConversationCard(props) {
content={data.content}
key={idx}
type={data.type}
session={session}
onRetry={idx === conversationItemData.length - 1 ? getRetryFn(session) : null}
descName={data.type === 'answer' && session.aiName}
modelName={data.type === 'answer' && session.modelName}
onRetry={idx === conversationItemData.length - 1 ? retryFn : null}
/>
))}
</div>
@@ -533,7 +536,7 @@ function ConversationCard(props) {
ConversationCard.propTypes = {
session: PropTypes.object.isRequired,
question: PropTypes.string.isRequired,
question: PropTypes.string,
onUpdate: PropTypes.func,
draggable: PropTypes.bool,
closeable: PropTypes.bool,
+28 -15
View File
@@ -1,4 +1,4 @@
import { useState } from 'react'
import { memo, useState } from 'react'
import { ChevronDownIcon, XCircleIcon, SyncIcon } from '@primer/octicons-react'
import CopyButton from '../CopyButton'
import ReadButton from '../ReadButton'
@@ -8,11 +8,29 @@ import { useTranslation } from 'react-i18next'
import { isUsingCustomModel } from '../../config/index.mjs'
import { useConfig } from '../../hooks/use-config.mjs'
// eslint-disable-next-line
export function ConversationItem({ type, content, session, onRetry }) {
function AnswerTitle({ descName, modelName }) {
const { t } = useTranslation()
const config = useConfig()
return (
<p style="white-space: nowrap;">
{descName && modelName
? `${t(descName)}${
isUsingCustomModel({ modelName }) ? ' (' + config.customModelName + ')' : ''
}:`
: t('Loading...')}
</p>
)
}
AnswerTitle.propTypes = {
descName: PropTypes.string,
modelName: PropTypes.string,
}
export function ConversationItem({ type, content, descName, modelName, onRetry }) {
const { t } = useTranslation()
const [collapsed, setCollapsed] = useState(false)
const config = useConfig()
switch (type) {
case 'question':
@@ -49,23 +67,17 @@ export function ConversationItem({ type, content, session, onRetry }) {
return (
<div className={type} dir="auto">
<div className="gpt-header">
<p style="white-space: nowrap;">
{session && session.aiName
? `${t(session.aiName)}${
isUsingCustomModel(session) ? ' (' + config.customModelName + ')' : ''
}:`
: t('Loading...')}
</p>
<AnswerTitle descName={descName} modelName={modelName} />
<div className="gpt-util-group">
{onRetry && (
<span title={t('Retry')} className="gpt-util-icon" onClick={onRetry}>
<SyncIcon size={14} />
</span>
)}
{session && (
{modelName && (
<CopyButton contentFn={() => content.replace(/\n<hr\/>$/, '')} size={14} />
)}
{session && <ReadButton contentFn={() => content} size={14} />}
{modelName && <ReadButton contentFn={() => content} size={14} />}
{!collapsed ? (
<span
title={t('Collapse')}
@@ -128,8 +140,9 @@ export function ConversationItem({ type, content, session, onRetry }) {
ConversationItem.propTypes = {
type: PropTypes.oneOf(['question', 'answer', 'error']).isRequired,
content: PropTypes.string.isRequired,
session: PropTypes.object.isRequired,
descName: PropTypes.string,
modelName: PropTypes.string,
onRetry: PropTypes.func,
}
export default ConversationItem
export default memo(ConversationItem)
+13 -9
View File
@@ -1,5 +1,5 @@
import Browser from 'webextension-polyfill'
import { cloneElement, useEffect, useState } from 'react'
import { cloneElement, useCallback, useEffect, useState } from 'react'
import ConversationCard from '../ConversationCard'
import PropTypes from 'prop-types'
import { config as toolsConfig } from '../../content-script/selection-tools'
@@ -70,10 +70,18 @@ function FloatingToolbar(props) {
updatePosition() // avoid jitter
}
const onDock = () => {
const onClose = useCallback(() => {
props.container.remove()
}, [])
const onDock = useCallback(() => {
props.container.className = 'chatgptbox-toolbar-container-not-queryable'
setCloseable(true)
}
}, [])
const onUpdate = useCallback(() => {
updatePosition()
}, [position])
if (config.alwaysPinWindow) onDock()
@@ -95,14 +103,10 @@ function FloatingToolbar(props) {
question={prompt}
draggable={true}
closeable={closeable}
onClose={() => {
props.container.remove()
}}
onClose={onClose}
dockable={props.dockable}
onDock={onDock}
onUpdate={() => {
updatePosition()
}}
onUpdate={onUpdate}
/>
</div>
</div>
+2 -1
View File
@@ -8,6 +8,7 @@ import remarkGfm from 'remark-gfm'
import remarkBreaks from 'remark-breaks'
import { Pre } from './Pre'
import { Hyperlink } from './Hyperlink'
import { memo } from 'react'
export function MarkdownRender(props) {
return (
@@ -41,4 +42,4 @@ MarkdownRender.propTypes = {
...ReactMarkdown.propTypes,
}
export default MarkdownRender
export default memo(MarkdownRender)