You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailchat/client/packages/design/components/VirtualChatList/index.tsx

83 lines
2.2 KiB
TypeScript

import React, { useEffect, useMemo, useRef } from 'react';
import { ResizeWatcher } from './ResizeWatcher';
import { Scroller, ScrollerRef } from './Scroller';
import { useUpdate } from 'ahooks';
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 (
<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';