React’te alışveriş sepeti UX’i: iyimser güncellemeler, geri alma ve alt birimlerde para
Anında hissettiren ve doğru kalan bir React sepeti: alt birimlerde para, geri alınabilen iyimser miktarlar, birleştirilmiş istekler, geri alma ve ücretsiz kargo ilerlemesi.
Preet Suthar · · 6 dk okuma
- React
- Next.js
- E-commerce
- UX
Alışveriş sepeti, bir mağazanın hem anında hissettirmesi hem de doğru olması gereken ilk parçasıdır. Artıya basın, rakam bir gidiş dönüşten sonra değil, hemen değişmeli. Ama stok, fiyatlar ve indirimler sunucuya aittir ve sunucu bazen hayır der.
React ve Next.js’te ikisini birden yapan bir sepeti böyle kuruyorum: tam sayı olarak saklanan para, temiz biçimde geri alınan iyimser güncellemeler, birleştirilmiş istekler, onay diyalogları yerine geri alma ve yalan söylemeyen bir ücretsiz kargo çubuğu.
Parayla başlayın
Herhangi bir arayüzden önce parayı nasıl sakladığınızı düzeltin, yoksa bundan sonraki her toplam biraz yanlış olur.
Bu 0.30000000000000004 eder ve bir sepet çok sayıda rakam toplar. Tutarları para biriminin en küçük biriminde tam sayı olarak saklayın: USD için cent, alt birimi olmayan JPY için yen. Stripe ve çoğu ödeme API’sinin gönderdiği ve beklediği de budur.
formatMoney({ amount: 4800, currency: "USD" }, "en-US") $48.00 verir, aynı tutar JPY’de ¥4,800 verir. Intl.NumberFormat sembolleri, gruplamayı ve ondalıkları her yerel ayara göre ele alır; dolayısıyla Almanya’da 48,00 € bedavaya gelir. Ödeme sağlayıcılarının, alt biriminin ISO standardından farklı olduğu birkaç para birimi vardır; sağlayıcınızın listesini bir kez kontrol edin.
İki para birimini toplamayı reddetmek paranoya değildir. EUR cinsinden bir sepetin USD cinsinden kargo ücreti aldığı hatayı yakalar.
Geri alınabilen iyimser güncellemeler
Sepet, biri artıya bastığı anda değişmeli: miktar, satır toplamı ve ara toplam. İstek arkada çalışır. Başarısız olursa satır, sunucunun onayladığı son miktara geri döner ve nedenini satırın altında söyler, örneğin "Sand / Large için yalnızca 2 adet kaldı".
React 19’un useOptimistic’i buna çok uyar. İyimser değer transition çalışırken görünür ve transition bittiğinde React onu bırakır; böylece bir hata ek kod olmadan geri alınır:
İki kural onu dürüst tutar. Sunucu her değişiklikten sonra sepetin tamamını döndürür ve o sepet sizinkinin yerini alır; böylece toplamlar, indirimler ve kargo her zaman tek bir yerden gelir. Satırın hatası da müşteri o satırı yeniden değiştirene kadar kalır, çünkü okunmadan kaybolan bir mesaj hiç mesaj olmamasıyla aynıdır.
Next.js’te updateLine bir server action olabilir. Next.js, production’da server action’lardan fırlatılan hata mesajlarını gizler; bu yüzden göstermek istediğiniz hatalar için fırlatmak yerine { ok: false, message } döndürün.
Hızlı basışları birleştirin
Bir şeyden beş tane isteyen biri bir saniye içinde artıya dört kez basar. Dört istek göndermek, başarısız olmak için dört şans ve sırasız gelebilecek dört yanıt yaratır. Bunun yerine son miktarla tek bir istek gönderin.
Asla "bir artır" değil, mutlak miktarı gönderin. Mutlak bir değeri yeniden denemek de geç almak da güvenlidir. Aynı satır için iki istek çakışırsa, gönderdiğiniz en son istekten daha eski olan her yanıtı yok sayın.
"Emin misiniz?" yerine geri al
Kaldırırken çıkan bir onay diyaloğu, nadir hataya karşı korumak için her kaldırmaya bir adım ekler. Geri al aynı hataya karşı korur ve hata olmadığında hiçbir maliyeti yoktur.
Kaldırılan satırı yaklaşık beş saniyeliğine kısa bir satıra, "Ring Vase kaldırıldı · Geri al", daraltın ve alttaki satırları yukarı kaydırarak yerine oturtun. Geri al, satırı en alta değil, olduğu yere geri koyar. Sunucudan hemen kaldırıp geri alındığında yeniden ekleyebilir ya da satırın süresi dolana kadar bekleyebilirsiniz. Hemen kaldırmak, sekme kapanırsa sunucunun sepetini doğru tutar; bu yüzden orijinal konumu istemcide saklayarak bunu tercih ediyorum.
Kaldırmayı polite bir canlı bölge üzerinden duyurun ve odağı sayfaya düşmesine izin vermek yerine mantıklı bir yerde, Geri al düğmesinde ya da sonraki satırda tutun.
Eskiyen satırlar
Bir sepet bir sekmede günlerce bekleyebilir. Yeniden yüklendiğinde sunucu, eklendiğinden beri fiyatı değişen satırları ("Fiyat $58’e düştü") ve tükenen satırları işaretlemelidir. Tükenen bir satır kaldırılana kadar ödemeyi engeller ve neden bir toast’ta değil, satırın kendisinde durur.
Doğruyu söyleyen bir ücretsiz kargo çubuğu
"Ücretsiz kargo için $12.00 daha ekleyin", insanların gerçekten sevdiği az sayıdaki sepet mesajından biridir. Doğru yapılması gereken iki şey var:
- Sunucuyla aynı ara toplamı kullanın. Ücretsiz kargo indirimlerden sonra hesaplanıyorsa çubuk da öyle hesaplanmalı; yoksa çubuk hak kazandığınızı söyler, ödeme sayfası ise kargo ücreti alır.
- Bir kez kutlayın. Eşik aşıldığında kısa bir an oynatın, sonra sakin bir "Ücretsiz kargo kazandınız" gösterin. Bunu her render’da ya da çekmece her açıldığında yeniden oynatmayın.
Metin etiketli gerçek bir progress öğesi kullanın; böylece çubuk renkli bir şerit olarak değil, "$150’nin $138’i" olarak okunur.
Sepete ekle düğmesi ve rozet
Müşterinin her ürün sayfasında gördüğü küçük şeyler:
- Düğme etiketten spinner’a, oradan onay işaretine geçerken genişliğini korur; böylece yanındaki hiçbir şey zıplamaz.
- Spinner görünmeden önce yaklaşık 300ms bekler. Çoğu ekleme daha hızlı biter ve buna hiç ihtiyaç duymaz.
- Sepet rozeti yalnızca değişen rakamı değiştirir ve çekmece açılır ya da kısa bir onay görünür; böylece insanlar ürünün nereye gittiğini bilir.
Bir kontrol listesi
- Para, alt birimlerde tam sayı olarak,
Intl.NumberFormatile biçimlendirilmiş. - Asla iki para birimini toplamayın.
- İyimser miktarlar; hata olduğunda satırda bir mesajla son onaylanan sepete geri alınır.
- Hızlı basışlar, son miktarla tek bir istekte birleştirilir.
- Kaldırmada yaklaşık beş saniye boyunca geri al, satırın konumunu geri yükleyerek.
- Eskimiş fiyatlar ve tükenen satırlar satırda işaretlenir, gerektiğinde ödemeyi engeller.
- Sunucuyla aynı ara toplamdan hesaplanan ücretsiz kargo ilerlemesi.
Bunun için HextaUI blokları
Bunlar HextaUI Pro’daki Cart bloğunun arkasındaki kurallar. Bir AddToCartButton’ı, canlı sayaçlı bir CartTrigger’ı ve masaüstünde sağdan, telefonlarda alttan kayarak açılan bir CartDrawer’ı var; tam bir sepet sayfası için de bir CartPanel. Hızlı basışlar tek bir istekte birleşir, başarısız bir callback satırı geri alır ve mesajınızı gösterir, kaldırılan satırlar beş saniyeliğine bir Geri al satırına daralır ve aynı mantık kendi düzenleriniz için useOptimisticCart olarak dışa aktarılır. Örnekleri Shopify Storefront API’yi ve Next.js server action’larını kapsar.
Order Summary, ödeme sayfası için aynı sepet yapısını alır; indirim kodları, tahmini vergiler ve fiyatı değişen satırlarla birlikte. İkisi de tam sayı alt birimlerle çalışan ve iki para birimini toplamayı reddeden Price para yardımcılarını kullanır. Hepsini canlı önizlemelerde deneyebilirsiniz.
Sepet bittiğinde sıradaki adım ödeme sayfası: React ve Next.js’te tek sayfalık bir ödeme akışı.
SSS
Fiyatları float olarak mı saklamalıyım? Hayır. Para biriminin alt biriminde tam sayılar saklayın ve yalnızca biçimlendirirken bölün.
Sepet güncellemeleri iyimser mi olmalı? Miktar ve kaldırma için evet; yeter ki her değişiklikten sonra sunucunun sepeti sizinkinin yerini alsın ve hatalar bir nedenle geri alınsın.
Ürün kaldırırken geri al mı, onay diyaloğu mu? Geri al. İnsanlar gerçekten kaldırmak istediğinde daha hızlıdır, istemediğinde de aynı derecede güvenlidir.
Her artı basışı için bir istek atmaktan nasıl kaçınırım? Son basıştan sonra birkaç yüz milisaniye bekleyin ve son miktarı gönderin.