diff --git a/packages/hooks/src/useInfiniteScroll/__tests__/index.test.ts b/packages/hooks/src/useInfiniteScroll/__tests__/index.test.ts index 12d0c8654b..f6cfb6699a 100644 --- a/packages/hooks/src/useInfiniteScroll/__tests__/index.test.ts +++ b/packages/hooks/src/useInfiniteScroll/__tests__/index.test.ts @@ -17,8 +17,6 @@ export async function mockRequest() { }; } -const targetEl = document.createElement('div'); - const setup = (service: Service, options?: InfiniteScrollOptions) => renderHook(() => useInfiniteScroll(service, options)); @@ -76,6 +74,7 @@ describe('useInfiniteScroll', () => { }); it('should auto load when scroll to bottom', async () => { + const targetEl = document.createElement('div'); const events = {}; const mockAddEventListener = jest .spyOn(targetEl, 'addEventListener') @@ -125,6 +124,61 @@ describe('useInfiniteScroll', () => { mockAddEventListener.mockRestore(); }); + it('should auto load when scroll to top', async () => { + const targetEl = document.createElement('div'); + const events = {}; + const mockAddEventListener = jest + .spyOn(targetEl, 'addEventListener') + .mockImplementation((eventName, callback) => { + events[eventName] = callback; + }); + const { result } = setup(mockRequest, { + target: targetEl, + isNoMore: (d) => d?.nextId === undefined, + isInverse: true, + }); + expect(result.current.loading).toBe(true); + + events['scroll'](); + + await act(async () => { + jest.advanceTimersByTime(1000); + }); + expect(result.current.loading).toBe(false); + // mock scroll + const currentTargetPosition = { + clientHeight: { + value: 400, + }, + scrollHeight: { + value: 300, + }, + scrollTop: { + value: 100, + }, + }; + Object.defineProperties(targetEl, currentTargetPosition); + + act(() => { + events['scroll'](); + }); + + expect(result.current.loadingMore).toBe(true); + await act(async () => { + jest.advanceTimersByTime(1000); + }); + expect(result.current.loadingMore).toBe(false); + + // not work when no more + expect(result.current.noMore).toBe(true); + act(() => { + events['scroll'](); + }); + expect(result.current.loadingMore).toBe(false); + + mockAddEventListener.mockRestore(); + }); + it('reload should be work', async () => { const fn = jest.fn(() => Promise.resolve({ list: [] })); const { result } = setup(fn); diff --git a/packages/hooks/src/useInfiniteScroll/index.tsx b/packages/hooks/src/useInfiniteScroll/index.tsx index a559c562d1..edaded520e 100644 --- a/packages/hooks/src/useInfiniteScroll/index.tsx +++ b/packages/hooks/src/useInfiniteScroll/index.tsx @@ -16,6 +16,7 @@ const useInfiniteScroll = ( isNoMore, threshold = 100, reloadDeps = [], + isInverse, manual, onBefore, onSuccess, @@ -99,7 +100,12 @@ const useInfiniteScroll = ( const scrollHeight = getScrollHeight(el); const clientHeight = getClientHeight(el); - if (scrollHeight - scrollTop <= clientHeight + threshold) { + const scrollBoundary = clientHeight + threshold; + const isReachToBottom = scrollHeight - scrollTop <= scrollBoundary; + const isReachToTop = scrollTop + scrollHeight <= scrollBoundary; + const isReachBoundary = isInverse ? isReachToTop : isReachToBottom; + + if (isReachBoundary) { loadMore(); } }; diff --git a/packages/hooks/src/useInfiniteScroll/types.ts b/packages/hooks/src/useInfiniteScroll/types.ts index 7687e6ff60..fcb6a40583 100644 --- a/packages/hooks/src/useInfiniteScroll/types.ts +++ b/packages/hooks/src/useInfiniteScroll/types.ts @@ -23,7 +23,7 @@ export interface InfiniteScrollOptions { target?: BasicTarget; isNoMore?: (data?: TData) => boolean; threshold?: number; - + isInverse?: boolean; manual?: boolean; reloadDeps?: DependencyList;