chore: infinite scroller

This commit is contained in:
jialin
2025-10-13 19:55:08 +08:00
parent 68d6993acd
commit 903500dcfa
15 changed files with 1335 additions and 277 deletions
@@ -0,0 +1,24 @@
import React from 'react';
import {
useInfiniteScroll,
UseInfiniteScrollOptions
} from './use-infinite-scroll';
const InfiniteScroller: React.FC<
UseInfiniteScrollOptions & { children: React.ReactNode }
> = (props) => {
const { children, ...restProps } = props;
const { observerRef } = useInfiniteScroll(restProps);
return (
<div>
{children}
<div ref={observerRef} style={{ height: 1 }}>
<span></span>
</div>
</div>
);
};
export default InfiniteScroller;
@@ -0,0 +1,49 @@
import { useMemoizedFn } from 'ahooks';
import { throttle } from 'lodash';
import { useEffect, useRef } from 'react';
import { useInView } from 'react-intersection-observer';
export interface UseInfiniteScrollOptions {
total: number;
current: number;
loading: boolean;
refresh: (nextPage: number) => void;
onBottom?: () => void;
throttleDelay?: number;
}
export function useInfiniteScroll({
total,
current,
loading,
refresh,
onBottom,
throttleDelay = 300
}: UseInfiniteScrollOptions) {
const { ref: observerRef, inView } = useInView({
threshold: 0.2
});
const isInitialLoad = useRef(true);
const throttledLoadMore = useMemoizedFn(
throttle(() => {
if (loading) return;
if (current >= total) return;
onBottom?.();
refresh(current + 1);
}, throttleDelay)
);
useEffect(() => {
if (inView) {
if (isInitialLoad.current) {
isInitialLoad.current = false;
return;
}
throttledLoadMore();
}
}, [inView, throttledLoadMore]);
return { observerRef };
}
@@ -0,0 +1,24 @@
import { createContext, useContext } from 'react';
interface ScrollerContextProps {
total: number;
current: number;
loading: boolean;
refresh: (nextPage: number) => void;
onBottom?: () => void;
throttleDelay?: number;
}
export const ScrollerContext = createContext<ScrollerContextProps>(
{} as ScrollerContextProps
);
export const useScrollerContext = () => {
const context = useContext(ScrollerContext);
if (!context) {
throw new Error(
'useScrollerContext must be used within a ScrollerProvider'
);
}
return context;
};