Skip to content

Commit

Permalink
fix: use Observer to check sticky bar (#1099)
Browse files Browse the repository at this point in the history
* fix: use Observer to check sticky bar

* add raf
  • Loading branch information
linxianxi authored Apr 2, 2024
1 parent 3fc8cbd commit 80c86bf
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 33 deletions.
7 changes: 5 additions & 2 deletions src/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,10 @@ function Table<RecordType extends DefaultRecordType>(
const fixColumn = horizonScroll && flattenColumns.some(({ fixed }) => fixed);

// Sticky
const stickyRef = React.useRef<{ setScrollLeft: (left: number) => void }>();
const stickyRef = React.useRef<{
setScrollLeft: (left: number) => void;
checkScrollBarVisible: () => void;
}>();
const { isSticky, offsetHeader, offsetSummary, offsetScroll, stickyClassName, container } =
useSticky(sticky, prefixCls);

Expand Down Expand Up @@ -486,6 +489,7 @@ function Table<RecordType extends DefaultRecordType>(
};

const onFullTableResize = ({ width }) => {
stickyRef.current?.checkScrollBarVisible();
let mergedWidth = fullTableRef.current ? fullTableRef.current.offsetWidth : width;
if (useInternalHooks && getContainerWidth && fullTableRef.current) {
mergedWidth = getContainerWidth(fullTableRef.current, mergedWidth) || mergedWidth;
Expand Down Expand Up @@ -716,7 +720,6 @@ function Table<RecordType extends DefaultRecordType>(
scrollBodyRef={scrollBodyRef}
onScroll={onInternalScroll}
container={container}
data={data}
/>
)}
</>
Expand Down
68 changes: 37 additions & 31 deletions src/stickyScrollBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import getScrollBarSize from 'rc-util/lib/getScrollBarSize';
import * as React from 'react';
import TableContext from './context/TableContext';
import { useLayoutState } from './hooks/useFrame';
import raf from 'rc-util/lib/raf';

interface StickyScrollBarProps {
scrollBodyRef: React.RefObject<HTMLDivElement>;
onScroll: (params: { scrollLeft?: number }) => void;
offsetScroll: number;
container: HTMLElement | Window;
data?: readonly any[];
}

const StickyScrollBar: React.ForwardRefRenderFunction<unknown, StickyScrollBarProps> = (
{ scrollBodyRef, onScroll, offsetScroll, container, data },
{ scrollBodyRef, onScroll, offsetScroll, container },
ref,
) => {
const prefixCls = useContext(TableContext, 'prefixCls');
Expand All @@ -40,6 +40,14 @@ const StickyScrollBar: React.ForwardRefRenderFunction<unknown, StickyScrollBarPr
x: 0,
});
const [isActive, setActive] = React.useState(false);
const rafRef = React.useRef<number | null>(null);

React.useEffect(
() => () => {
raf.cancel(rafRef.current);
},
[],
);

const onMouseUp: React.MouseEventHandler<HTMLDivElement> = () => {
setActive(false);
Expand Down Expand Up @@ -82,30 +90,32 @@ const StickyScrollBar: React.ForwardRefRenderFunction<unknown, StickyScrollBarPr
};

const checkScrollBarVisible = () => {
if (!scrollBodyRef.current) {
return;
}
const tableOffsetTop = getOffset(scrollBodyRef.current).top;
const tableBottomOffset = tableOffsetTop + scrollBodyRef.current.offsetHeight;
const currentClientOffset =
container === window
? document.documentElement.scrollTop + window.innerHeight
: getOffset(container).top + (container as HTMLElement).clientHeight;

if (
tableBottomOffset - getScrollBarSize() <= currentClientOffset ||
tableOffsetTop >= currentClientOffset - offsetScroll
) {
setScrollState(state => ({
...state,
isHiddenScrollBar: true,
}));
} else {
setScrollState(state => ({
...state,
isHiddenScrollBar: false,
}));
}
rafRef.current = raf(() => {
if (!scrollBodyRef.current) {
return;
}
const tableOffsetTop = getOffset(scrollBodyRef.current).top;
const tableBottomOffset = tableOffsetTop + scrollBodyRef.current.offsetHeight;
const currentClientOffset =
container === window
? document.documentElement.scrollTop + window.innerHeight
: getOffset(container).top + (container as HTMLElement).clientHeight;

if (
tableBottomOffset - getScrollBarSize() <= currentClientOffset ||
tableOffsetTop >= currentClientOffset - offsetScroll
) {
setScrollState(state => ({
...state,
isHiddenScrollBar: true,
}));
} else {
setScrollState(state => ({
...state,
isHiddenScrollBar: false,
}));
}
});
};

const setScrollLeft = (left: number) => {
Expand All @@ -119,6 +129,7 @@ const StickyScrollBar: React.ForwardRefRenderFunction<unknown, StickyScrollBarPr

React.useImperativeHandle(ref, () => ({
setScrollLeft,
checkScrollBarVisible,
}));

React.useEffect(() => {
Expand Down Expand Up @@ -156,11 +167,6 @@ const StickyScrollBar: React.ForwardRefRenderFunction<unknown, StickyScrollBarPr
}
}, [scrollState.isHiddenScrollBar]);

// The best way is to use ResizeObserver to detect the body height, but this way is enough
React.useEffect(() => {
checkScrollBarVisible();
}, [data]);

if (bodyScrollWidth <= bodyWidth || !scrollBarWidth || scrollState.isHiddenScrollBar) {
return null;
}
Expand Down

0 comments on commit 80c86bf

Please sign in to comment.