Приведи пример использования пагинации в своих проектах
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Реализация пагинации в frontend-проектах
В современных веб-приложениях пагинация — не просто техническое требование, а важная часть пользовательского опыта. В своих проектах я реализовывал различные подходы к пагинации, в зависимости от требований к UX, объема данных и архитектуры приложения.
Основные подходы к реализации
1. Серверная пагинация (Backend-driven)
Наиболее распространенный подход для больших наборов данных. Frontend отправляет параметры страницы, а сервер возвращает только нужную порцию данных.
// Пример хука для серверной пагинации
function usePagination(apiEndpoint, initialPage = 1, pageSize = 10) {
const [data, setData] = useState([]);
const [currentPage, setCurrentPage] = useState(initialPage);
const [totalPages, setTotalPages] = useState(0);
const [loading, setLoading] = useState(false);
const fetchPage = async (page) => {
setLoading(true);
try {
const response = await fetch(
`${apiEndpoint}?page=${page}&limit=${pageSize}`
);
const result = await response.json();
setData(result.items);
setTotalPages(Math.ceil(result.total / pageSize));
setCurrentPage(page);
} catch (error) {
console.error('Ошибка загрузки данных:', error);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchPage(currentPage);
}, []);
return { data, currentPage, totalPages, loading, fetchPage };
}
2. Клиентская пагинация (Frontend-driven)
Используется при небольших наборах данных, которые можно загрузить один раз и фильтровать на клиенте.
// Компонент клиентской пагинации
const ClientSidePaginator = ({ items, itemsPerPage = 10 }) => {
const [currentPage, setCurrentPage] = useState(1);
const totalPages = Math.ceil(items.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const currentItems = items.slice(startIndex, endIndex);
const handlePageChange = (page) => {
if (page >= 1 && page <= totalPages) {
setCurrentPage(page);
window.scrollTo({ top: 0, behavior: 'smooth' });
}
};
return (
<div className="paginator">
<div className="items-container">
{currentItems.map(item => (
<ItemComponent key={item.id} item={item} />
))}
</div>
<PaginationControls
currentPage={currentPage}
totalPages={totalPages}
onPageChange={handlePageChange}
/>
</div>
);
};
Ключевые компоненты системы пагинации
Компонент управления пагинацией
const PaginationControls = ({ currentPage, totalPages, onPageChange }) => {
const pages = useMemo(() => {
// Логика отображения диапазона страниц
const range = [];
const delta = 2; // Количество страниц слева и справа от текущей
for (
let i = Math.max(2, currentPage - delta);
i <= Math.min(totalPages - 1, currentPage + delta);
i++
) {
range.push(i);
}
return range;
}, [currentPage, totalPages]);
return (
<nav className="pagination-controls">
<button
onClick={() => onPageChange(currentPage - 1)}
disabled={currentPage === 1}
>
Назад
</button>
<button onClick={() => onPageChange(1)}>
1
</button>
{currentPage - delta > 2 && <span>...</span>}
{pages.map(page => (
<button
key={page}
onClick={() => onPageChange(page)}
className={currentPage === page ? 'active' : ''}
>
{page}
</button>
))}
{currentPage + delta < totalPages - 1 && <span>...</span>}
{totalPages > 1 && (
<button onClick={() => onPageChange(totalPages)}>
{totalPages}
</button>
)}
<button
onClick={() => onPageChange(currentPage + 1)}
disabled={currentPage === totalPages}
>
Вперед
</button>
</nav>
);
};
Расширенные возможности пагинации
Бесконечный скролл (Infinite Scroll)
Для улучшения UX в социальных сетях и лентах новостей:
function InfiniteScrollPaginator({ fetchData }) {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const loaderRef = useRef();
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting && hasMore) {
loadMore();
}
},
{ threshold: 0.5 }
);
if (loaderRef.current) {
observer.observe(loaderRef.current);
}
return () => observer.disconnect();
}, [hasMore]);
const loadMore = async () => {
const newData = await fetchData(page);
if (newData.length === 0) {
setHasMore(false);
} else {
setItems(prev => [...prev, ...newData]);
setPage(prev => prev + 1);
}
};
return (
<div>
{items.map(item => (
<Item key={item.id} item={item} />
))}
{hasMore && <div ref={loaderRef}>Загрузка...</div>}
</div>
);
}
Сохранение состояния пагинации
Для SPA важно сохранять состояние при навигации:
// Использование URL parameters
const PaginatedRoute = () => {
const [searchParams, setSearchParams] = useSearchParams();
const page = parseInt(searchParams.get('page')) || 1;
const handlePageChange = (newPage) => {
setSearchParams({ page: newPage });
// Данные загружаются на основе параметра page из URL
};
return <PaginatedComponent page={page} onPageChange={handlePageChange} />;
};
Практические советы из опыта
- Оптимизация производительности: При серверной пагинации обязательно кэшируйте результаты запросов
- Доступность (a11y): Всегда добавляйте ARIA-атрибуты к элементам управления
- Мобильная адаптация: На мобильных устройствах увеличивайте touch target для кнопок пагинации
- Показ общего количества: Пользователи ценят информацию о общем количестве элементов
- Быстрая навигация: Добавляйте возможность перехода на первую/последнюю страницу для больших наборов данных
Производительность пагинации можно дополнительно улучшить с помощью:
- Виртуализации списков для очень больших наборов данных
- Prefetching следующей страницы при наведении на кнопку "Вперед"
- Оптимистичных обновлений UI при переключении страниц
Пагинация — это баланс между производительностью и удобством использования. Правильно реализованная система пагинации значительно улучшает восприятие приложения пользователем и снижает нагрузку как на клиент, так и на сервер.