Wzorzec 07
Optymistyczna odpowiedź
Użytkownik nie powinien czekać na serwer, żeby zobaczyć skutek własnego kliknięcia. Wzorzec optymistyczny pokazuje nowy stan od razu, wysyła żądanie w tle, a w razie błędu przywraca poprzedni stan i wyjaśnia przyczynę w zarezerwowanym miejscu.
Głosowanie na pomysły zespołu
Głos liczy się od razu, zapis leci w tle. Pomysł 2 zawsze zostanie odrzucony przez serwer, żeby pokazać wycofanie.
Skeleton generowany z tych samych propsów co treść
zapis…Tokeny kontenerów wspólne dla Figmy i CSS
zapis…Budżet Core Web Vitals w pipeline CI
zapis…
Reguły
- Kliknięcie zmienia interfejs natychmiast, bez spinnera na głównej ścieżce.
- Każda optymistyczna zmiana ma zapamiętany stan poprzedni, do którego można wrócić.
- Wycofanie tłumaczy przyczynę w zarezerwowanym slocie, nie wyskakującym alertem.
- Element w trakcie zapisu nie blokuje reszty interfejsu.
Wzorzec w kodzie
async function toggle(id: number) {
const previous = votes[id];
const optimistic = applyVote(previous);
setVotes((state) => ({ ...state, [id]: optimistic }));
try {
await saveVote(id, optimistic);
} catch {
setVotes((state) => ({ ...state, [id]: previous }));
setError("Serwer odrzucił zmianę, przywróciliśmy poprzedni state.");
}
}const [optimisticVotes, addVote] = useOptimistic(
votes,
(state, id: number) => applyVote(state, id)
);Prompt dla Claude
Wklej do Claude Code w swoim projekcie. Prompt niesie komplet reguł tej lekcji i ogólne zasady Liquid Design, więc implementacja trafia w metodologię bez tłumaczenia jej od zera.
Zaimplementuj w moim projekcie wzorzec „Optymistyczna odpowiedź" z metodologii Liquid Design. Interfejs odpowiada natychmiast, zapisuje w tle i umie się wycofać, gdy serwer odmówi. Wymagania: - Kliknięcie zmienia interfejs natychmiast, bez spinnera na głównej ścieżce. - Każda optymistyczna zmiana ma zapamiętany stan poprzedni, do którego można wrócić. - Wycofanie tłumaczy przyczynę w zarezerwowanym slocie, nie wyskakującym alertem. - Element w trakcie zapisu nie blokuje reszty interfejsu. Ogólne reguły Liquid Design, których implementacja nie może złamać: - HTML jest semantyczny: button, a, nav, form, label, dialog, details, ul, dl i nagłówki h1-h6 zamiast div z onClick i ARIA dopisywanym ręcznie. div i span służą wyłącznie do layoutu, nigdy do interakcji ani struktury treści. - Layout jest umową: treść, która dociera później, ma miejsce zarezerwowane od pierwszego renderu. Nic nie skacze. - Stany ładowania, pustki, błędu i treści dzielą jeden layout. - Typografia pochodzi z nazwanej, płynnej skali opartej o clamp(), nie z gołych rozmiarów. - Animacje dotyczą wyłącznie transform i opacity, a prefers-reduced-motion redukuje je do natychmiastowej zmiany stanu. - Breakpoint jest ostatecznością: najpierw container queries i repeat(auto-fit, minmax(...)). Sposób pracy – zanim napiszesz pierwszą linię kodu: - Sprawdź w plikach projektu, jak stylowane są komponenty (Tailwind, CSS Modules, vanilla-extract, styled-components, Sass, czysty CSS...) i pisz wyłącznie w tej konwencji. Niczego nie zakładaj z góry i nie dodawaj nowych zależności. - Wymagania powyżej opisują właściwości CSS i atrybuty HTML, nie klasy narzędziowe. Przełóż je na system stylowania zastany w projekcie. - Sprawdź framework komponentów, wersję i konwencje nazewnictwa, zamiast zakładać konkretny stack. - Używaj istniejących tokenów projektu (kolory, typografia, odstępy). Jeśli czegoś brakuje, zaproponuj minimalne uzupełnienie w duchu istniejącego kodu, nie osobny system. - Nie używaj klas, tokenów ani API, których nie znalazłeś w tym projekcie. Pełny opis z żywym demo i kodem: https://liquid-design.website/wzorce/optymistyczny-interfejs