refactor: 动态列表的代码优化

pull/13/head
moonrailgun 3 years ago
parent f331ec3071
commit ebebeb5f0a

@ -1,6 +1,8 @@
import DynamicSizeList from '@/components/DynamicVirtualizedList/DynamicSizeList';
import DynamicSizeList, {
OnScrollInfo,
} from '@/components/DynamicVirtualizedList/DynamicSizeList';
import { Divider } from 'antd';
import React, { useRef } from 'react';
import React, { useRef, useState } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import {
ChatMessage,
@ -33,9 +35,15 @@ export const VirtualizedMessageList: React.FC<VirtualizedMessageListProps> =
React.memo((props) => {
const listRef = useRef<DynamicSizeList>(null);
const postListRef = useRef<any>(null);
const [isBottom, setIsBottom] = useState(true);
const onScroll = (info: any) => {
const onScroll = (info: OnScrollInfo) => {
console.log('onScroll', info);
if (info.clientHeight + info.scrollOffset === info.scrollHeight) {
// 当前滚动条位于底部
setIsBottom(true);
}
};
const initScrollToIndex = () => {
@ -60,13 +68,13 @@ export const VirtualizedMessageList: React.FC<VirtualizedMessageListProps> =
};
const renderRow = ({ data, itemId, style }: any) => {
const index = data.indexOf(itemId);
const message = props.messages.find((m) => m._id === itemId); // TODO: 这里是因为mattermost的动态列表传的id因此只能这边再用id找回可以看看是否可以优化
if (!message) {
const index = props.messages.findIndex((m) => m._id === itemId); // TODO: 这里是因为mattermost的动态列表传的id因此只能这边再用id找回可以看看是否可以优化
if (index === -1) {
return <div />;
}
const message = props.messages[index];
let showDate = true;
let showAvatar = true;
const messageCreatedAt = new Date(message.createdAt ?? '');
@ -91,7 +99,7 @@ export const VirtualizedMessageList: React.FC<VirtualizedMessageListProps> =
}
return (
<div key={message._id}>
<div key={message._id} data-debug={JSON.stringify(index)}>
{showDate && (
<Divider className="text-sm opacity-40 px-6 font-normal select-none">
{getMessageTimeDiff(messageCreatedAt)}
@ -115,8 +123,7 @@ export const VirtualizedMessageList: React.FC<VirtualizedMessageListProps> =
ref={listRef}
height={height}
width={width}
className="post-list__dynamic"
itemData={props.messages.map((m) => m._id)}
itemData={props.messages.map((m) => m._id).reverse()}
overscanCountForward={OVERSCAN_COUNT_FORWARD}
overscanCountBackward={OVERSCAN_COUNT_BACKWARD}
onScroll={onScroll}
@ -127,7 +134,7 @@ export const VirtualizedMessageList: React.FC<VirtualizedMessageListProps> =
innerListStyle={postListStyle}
initRangeToRender={initRangeToRender}
// loaderId={PostListRowListIds.OLDER_MESSAGES_LOADER}
// correctScrollToBottom={this.props.atLatestPost}
correctScrollToBottom={isBottom}
onItemsRendered={onItemsRendered}
scrollToFailed={scrollToFailed}
>

@ -1,4 +1,5 @@
import memoizeOne from 'memoize-one';
import React from 'react';
import { createElement, PureComponent } from 'react';
import { ItemMeasurer } from './ItemMeasurer';
@ -129,13 +130,13 @@ const getItemSize = (props: any, index: any, listMetaData: any) => {
return getItemMetadata(props, index, listMetaData).size;
};
type OnScrollArgs = {
export interface OnScrollInfo {
scrollDirection: 'backward' | 'forward';
scrollOffset: number;
scrollUpdateWasRequested: boolean;
clientHeight: number;
scrollHeight: number;
};
}
interface DynamicSizeListProps {
canLoadMorePosts: () => void;
@ -149,17 +150,20 @@ interface DynamicSizeListProps {
initScrollToIndex: () => any;
initialScrollOffset?: number;
innerRef: React.RefObject<any>;
innerTagName?: string;
outerTagName?: string;
itemData: string[];
onItemsRendered: (args: any) => void;
onScroll: (scrollArgs: OnScrollArgs) => void;
onScroll: (scrollArgs: OnScrollInfo) => void;
overscanCountBackward: number;
overscanCountForward: number;
style: React.CSSProperties;
width: number;
outerRef?: any;
className?: string;
/**
*
*
*/
correctScrollToBottom?: boolean;
innerListStyle?: React.CSSProperties;
loaderId?: string;
@ -194,13 +198,6 @@ export default class DynamicSizeList extends PureComponent<
_mountingCorrections = 0;
_correctedInstances = 0;
innerRefWidth = 0;
static defaultProps = {
innerTagName: 'div',
itemData: undefined,
outerTagName: 'div',
overscanCountForward: 30,
overscanCountBackward: 10,
};
state: DynamicSizeListState = {
scrollDirection: 'backward',
@ -416,39 +413,30 @@ export default class DynamicSizeList extends PureComponent<
}
render() {
const {
className,
innerRef,
innerTagName,
outerTagName,
style,
innerListStyle,
} = this.props;
const { className, innerRef, style, innerListStyle } = this.props;
const onScroll = this._onScrollVertical;
const items = this._renderItems();
return createElement(
outerTagName!,
{
className,
onScroll,
ref: this._outerRefSetter,
style: {
return (
<div
className={className}
onScroll={onScroll}
ref={this._outerRefSetter}
style={{
WebkitOverflowScrolling: 'touch',
overflowY: 'auto',
overflowAnchor: 'none',
willChange: 'transform',
width: '100%',
...style,
},
},
createElement(innerTagName!, {
children: items,
ref: innerRef,
style: innerListStyle,
})
}}
>
<div ref={innerRef} style={innerListStyle}>
{items}
</div>
</div>
);
}
@ -618,6 +606,9 @@ export default class DynamicSizeList extends PureComponent<
return style;
};
/**
*
*/
_getRangeToRender(scrollTop = 0): number[] {
const { itemData, overscanCountForward, overscanCountBackward } =
this.props;
@ -709,9 +700,9 @@ export default class DynamicSizeList extends PureComponent<
};
_handleNewMeasurements = (
key: any,
newSize: any,
forceScrollCorrection: any
key: string,
newSize: number,
forceScrollCorrection: boolean
) => {
const { itemSizeMap } = this._listMetaData;
const { itemData } = this.props;
@ -841,31 +832,26 @@ export default class DynamicSizeList extends PureComponent<
isItemInLocalPosts ||
isLoader
) {
const item = createElement(children, {
const item: React.ReactElement = createElement(children, {
data: itemData,
itemId,
});
// Always wrap children in a ItemMeasurer to detect changes in size.
items.push(
createElement(ItemMeasurer, {
handleNewMeasurements: this._handleNewMeasurements,
index,
item,
key: itemId,
size,
itemId,
width,
onUnmount: this._onItemRowUnmount,
})
<ItemMeasurer
handleNewMeasurements={this._handleNewMeasurements}
index={index}
item={item}
key={itemId}
size={size}
itemId={itemId}
width={width}
onUnmount={this._onItemRowUnmount}
/>
);
} else {
items.push(
createElement('div', {
key: itemId,
style,
})
);
items.push(<div key={itemId} style={style} />);
}
}
}

@ -71,12 +71,16 @@ const expandScrollDelta = shrinkScrollDelta + 10;
interface ItemMeasurerProps {
size: number;
handleNewMeasurements: any;
itemId: any;
item: any;
handleNewMeasurements: (
key: string,
newSize: number,
forceScrollCorrection: boolean
) => void;
itemId: string;
item: React.ReactElement;
width: number;
onUnmount: any;
index: any;
onUnmount: (itemId: string, index: number) => void;
index: number;
}
export class ItemMeasurer extends Component<ItemMeasurerProps> {
@ -141,9 +145,7 @@ export class ItemMeasurer extends Component<ItemMeasurerProps> {
}
const { onUnmount, itemId, index } = this.props;
if (onUnmount) {
onUnmount(itemId, index);
}
typeof onUnmount === 'function' && onUnmount(itemId, index);
}
scrollingDiv = (event: any) => {
@ -164,7 +166,7 @@ export class ItemMeasurer extends Component<ItemMeasurerProps> {
};
const renderItem = (
<div style={{ position: 'relative' }}>
<div className="relative">
{item}
<div style={scrollableContainerStyles}>
<div dir="ltr" style={scrollableWrapperStyle}>
@ -195,7 +197,7 @@ export class ItemMeasurer extends Component<ItemMeasurerProps> {
return this.renderItems();
}
_measureItem = (forceScrollCorrection: any) => {
_measureItem = (forceScrollCorrection: boolean) => {
const { handleNewMeasurements, size: oldSize, itemId } = this.props;
const node = this._node;

Loading…
Cancel
Save