İçeriğe geç

İyimser Arayüz — Ne Zaman Hemen 'Tamam' Denir, Ne Zaman Beklenir?

Orta 8 dk Sık karşılaşılır

Önce şunu oku: State Nerede Yaşamalı? — Bileşen, Üst Bileşen, Context, Cache, URL

30 saniyede özet

Arayüz bir işlemi sunucu cevap vermeden 'tamam' gösterirse uygulama hızlı hissettirir. Favori eklemek gibi geri alınabilen işlerde bu iyidir; havale gibi geri alınamayan işlerde müşteriye yalan söylemek olur.

Bir kafede su istediğinde garson hemen geleceğini söyler; sürahi boşsa bir özür yeter. Ama kartla ödediğinde kimse cihaz onaylamadan “ödendi” demez. Biri geri alınabilir, öbürü para.

  1. Bayt: Uygulamayı hızlandırdım: her düğme sunucuyu beklemeden 'tamam' gösteriyor!

  2. Sen: Bir müşteri 'havale gönderildi' yazısını görmüş, sonra yazı kaybolmuş. Para gitmemiş.

  3. Bayt: Yetersiz bakiye... Sunucu reddetmiş, ama ekran çoktan 'gönderildi' demişti.

  4. Bayt: Favori eklemek için harikaydı. Para için ise bir yalan.

Neden hemen göstermek istenir?

Sunucuya giden her işlem bir süre alır. Bu sırada dönen bir simge görmek, uygulamanın yavaş olduğu hissini verir.

iyimser arayüzBir işlemi sunucu cevap vermeden gösterip, reddedilirse sakince geri alan arayüz. Geri alınabilen küçük işler içindir, para için değil.Sözlükte gör →, sunucunun büyük ihtimalle onaylayacağı bir işlemi cevabı beklemeden gösterir. Sunucu reddederse ekranı eski hâline getirir ve bunu sakin bir notla söyler.

Kafam karıştı, daha basit anlat

İyimser arayüz, sonucu sunucu cevap vermeden gösterir. Sunucu reddederse geri alır.

Hızlı kontrolBaşlangıç

İyimser arayüz (optimistic UI) nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Neden her işlemde sunucuyu beklemek yavaş hissettirir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Geri alınabilene evet, paraya bekle

Her işlem iyimser gösteriliyor. Müşteri 5.000 TL havale gönderdi; ekran hemen 'gönderildi' dedi. Sunucu yetersiz bakiye nedeniyle reddetti. Müşteri ne anlar? Cevabı göster

Büyük ihtimalle parayı gönderdiğini sanır. Ekran sonradan geri alsa bile, o “gönderildi” yazısı görülmüştür. Geri alınamayan bir işlemde iyimser göstermek, müşteriye yanlış bir bilgi vermektir.

Geri alınabilene hemen evet, paraya onaydan sonra.
Adım adım oku
  1. Su alabilir miyim? Hemen geliyor!
  2. Sürahi boşmuş: kusura bakmayın yeter.
  3. Kartla ödeme: önce cihaz onaylasın.
  4. Geri alınabilene hemen evet, paraya onaydan sonra.

İyimser göstermek için soru basit: sunucu reddederse, müşteri yanıldığını fark edip kolayca düzeltebilir mi? Favori ya da bir not için evet; para, yetki ya da bir başkasına giden mesaj için hayır.

Beklenen işlemlerde de hız hissi verilebilir. Düğmeyi kilitle, “gönderiliyor” yaz, ikinci tıklamayı engelle ve işleme bir idempotencyAynı işlemin bir kez de on kez de çalışsa aynı sonucu vermesi. Dağıtık sistemde timeout aldığında işlemin yapılıp yapılmadığını bilemediğin için zorunludur.Sözlükte gör → anahtarı ekle ki tekrar gönderim iki kez para çekmesin.

Kafam karıştı, daha basit anlat

Geri alınabilen işi hemen göster. Parayı sunucu onaylayınca göster; beklerken ne olduğunu açıkça yaz.

Hızlı kontrolOrta

Hangi işlem iyimser gösterilmeye uygundur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Havale beklerken hız hissi nasıl verilir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendin gör

Üç işlem, üç sunucu cevabı

Tohum 77397
  1. Ayşe’yi favori alıcılara eklesunucu: onaylar
  2. Harcama notunu düzenlesunucu: reddeder
  3. 💸 5.000 TL havale göndersunucu: reddeder

⏳ toplam bekleme: 0 ms · ↩ geri alınan: 0 · ✕ yanlış başarı: 0

Hız
Adım 0

Şu an ne oldu?

Her işlemde sunucuyu bekle

Sunucu her işleme yaklaşık 800 ms sonra cevap veriyor. İkinci ve üçüncü işlem reddedilecek.

Görevler0/3

  • Hiçbir işlem anında görünmesinaçık

    İpucu

    Her işlemde sunucuyu bekle.

  • Müşteri gitmeyen bir havaleyi “gönderildi” görsünaçık

    İpucu

    Her şeyi hemen “tamam” göster.

  • Yanlış başarı olmasın, toplam bekleme 800 ms’yi geçmesinaçık

    İpucu

    Riskine göre ayır.

Olay günlüğü (0)

Henüz olay yok. Oynat veya adımla.

  1. Varsayılanla oynat. Hiçbir yanlış gösterilmedi, ama her işlemde beklendi; favori için bile.
  2. “Her işlemi hemen tamam göster” seç. Not sakince geri alındı. Havale ise “gönderildi” gösterildi ve para hiç gitmedi.
  3. “Geri alınabileni hemen göster, parayı bekle” seç. Favori ve not anında; havale beklendi ve hata doğru gösterildi.
Hızlı kontrolOrta

Her işlem iyimser gösterilirken sunucu bir havaleyi yetersiz bakiye nedeniyle reddetti. Sorun nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

React 19'da useOptimistic ile gösterilen değer sunucu reddederse ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Tuzaklar

Sessizce geri almak. Favori yıldızı aniden sönerse müşteri kafası karışır. “Kaydedilemedi, eski hâline döndü” gibi kısa bir not yeter.

Ekranı sunucudan ayırmak. İyimser değer yalnızca bekleme süresince gösterilir. Sunucunun cevabı gelince doğru olan her zaman sunucudaki değerdir.

Bekleyen düğmeyi açık bırakmak. Havale beklerken düğme tıklanabilir kalırsa sabırsız bir ikinci tıklama ikinci bir havale olabilir. Düğmeyi kilitle, isteğe bir anahtar ver.

Kafam karıştı, daha basit anlat

Geri alırken söyle, sonunda sunucuya güven, bekleyen düğmeyi kilitle.

Hızlı kontrolOrta

İyimser bir değişiklik geri alınırken ne yapılmalı?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
Derinleş · Mobil bankacılık: favori iyimser, havale beklenir 4 dosya · ~92 satır · ilk okumada atlayabilirsin
Proje dosyaları

web/src/payees/ FavoriteButton.tsx Favori düğmesi: useOptimistic ile hemen değişir; sunucu reddederse kendiliğinden eski hâline döner ve bir not gösterir.

web/src/payees/FavoriteButton.tsx
import { startTransition, useOptimistic, useState } from 'react';
import { setFavorite } from '../api';
interface FavoriteButtonProps {
payeeId: string;
initial: boolean;
}
export function FavoriteButton({ payeeId, initial }: FavoriteButtonProps) {
const [saved, setSaved] = useState(initial);
const [shown, showOptimistic] = useOptimistic(saved);
const [note, setNote] = useState<string | null>(null);
const toggle = () =>
startTransition(async () => {
const next = !saved;
showOptimistic(next); // on screen at once; reverts by itself if we never set `saved`
try {
await setFavorite(payeeId, next);
setSaved(next);
setNote(null);
} catch {
setNote('Kaydedilemedi, eski hâline döndü.');
}
});
return (
<>
<button type="button" aria-pressed={shown} onClick={toggle}>
{shown ? '★ Favori' : '☆ Favoriye ekle'}
</button>
{note && <p role="status">{note}</p>}
</>
);
}

web/src/transfers/ TransferForm.tsx Havale formu: iyimser değil; düğme kilitlenir, 'gönderiliyor' yazar, sonucu sunucu söyler.

web/src/transfers/TransferForm.tsx
import { useRef, useState, type FormEvent } from 'react';
import { sendTransfer, type TransferResult } from '../api';
export function TransferForm() {
const [pending, setPending] = useState(false);
const [result, setResult] = useState<TransferResult | null>(null);
// One key per attempt: a double click or a retry cannot move the money twice.
const key = useRef(crypto.randomUUID());
async function submit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
setPending(true);
const form = new FormData(event.currentTarget);
setResult(await sendTransfer({ to: String(form.get('to')), amount: String(form.get('amount')) }, key.current));
setPending(false);
}
return (
<form onSubmit={submit}>
<input name="to" aria-label="Alıcı IBAN" required />
<input name="amount" aria-label="Tutar" inputMode="decimal" required />
<button type="submit" disabled={pending}>{pending ? 'Gönderiliyor…' : 'Gönder'}</button>
{result && <p role="status">{result.ok ? `Gönderildi: ${result.reference}` : result.message}</p>}
</form>
);
}

web/src/ api.ts API: havale isteği bir idempotency anahtarı taşır; ikinci gönderim yeni para hareketi yaratmaz.

web/src/api.ts
export type TransferResult = { ok: true; reference: string } | { ok: false; message: string };
export async function setFavorite(payeeId: string, favorite: boolean): Promise<void> {
const response = await fetch(`/api/payees/${payeeId}/favorite`, { method: favorite ? 'PUT' : 'DELETE' });
if (!response.ok) throw new Error(`favorite: ${response.status}`);
}
export async function sendTransfer(body: { to: string; amount: string }, idempotencyKey: string): Promise<TransferResult> {
const response = await fetch('/api/transfers', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Idempotency-Key': idempotencyKey },
body: JSON.stringify(body),
});
if (response.ok) return { ok: true, reference: (await response.json()).reference };
return { ok: false, message: response.status === 422 ? 'Bakiye yetersiz. Para gönderilmedi.' : 'Havale şu an yapılamadı. Para gönderilmedi.' };
}

web/src/payees/ FavoriteButton.test.tsx Test: sunucu reddedince yıldız söner ve not görünür.

web/src/payees/FavoriteButton.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { vi } from 'vitest';
import { FavoriteButton } from './FavoriteButton';
import * as api from '../api';
it('reverts the star and says so when the server refuses', async () => {
vi.spyOn(api, 'setFavorite').mockRejectedValue(new Error('500'));
render(<FavoriteButton payeeId="p1" initial={false} />);
await userEvent.click(screen.getByRole('button'));
expect(await screen.findByRole('status')).toHaveTextContent('eski hâline döndü');
expect(screen.getByRole('button')).toHaveAttribute('aria-pressed', 'false');
});

Kendini sına

Şimşek turu1/4

İyimser arayüz, işlemi sunucu cevap vermeden gösterir.

Soru 1/3İleri

Bekleyen havale düğmesi tıklanabilir kalırsa ne olabilir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aklında kalacak üç şey

  1. 1 İyimser arayüz, sunucunun büyük ihtimalle onaylayacağı bir işlemi cevabı beklemeden gösterir; sunucu reddederse sakin bir notla geri alır.
  2. 2 Bu yalnızca geri alınabilen ve küçük işler içindir: favori eklemek, bir notu düzenlemek. Para hareketi gibi geri alınamayan işlerde arayüz sunucunun cevabını bekler.
  3. 3 Beklerken de iyi davranılabilir: düğmeyi kilitle, ne olduğunu yaz, ikinci tıklamayı engelle. Hız hissi yalan söylemeden de verilebilir.
Sonraki kapı Giriş ekranında yalnızca iki kutu ve bir düğme var. Telefon yine de yarım megabayt indiriyor. Neyi? Kod Bölme — Giriş Ekranı Neden Grafik Kütüphanesini İndiriyor? · 8 dk

4 kart sonraki derste seni bekliyor

0/4 kart bu dersten toplandı