chore: infinite scroller
This commit is contained in:
@@ -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;
|
||||
};
|
||||
Reference in New Issue
Block a user