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

Реализовывал ли фильтры в интернет-магазине

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

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

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

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

Да, я неоднократно реализовывал системы фильтров в интернет-магазинах. Это одна из ключевых функциональных частей, напрямую влияющих на пользовательский опыт и конверсию. Я поделюсь своим подходом, архитектурными решениями, типичными проблемами и их решениями.

Архитектура и стейт-менеджмент фильтров

В современных SPA-приложениях я предпочитаю использовать централизованный стейт для фильтров, часто в связке с менеджером состояний, таким как Redux (Toolkit), Zustand или контекст React + useReducer. Это позволяет синхронизировать состояние фильтров с историей браузера (для сохранения и шаринга ссылок) и декомпозировать логику.

Пример базовой структуры состояния (TypeScript)

// types/filters.ts
export interface FilterState {
  category: string | null;
  brands: string[];
  priceRange: { min: number; max: number };
  attributes: Record<string, string[]>; // Динамические атрибуты (цвет, размер)
  sortBy: 'price_asc' | 'price_desc' | 'newest';
  searchQuery: string;
  inStock: boolean;
}

// Пример начального состояния
export const initialFilters: FilterState = {
  category: null,
  brands: [],
  priceRange: { min: 0, max: 100000 },
  attributes: {},
  sortBy: 'newest',
  searchQuery: '',
  inStock: false,
};

Ключевые компоненты системы фильтров

Реализация обычно включает несколько связанных компонентов:

  1. Панель фильтров (Sidebar/Modal): Визуальный интерфейс с чекбоксами, диапазонными слайдерами, поиском по фильтрам.
  2. Строка активных фильтров (Active Filters Bar): Отображает выбранные критерии с возможностью быстрого сброса.
  3. Логика запросов к API: Формирование параметров на основе стейта и отправка на бэкенд.
  4. Синхронизация с URL: Кодирование состояния фильтров в query-параметрах.

Пример компонента Range-слайдера (React)

// components/PriceRangeFilter.jsx
import React from 'react';
import { Slider, Box, Typography } from '@mui/material'; // Использую MUI для примера

const PriceRangeFilter = ({ min, max, value, onChange }) => {
  const handleChange = (event, newValue) => {
    onChange(newValue);
  };

  return (
    <Box sx={{ width: 250, px: 2 }}>
      <Typography gutterBottom>
        Цена: {value[0]}₽ — {value[1]}₽
      </Typography>
      <Slider
        value={value}
        onChange={handleChange}
        valueLabelDisplay="auto"
        min={min}
        max={max}
        step={100}
      />
    </Box>
  );
};
export default PriceRangeFilter;

Сложности и решения в реализации

  • Производительность при большом количестве товаров: Критически важна оптимизация запросов. Я использую:
    *   **Дебаунсинг (debounce)** для полей поиска и диапазонных слайдеров.
    *   **Мемоизацию** результатов фильтрации на фронтенде (если данные уже загружены) с помощью `useMemo`.
    *   **Пагинацию или бесконечный скролл** на стороне сервера.

  • Динамические фильтры (например, по характеристикам товара): Их нельзя захардкодить. Я загружаю метаданные об атрибутах и возможных значениях отдельным запросом (/api/attributes) и рендерю интерфейс на их основе.

  • Сброс и зависимость фильтров: Например, при смене категории нужно сбрасывать фильтр по бренду, так как бренды теперь относятся к новой категории. Это требует каскадной логики в редюсере.

    // Пример действия в Redux Toolkit
    setCategory(state, action) {
      const newCategory = action.payload;
      // При смене категории сбрасываем бренды и атрибуты
      return {
        ...state,
        category: newCategory,
        brands: [],
        attributes: {},
      };
    }
    
  • Синхронизация с URL: Для сохранения состояния фильтров в строке браузера я использую библиотеку React Router или Next.js Router, сериализуя состояние в параметры.

    // Хук для синхронизации состояния фильтров с URL
    const useSyncedFilters = () => {
      const [filters, setFilters] = useState(initialFilters);
      const router = useRouter(); // Next.js пример
      const searchParams = useSearchParams();
    
      // При изменении фильтров -> обновляем URL
      useEffect(() => {
        const params = new URLSearchParams();
        if (filters.category) params.set('category', filters.category);
        if (filters.brands.length) params.set('brands', filters.brands.join(','));
        router.replace(`?${params.toString()}`);
      }, [filters, router]);
    
      // При изменении URL -> обновляем стейт
      useEffect(() => {
        // Парсим параметры и применяем к стейту...
      }, [searchParams]);
    
      return [filters, setFilters];
    };
    

Оптимизация UX

  • Количество найденных товаров: Рядом с каждым фильтром отображается число соответствующих ему товаров. Важно инвалидировать эти счетчики при изменении других фильтров.
  • Прогрессивная загрузка и скелетоны: Пока основной список товаров обновляется, показываю скелетоны, а фильтры остаются интерактивными (если логика позволяет).
  • Мобильная адаптация: На мобильных устройствах фильтры часто выносятся в модальное окно или шторку (drawer).

Взаимодействие с бэкендом

Обычно используется REST или GraphQL эндпоинт, который принимает параметры фильтрации и возвращает пагинированный список. Важно договориться об едином формате.

Пример REST-запроса: GET /api/products?category=electronics&brands=apple,samsung&price_min=20000&price_max=60000&sort=-price

Таким образом, реализация фильтров — это комплексная задача на стыке UI/UX, state-менеджмента, работы с API и оптимизации производительности. Мой подход всегда начинается с проектирования гибкой и типобезопасной структуры состояния, вокруг которой затем строится весь интерфейс и логика взаимодействия.

Реализовывал ли фильтры в интернет-магазине | PrepBro