← Назад к вопросам

Приведи пример использования пагинации в своих проектах

2.0 Middle🔥 202 комментариев
#JavaScript Core

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Реализация пагинации в 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 при переключении страниц

Пагинация — это баланс между производительностью и удобством использования. Правильно реализованная система пагинации значительно улучшает восприятие приложения пользователем и снижает нагрузку как на клиент, так и на сервер.