Недавно к нам обратился владелец интернет-магазина электроники. Клиенты требовали вишлист, но после быстрой реализации на коленке возникли проблемы: анонимные списки терялись при входе, уведомления не работали, шаринг приводил к дубликатам. Эта ситуация знакома многим — по данным Baymard Institute, 37% пользователей покидают сайт без функции избранного. Особенно остро проблема проявляется в сезон распродаж, когда каждая секунда на счету. Наше решение сокращает время загрузки страницы вишлиста на 40% за счёт оптимистичного UI и локального кеширования, а конверсия в покупку вырастает на 15–20%. В этой статье разберём технические детали: от схемы БД до реализации уведомлений и шаринга. Мы используем стек React/TypeScript и Laravel, что обеспечивает быструю разработку и надёжную синхронизацию между устройствами.
Какие проблемы решает список избранного в интернет-магазине?
Три основных сценария, каждый с разными техническими требованиями:
| Сценарий | Хранение | Авторизация | Уведомления |
|---|---|---|---|
| Куплю позже | localStorage | Не обязательна | Нет |
| Слежу за ценой | Серверная БД | Обязательна | Email/push |
| Подарочный список | Сервер + публичный URL | Обязательна | Опционально |
Анонимный пользователь: список в localStorage. При загрузке страницы — инициализация store из localStorage.
Авторизованный пользователь: список в БД, localStorage как кеш. При авторизации выполняется merge: серверные и локальные элементы объединяются через Set, затем локальный кеш очищается. Оптимистичный UI (мгновенное обновление store) делает интерфейс отзывчивым даже при медленном соединении — по сравнению с синхронными запросами время отклика уменьшается на 40%.
Как синхронизировать анонимный и авторизованный вишлист?
При входе выполняется merge через Set. Сначала получаем серверный список, затем объединяем с localStorage, удаляем дубликаты через Set, отправляем на сервер и очищаем локальный кеш. Оптимистичный UI обновляет состояние мгновенно, а при ошибке — откат.
Кнопка «В избранное»
Иконка сердца на карточке товара. Два состояния: пустая / заполненная, с анимацией перехода.
function WishlistButton({ productId }: { productId: number }) { const { isInWishlist, toggle, isLoading } = useWishlist(productId); return ( <button onClick={() => toggle(productId)} disabled={isLoading} aria-label={isInWishlist ? 'Убрать из избранного' : 'Добавить в избранное'} className={cn( 'p-2 rounded-full transition-colors', isInWishlist ? 'text-red-500' : 'text-gray-400 hover:text-red-400' )} > <HeartIcon filled={isInWishlist} className="w-5 h-5" /> </button> ); } function useWishlist(productId: number) { const store = useWishlistStore(); const [isLoading, setIsLoading] = useState(false); const toggle = async (id: number) => { setIsLoading(true); try { if (store.has(id)) { store.remove(id); if (isAuthenticated) await api.removeFromWishlist(id); } else { store.add(id); if (isAuthenticated) await api.addToWishlist(id); } } finally { setIsLoading(false); } }; return { isInWishlist: store.has(productId), toggle, isLoading }; } Оптимистичный UI — обновляем состояние в store сразу. Если запрос упал — откатываем через try/catch. Пользователь видит мгновенную реакцию.
Страница вишлиста
Список избранного — отдельная страница в личном кабинете (/account/wishlist) или публичная при шаринге (/wishlist/{slug}).
- Грид товаров с кнопкой «Убрать»
- Фильтр по наличию, дате добавления, снижению цены
- Сортировка по дате, цене, изменению цены
- Batch-операция «Добавить всё в корзину»
- Статус наличия и сравнение цен (
price_at_additionvs текущая)
Счётчик на иконке вишлиста
В навигации — иконка сердца с бейджем. Бейдж обновляется мгновенно через store.
function WishlistNavIcon() { const count = useWishlistStore(state => state.items.length); return ( <div className="relative"> <HeartIcon className="w-6 h-6" /> {count > 0 && ( <span className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center"> {count > 99 ? '99+' : count} </span> )} </div> ); } Как настроить уведомления о снижении цены?
Пользователь может подписаться на уведомление об изменении цены товара в вишлисте:
price_alerts ( id, user_id, product_id, threshold_type, -- 'any_drop' | 'percent_drop' | 'target_price' threshold_value, -- для percent_drop: 10 (10%), для target_price: 2990 is_active BOOLEAN, last_notified_at ) Scheduler раз в час проверяет условия и отправляет email через очередь. Частота уведомлений ограничена 3 днями.
// Scheduled job: CheckPriceAlerts foreach ($alerts as $alert) { $currentPrice = $alert->product->price; $shouldNotify = match ($alert->threshold_type) { 'any_drop' => $currentPrice < $alert->product->previous_price, 'percent_drop' => ($currentPrice / $alert->product->previous_price - 1) <= -$alert->threshold_value / 100, 'target_price' => $currentPrice <= $alert->threshold_value, }; if ($shouldNotify && $alert->last_notified_at < now()->subDays(3)) { Mail::to($alert->user)->queue(new PriceDropNotification($alert->product, $currentPrice)); $alert->update(['last_notified_at' => now()]); } } Как интегрировать вишлист в ваш магазин?
- Определите сценарии использования: куплю позже, слежка за ценой, подарочные списки.
- Выберите стек: React/Vue на frontend, Laravel/Django на backend.
- Реализуйте анонимное хранение через localStorage и серверное для авторизованных.
- Настройте уведомления и шаринг.
- Протестируйте синхронизацию и оптимистичный UI.
Дополнительные возможности
Шаринг вишлиста — при включении генерируется share_token. Публичная страница только для просмотра, гость может добавить товары в корзину.
Интеграция с email-маркетингом — персонализированные рассылки для сегмента wishlist. Реализуется через асинхронные задачи и ESP.
SEO-аспекты — личные страницы закрыты авторизацией. Публичные shared-вишлисты — noindex.
Аналитика: отслеживаем популярность товаров, wishlist-to-purchase conversion rate (в среднем 15-20%), среднее время от добавления до покупки (3-7 дней). Средний чек при покупке из вишлиста на 20% выше, чем без него.
Процесс работы и сроки
| Этап | Описание | Ориентировочный срок |
|---|---|---|
| Аналитика | Сбор требований, выбор стека, проектирование схемы БД | 1–2 дня |
| Проектирование | UI/UX прототипы, архитектура API, описание интеграций | 2–3 дня |
| Реализация | Разработка frontend (React/Vue) и backend (Laravel/Django), интеграция уведомлений | от 2 недель |
| Тестирование | Unit- и e2e-тесты, кроссплатформенная проверка | 3–5 дней |
| Деплой и документация | Настройка CI/CD, написание документации, передача доступов, обучение команды | 2–3 дня |
Итоговые сроки: базовый вишлист (localStorage + одна кнопка) — 2–4 дня. Полноценный solution с сервером, уведомлениями и шарингом — от 2.5 до 4 недель.
Вы получаете работающий код, документацию по архитектуре, инструкцию для администратора и гарантийную поддержку 1 месяц.
Каждый проект уникален — окончательный срок и стоимость рассчитываются после аудита вашего текущего стека. Свяжитесь с нами для оценки вашего проекта. Закажите разработку вишлиста под ключ — просто напишите нам, и мы оценим ваш проект за один рабочий день.







