mirror of https://github.com/msgbyte/tailchat
refactor: 迭代自实现虚拟列表并升级react-virtuoso
parent
f038d08af8
commit
9500a2fab0
@ -1,14 +1,82 @@
|
||||
import React, { useRef } from 'react';
|
||||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import { ResizeWatcher } from './ResizeWatcher';
|
||||
import { Scroller, ScrollerRef } from './Scroller';
|
||||
import { useUpdate } from 'ahooks';
|
||||
|
||||
export const VirtualChatList: React.FC = React.memo(() => {
|
||||
interface VirtualChatListProps<ItemType> {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
innerStyle?: React.CSSProperties;
|
||||
getItemKey?: (item: ItemType) => string;
|
||||
items: ItemType[];
|
||||
itemContent: (item: ItemType, index: number) => React.ReactNode;
|
||||
}
|
||||
|
||||
const defaultContainerStyle: React.CSSProperties = {
|
||||
overflow: 'hidden',
|
||||
};
|
||||
|
||||
const defaultInnerStyle: React.CSSProperties = {
|
||||
height: '100%',
|
||||
};
|
||||
|
||||
const scrollerStyle: React.CSSProperties = {
|
||||
height: '100%',
|
||||
};
|
||||
|
||||
const InternalVirtualChatList = <ItemType extends object>(
|
||||
props: VirtualChatListProps<ItemType>
|
||||
) => {
|
||||
const scrollerRef = useRef<ScrollerRef>(null);
|
||||
const itemHeightCache = useMemo(() => new Map<ItemType, number>(), []);
|
||||
const forceUpdate = useUpdate();
|
||||
const style = useMemo(
|
||||
() => ({
|
||||
...defaultContainerStyle,
|
||||
...props.style,
|
||||
}),
|
||||
[props.style]
|
||||
);
|
||||
const innerStyle = useMemo(
|
||||
() => ({
|
||||
...defaultInnerStyle,
|
||||
...props.innerStyle,
|
||||
}),
|
||||
[props.innerStyle]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// 挂载后滚动到底部
|
||||
scrollerRef.current?.scrollToBottom();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Scroller ref={scrollerRef}>
|
||||
{/* TODO */}
|
||||
<div>Foo</div>
|
||||
</Scroller>
|
||||
<div className="virtual-chat-list" style={style}>
|
||||
<Scroller ref={scrollerRef} style={scrollerStyle} innerStyle={innerStyle}>
|
||||
{props.items.map((item, i) => (
|
||||
<div
|
||||
key={props.getItemKey ? props.getItemKey(item) : i}
|
||||
className="virtual-chat-list__item"
|
||||
style={{ height: itemHeightCache.get(item) }}
|
||||
>
|
||||
<ResizeWatcher
|
||||
onResize={(size) => {
|
||||
itemHeightCache.set(item, size.height);
|
||||
forceUpdate();
|
||||
}}
|
||||
>
|
||||
{props.itemContent(item, i)}
|
||||
</ResizeWatcher>
|
||||
</div>
|
||||
))}
|
||||
</Scroller>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
type VirtualChatListInterface = typeof InternalVirtualChatList & React.FC;
|
||||
|
||||
export const VirtualChatList: VirtualChatListInterface = React.memo(
|
||||
InternalVirtualChatList
|
||||
) as any;
|
||||
VirtualChatList.displayName = 'VirtualChatList';
|
||||
|
@ -0,0 +1,55 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { VirtualChatList } from 'tailchat-design';
|
||||
import { ChatMessage, useMemoizedFn } from 'tailchat-shared';
|
||||
import { buildMessageItemRow } from './Item';
|
||||
import type { MessageListProps } from './types';
|
||||
|
||||
/**
|
||||
* WIP:
|
||||
* 自制的虚拟列表
|
||||
*/
|
||||
|
||||
const style: React.CSSProperties = {
|
||||
// height: '100%',
|
||||
flex: 1,
|
||||
};
|
||||
|
||||
export const VirtualizedMessageList: React.FC<MessageListProps> = React.memo(
|
||||
(props) => {
|
||||
// useSharedEventHandler('sendMessage', () => {
|
||||
// listRef.current?.scrollToIndex({
|
||||
// index: 'LAST',
|
||||
// align: 'end',
|
||||
// behavior: 'smooth',
|
||||
// });
|
||||
// });
|
||||
|
||||
// const handleLoadMore = useMemoizedFn(() => {
|
||||
// if (props.isLoadingMore) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (props.hasMoreMessage) {
|
||||
// props.onLoadMore();
|
||||
// }
|
||||
// });
|
||||
|
||||
const itemContent = useMemoizedFn((item: ChatMessage, index: number) => {
|
||||
return buildMessageItemRow(props.messages, index);
|
||||
});
|
||||
|
||||
const getItemKey = useCallback((item: ChatMessage) => {
|
||||
return String(item._id);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<VirtualChatList
|
||||
style={style}
|
||||
items={props.messages}
|
||||
itemContent={itemContent}
|
||||
getItemKey={getItemKey}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
VirtualizedMessageList.displayName = 'VirtualizedMessageList';
|
Loading…
Reference in New Issue