perf: 优化AutoFold 设计, 确保在长文本时减少渲染

pull/56/head
moonrailgun 3 years ago
parent 6d2cdfb1d7
commit 64d8cfc08e

@ -1,3 +1,4 @@
import { useMemoizedFn } from 'node_modules/tailchat-shared';
import React, { import React, {
PropsWithChildren, PropsWithChildren,
useEffect, useEffect,
@ -12,31 +13,28 @@ interface AutoFolderProps extends PropsWithChildren {
backgroundColor?: string; backgroundColor?: string;
} }
export const AutoFolder: React.FC<AutoFolderProps> = React.memo((props) => { export const AutoFolder: React.FC<AutoFolderProps> = React.memo((props) => {
const { maxHeight, showFullText = 'More', backgroundColor = 'white' } = props; const { showFullText = 'More', backgroundColor = 'white' } = props;
const [isShowFull, setIsShowFull] = useState(false); const [isShowFullBtn, setIsShowFullBtn] = useState(false); // 是否显示展示所有内容的按钮
const [isShowFull, setIsShowFull] = useState(false); // 是否点击按钮展示所有
const contentRef = useRef<HTMLDivElement>(null); const contentRef = useRef<HTMLDivElement>(null);
const observer = useMemo(
() =>
new window.ResizeObserver((entries) => {
if (entries[0]) {
const { height } = entries[0].contentRect;
if (height > maxHeight) {
setIsShowFull(false);
observer.disconnect(); // 触发一次则解除连接
} else {
setIsShowFull(true);
}
}
}),
[]
);
useEffect(() => { useEffect(() => {
if (!contentRef.current) { if (!contentRef.current) {
return; return;
} }
const observer = new window.ResizeObserver((entries) => {
if (entries[0]) {
const { height } = entries[0].contentRect;
if (height > maxHeight) {
setIsShowFull(false);
setIsShowFullBtn(true);
observer.disconnect(); // 触发一次则解除连接
}
}
});
observer.observe(contentRef.current); observer.observe(contentRef.current);
return () => { return () => {
@ -44,17 +42,30 @@ export const AutoFolder: React.FC<AutoFolderProps> = React.memo((props) => {
}; };
}, []); }, []);
const maxHeight = useMemo(() => {
if (isShowFull) {
return 'none';
} else {
return props.maxHeight;
}
}, [isShowFull, props.maxHeight]);
const handleClickShowFullBtn = useMemoizedFn(() => {
setIsShowFullBtn(false);
setIsShowFull(true);
});
return ( return (
<div <div
style={{ style={{
maxHeight: isShowFull ? 'none' : maxHeight, maxHeight,
overflow: 'hidden', overflow: 'hidden',
position: 'relative', position: 'relative',
}} }}
> >
<div ref={contentRef}>{props.children}</div> <div ref={contentRef}>{props.children}</div>
{!isShowFull && ( {isShowFullBtn && (
<div <div
style={{ style={{
position: 'absolute', position: 'absolute',
@ -66,7 +77,7 @@ export const AutoFolder: React.FC<AutoFolderProps> = React.memo((props) => {
backgroundImage: `linear-gradient(rgba(0,0,0,0), ${backgroundColor})`, backgroundImage: `linear-gradient(rgba(0,0,0,0), ${backgroundColor})`,
padding: '4px 0', padding: '4px 0',
}} }}
onClick={() => setIsShowFull(true)} onClick={handleClickShowFullBtn}
> >
{showFullText} {showFullText}
</div> </div>

@ -76,11 +76,15 @@ export const VirtualizedMessageList: React.FC<MessageListProps> = React.memo(
} }
); );
const itemContent = (virtuosoIndex: number) => { const computeItemKey = useMemoizedFn((index: number, item: ChatMessage) => {
return item?._id ?? index;
});
const itemContent = useMemoizedFn((virtuosoIndex: number) => {
const index = virtuosoIndex + numItemsPrepended - PREPEND_OFFSET; const index = virtuosoIndex + numItemsPrepended - PREPEND_OFFSET;
return buildMessageItemRow(props.messages, props.messages[index]._id); return buildMessageItemRow(props.messages, props.messages[index]._id);
}; });
return ( return (
<Virtuoso <Virtuoso
@ -88,6 +92,7 @@ export const VirtualizedMessageList: React.FC<MessageListProps> = React.memo(
ref={listRef} ref={listRef}
firstItemIndex={PREPEND_OFFSET - numItemsPrepended} firstItemIndex={PREPEND_OFFSET - numItemsPrepended}
initialTopMostItemIndex={Math.max(props.messages.length - 1, 0)} initialTopMostItemIndex={Math.max(props.messages.length - 1, 0)}
computeItemKey={computeItemKey}
totalCount={props.messages.length} totalCount={props.messages.length}
overscan={{ overscan={{
main: 450, main: 450,

Loading…
Cancel
Save