Я реализовал компонент пагинации. Проблема в том, что мне нужна пагинация сообщений в чате, и, соответственно, скролл должен идти вверх, но в таком случае при добавлении новых сообщений этот скролл “прилипает” к верху элемента div.
Мой компонент выглядит так:
onst paginationRef = useRef(paginateFn);
const dataCountRef = useRef(0);
const fixedScroll = useScroll({
paginationProcess, // лоадер перед тем как отрисуются данные
scrollElement, // сам элемент
paginationScroll, // вариативность скролла - bottom или top
scrollPositionMount, // boolean чтобы при переходе к диалогу скролл был в самом низу
willTriggerScrollPosition, // это то что триггерит чтобы скролл прилипал к низу элемента, в моем случае если в чат пришло новое сообщение
});
useLayoutEffect(() => {
paginationRef.current = paginateFn;
}, [paginateFn]);
useLayoutEffect(() => {
dataCountRef.current = dataCount;
}, [dataCount]);
const isClockPaginate = useCallback(
(
paginationScroll: ScrollPaginationProps['paginationScroll'],
scrollData: { scrollTop: number; clientHeight: number; scrollHeight: number },
) => {
const { scrollTop, clientHeight, scrollHeight } = scrollData;
if (paginationScroll === 'bottom') {
return scrollTop + clientHeight >= scrollHeight - 120;
}
return scrollTop <= 100;
},
[],
);
useEffect(() => {
const fn = (nextLength: number) => paginationRef.current(nextLength);
const handleScroll = () => {
if (!scrollElement) {
return;
}
const { scrollTop, clientHeight, scrollHeight } = scrollElement;
fixedScroll.current.scrollTop = scrollTop;
const direction = isClockPaginate(paginationScroll, { scrollTop, clientHeight, scrollHeight });
if (!paginationProcess && direction) {
fn(dataCountRef.current);
}
};
window.addEventListener('wheel', handleScroll);
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('wheel', handleScroll);
window.removeEventListener('scroll', handleScroll);
};
}, [scrollElement, paginationProcess, paginationScroll]);
И есть хук, который я сделал чтобы при загрузке данных и скроллинге элемента скролл хотя бы примерно оставался на своем месте
const fixScrollPosition = useRef({
prevScroll: 0,
currentScroll: 0,
scrollTop: 0,
});
// то что я пробовал сделать со скроллом
useLayoutEffect(() => {
if (!scrollElement) {
return;
}
const { scrollHeight } = scrollElement;
if (paginationProcess) {
fixScrollPosition.current.prevScroll = scrollHeight;
} else {
fixScrollPosition.current.currentScroll = scrollHeight;
}
}, [paginationProcess, scrollElement, scrollPositionMount]);
useLayoutEffect(() => {
if (!scrollElement) {
return;
}
const { currentScroll, prevScroll, scrollTop } = fixScrollPosition.current;
if (paginationScroll === 'top') {
const calculateScrollPosition = currentScroll - prevScroll;
const scrollPaginate = scrollTop > 100 ? calculateScrollPosition + scrollTop : calculateScrollPosition;
scrollElement.scrollTo(0, scrollPaginate);
}
}, [paginationProcess, paginationScroll, scrollElement, fixScrollPosition]);
// если открыли другой диалог то скролл будет внизу
useLayoutEffect(() => {
if (!scrollElement || !scrollPositionMount) {
return;
}
if (paginationScroll === 'top') {
scrollElement.scrollTo(0, scrollElement.scrollHeight);
}
}, [scrollElement, paginationScroll, scrollPositionMount]);
// если пришло новое сообщение то скролл будет внизу
useLayoutEffect(() => {
if (!scrollElement) {
return;
}
if (paginationScroll === 'top') {
scrollElement.scrollTo(0, scrollElement.scrollHeight);
}
}, [scrollElement, paginationScroll, willTriggerScrollPosition]);
Пробовал добавить return если scrollTop > 100, но тогда скролл телепортируется вниз
Я думаю, у меня реализация не совсем корректная
Kreet is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.