Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
CoderSerio authored Jan 7, 2025
2 parents 325c740 + 10ca51d commit debf618
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rc-virtual-list",
"version": "3.16.1",
"version": "3.17.0",
"description": "React Virtual List Component",
"engines": {
"node": ">=8.x"
Expand Down
20 changes: 20 additions & 0 deletions src/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,26 @@ export function RawList<T>(props: ListProps<T>, ref: React.Ref<ListRef>) {
rangeRef.current.start = start;
rangeRef.current.end = end;

// When scroll up, first visible item get real height may not same as `itemHeight`,
// Which will make scroll jump.
// Let's sync scroll top to avoid jump
React.useLayoutEffect(() => {
const changedRecord = heights.getRecord();
if (changedRecord.size === 1) {
const recordKey = Array.from(changedRecord)[0];
const startIndexKey = getKey(mergedData[start]);
if (startIndexKey === recordKey) {
const realStartHeight = heights.get(recordKey);
const diffHeight = realStartHeight - itemHeight;
syncScrollTop((ori) => {
return ori + diffHeight;
});
}
}

heights.resetRecord();
}, [scrollHeight]);

// ================================= Size =================================
const [size, setSize] = React.useState({ width: 0, height });

Expand Down
14 changes: 10 additions & 4 deletions src/hooks/useHeights.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import raf from 'rc-util/lib/raf';
import * as React from 'react';
import { useEffect, useRef } from 'react';
import type { GetKey } from '../interface';
Expand All @@ -22,10 +21,11 @@ export default function useHeights<T>(
const [updatedMark, setUpdatedMark] = React.useState(0);
const instanceRef = useRef(new Map<React.Key, HTMLElement>());
const heightsRef = useRef(new CacheMap());
const collectRafRef = useRef<number>();

const promiseIdRef = useRef<number>(0);

function cancelRaf() {
raf.cancel(collectRafRef.current);
promiseIdRef.current += 1;
}

function collectHeight(sync = false) {
Expand Down Expand Up @@ -54,7 +54,13 @@ export default function useHeights<T>(
if (sync) {
doCollect();
} else {
collectRafRef.current = raf(doCollect);
promiseIdRef.current += 1;
const id = promiseIdRef.current;
Promise.resolve().then(() => {
if (id === promiseIdRef.current) {
doCollect();
}
});
}
}

Expand Down
15 changes: 15 additions & 0 deletions src/utils/CacheMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,33 @@ class CacheMap {
// `useMemo` no need to update if `id` not change
id: number = 0;

diffKeys = new Set<React.Key>();

constructor() {
this.maps = Object.create(null);
}

set(key: React.Key, value: number) {
this.maps[key as string] = value;
this.id += 1;
this.diffKeys.add(key as string);
}

get(key: React.Key) {
return this.maps[key as string];
}

/**
* CacheMap will record the key changed.
* To help to know what's update in the next render.
*/
resetRecord() {
this.diffKeys.clear();
}

getRecord() {
return this.diffKeys;
}
}

export default CacheMap;

0 comments on commit debf618

Please sign in to comment.