From f12ff5f32136430146d7bb922995942c9f5c9c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Thu, 2 Jan 2025 15:30:21 +0800 Subject: [PATCH 1/4] docs: update docs --- examples/basic.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/basic.tsx b/examples/basic.tsx index 2f14a202..d63f27d3 100644 --- a/examples/basic.tsx +++ b/examples/basic.tsx @@ -10,7 +10,8 @@ const MyItem: React.ForwardRefRenderFunction = ({ id }, ref) => ( { @@ -44,7 +45,7 @@ const TYPES = [ ]; const onScroll: React.UIEventHandler = (e) => { - console.log('scroll:', e.currentTarget.scrollTop); + // console.log('scroll:', e.currentTarget.scrollTop); }; const Demo = () => { @@ -53,6 +54,12 @@ const Demo = () => { const [type, setType] = React.useState('dom'); const listRef = React.useRef(null); + React.useEffect(() => { + listRef.current.scrollTo({ + index: 99999999, + }); + }, []); + return (
From 174c2c1ac046b28d747895e46c24596bf7d21187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 3 Jan 2025 12:01:18 +0800 Subject: [PATCH 2/4] chore: sync back --- src/List.tsx | 21 +++++++++++++++++++++ src/utils/CacheMap.ts | 15 +++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/List.tsx b/src/List.tsx index c1b4521b..d403a96a 100644 --- a/src/List.tsx +++ b/src/List.tsx @@ -271,6 +271,27 @@ export function RawList(props: ListProps, ref: React.Ref) { rangeRef.current.start = start; rangeRef.current.end = end; + React.useLayoutEffect(() => { + console.log('>>>> offsetTop', offsetTop); + console.log('>>>>', scrollHeight, start, end, heights.getRecord()); + + 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) => { + console.log('-->', diffHeight, ori); + return ori + diffHeight; + }); + } + } + + heights.resetRecord(); + }, [scrollHeight]); + // ================================= Size ================================= const [size, setSize] = React.useState({ width: 0, height }); diff --git a/src/utils/CacheMap.ts b/src/utils/CacheMap.ts index a428bbb4..e3d2cef2 100644 --- a/src/utils/CacheMap.ts +++ b/src/utils/CacheMap.ts @@ -8,6 +8,8 @@ class CacheMap { // `useMemo` no need to update if `id` not change id: number = 0; + diffKeys = new Set(); + constructor() { this.maps = Object.create(null); } @@ -15,11 +17,24 @@ class CacheMap { 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; From 636c04a522a3299659d0a63a80ae9dda5aad97a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 3 Jan 2025 14:26:01 +0800 Subject: [PATCH 3/4] chore: use promise to enhance scroll logic --- src/List.tsx | 7 +++---- src/hooks/useHeights.tsx | 14 ++++++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/List.tsx b/src/List.tsx index d403a96a..95b46810 100644 --- a/src/List.tsx +++ b/src/List.tsx @@ -271,10 +271,10 @@ export function RawList(props: ListProps, ref: React.Ref) { 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(() => { - console.log('>>>> offsetTop', offsetTop); - console.log('>>>>', scrollHeight, start, end, heights.getRecord()); - const changedRecord = heights.getRecord(); if (changedRecord.size === 1) { const recordKey = Array.from(changedRecord)[0]; @@ -283,7 +283,6 @@ export function RawList(props: ListProps, ref: React.Ref) { const realStartHeight = heights.get(recordKey); const diffHeight = realStartHeight - itemHeight; syncScrollTop((ori) => { - console.log('-->', diffHeight, ori); return ori + diffHeight; }); } diff --git a/src/hooks/useHeights.tsx b/src/hooks/useHeights.tsx index 6ab1881c..b4c6955d 100644 --- a/src/hooks/useHeights.tsx +++ b/src/hooks/useHeights.tsx @@ -1,5 +1,4 @@ import findDOMNode from 'rc-util/lib/Dom/findDOMNode'; -import raf from 'rc-util/lib/raf'; import * as React from 'react'; import { useEffect, useRef } from 'react'; import type { GetKey } from '../interface'; @@ -23,10 +22,11 @@ export default function useHeights( const [updatedMark, setUpdatedMark] = React.useState(0); const instanceRef = useRef(new Map()); const heightsRef = useRef(new CacheMap()); - const collectRafRef = useRef(); + + const promiseIdRef = useRef(0); function cancelRaf() { - raf.cancel(collectRafRef.current); + promiseIdRef.current += 1; } function collectHeight(sync = false) { @@ -56,7 +56,13 @@ export default function useHeights( if (sync) { doCollect(); } else { - collectRafRef.current = raf(doCollect); + promiseIdRef.current += 1; + const id = promiseIdRef.current; + Promise.resolve().then(() => { + if (id === promiseIdRef.current) { + doCollect(); + } + }); } } From c568e8bdd6e9e770e0ededd55ba83ca0f7691ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 3 Jan 2025 15:06:13 +0800 Subject: [PATCH 4/4] docs: back --- examples/basic.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/examples/basic.tsx b/examples/basic.tsx index d63f27d3..2f14a202 100644 --- a/examples/basic.tsx +++ b/examples/basic.tsx @@ -10,8 +10,7 @@ const MyItem: React.ForwardRefRenderFunction = ({ id }, ref) => ( { @@ -45,7 +44,7 @@ const TYPES = [ ]; const onScroll: React.UIEventHandler = (e) => { - // console.log('scroll:', e.currentTarget.scrollTop); + console.log('scroll:', e.currentTarget.scrollTop); }; const Demo = () => { @@ -54,12 +53,6 @@ const Demo = () => { const [type, setType] = React.useState('dom'); const listRef = React.useRef(null); - React.useEffect(() => { - listRef.current.scrollTo({ - index: 99999999, - }); - }, []); - return (