这样处理的原因是因为, 当你滑到最顶部再 push 元素, 会直接定位到顶部, 需要scrollIntoView
到之前的位置.
export function ContentComponent() {
const scrollEl = useRef<HTMLDivElement>(null);
const [distanceToBottom, setDistanceToBottom] = useState<number | null>(null);
// handle scroll event function, when scroll trigger it.
const handleScroll = async () => {
// when distance to top less than 300px
if (
message.length > 0 &&
Number(scrollEl.current?.scrollTop) < 300 &&
!loadingMessage &&
hasMessage
) {
// request API first
const { payload } = await asyncLoadMessage();
const distanceToTop = getTopSpace();
dispatch(asyncLoadMessage(payload));
// only when current position to top is 0px, need to reset scroll position
if (Number(distanceToTop) === 0) {
setDistanceToBottom(getBottomSpace());
}
}
};
useLayoutEffect(() => {
if (
scrollEl.current?.scrollTop !== undefined &&
distanceToBottom !== null
) {
scrollEl.current.scrollTop =
scrollEl.current.scrollHeight - distanceToBottom;
setDistanceToBottom(null);
}
}, [distanceToBottom]);
return (
<div
className="overflow-y-auto flex-1 relative px-3.5 py-0"
ref={scrollEl}
onScroll={throttle(handleScroll)}
>
<TipComponent />
{message.map((msg) => (
<MessageComponent key={msg._id} data={msg} />
))}
</div>
)
}