In many mobile browsers, a "pull down" gesture at the top of the page can trigger the "pull-to-refresh" functionality. While useful in some scenarios, this behavior can be undesirable in web applications that utilize touch elements or where the page should not be reloaded.
We can use touch events (touchstart and touchmove) to detect when the user tries to "pull down" from the top of the page. In this case, we can prevent the default refresh action, ensuring that normal scrolling continues to work.
To do this, I created the component below:
import { ReactNode, useEffect } from "react";
export interface PreventPullToRefreshContainerProps {
children: ReactNode;
}
const PreventPullToRefreshContainer = ({
children,
}: PreventPullToRefreshContainerProps) => {
useEffect(() => {
let startY: number | null = null; // Para armazenar a posição inicial do toque.
// verifica se o elemento possui scroll ativo.
const isScrollable = (element: HTMLElement): boolean => {
const style = window.getComputedStyle(element);
const overflowY = style.overflowY;
const canScroll = overflowY === "auto" || overflowY === "scroll";
return canScroll && element.scrollHeight > element.clientHeight;
};
// verifica se o evento pode ser bloqueado no elemento alvo.
const shouldPreventPullToRefresh = (target: HTMLElement): boolean => {
let currentElement: HTMLElement | null = target;
while (currentElement !== null && currentElement !== document.body) {
if (isScrollable(currentElement)) {
return false;
}
currentElement = currentElement.parentElement;
}
return true;
};
const onTouchStart = (e: TouchEvent) => {
// Salva a posição inicial do toque.
startY = e.touches[0].clientY;
};
const onTouchMove = (e: TouchEvent) => {
if (startY === null) return;
const currentY = e.touches[0].clientY;
const isPullingDown = currentY > startY;
// Previne "pull-to-refresh" somente se no topo e arrastando para baixo.
if (window.scrollY === 0 && isPullingDown) {
const target = e.target as HTMLElement;
if (shouldPreventPullToRefresh(target)) {
e.preventDefault();
}
}
};
// Adiciona os event listeners
document.addEventListener("touchstart", onTouchStart, { passive: true });
document.addEventListener("touchmove", onTouchMove, { passive: false });
// Remove os event listeners no cleanup
return () => {
document.removeEventListener("touchstart", onTouchStart);
document.removeEventListener("touchmove", onTouchMove);
};
}, []);
return <div className="touch-pan-x">{children}</div>;
};
export default PreventPullToRefreshContainer;
Check out the full article at: https://cafecomdev.blogspot.com/2025/01/como-evitar-atualizacao-da-pagina-ao.html