#[component]
fn HomePage() -> impl IntoView {
let increment_action = ServerAction::<IncrementCount>::new();
let counter_view = Resource::new(|| (), |_| get_counter_view());
let (current_view, set_current_view) = signal(None::<CounterViewDto>);
let (optimistic_count, set_optimistic_count) = signal(None::<i32>);
let (last_seen_sequence, set_last_seen_sequence) = signal(0_u64);
let (pending_until_sequence, set_pending_until_sequence) = signal(None::<u64>);
Effect::new(move |_| {
if let Some(Ok(view_data)) = counter_view.get() {
if current_view
.get_untracked()
.is_some_and(|current| view_data.last_sequence < current.last_sequence)
{
return;
}
let caught_up = pending_until_sequence
.get_untracked()
.is_none_or(|sequence| view_data.last_sequence >= sequence);
if caught_up {
set_optimistic_count.set(Some(view_data.count));
set_pending_until_sequence.set(None);
}
set_last_seen_sequence.set(view_data.last_sequence);
set_current_view.set(Some(view_data));
}
});
let apply_optimistic_increment = move |_| {
let base_count = optimistic_count
.get_untracked()
.or_else(|| current_view.get_untracked().map(|view| view.count))
.unwrap_or_default();
set_optimistic_count.set(Some(base_count.saturating_add(1)));
let base_sequence = pending_until_sequence
.get_untracked()
.or_else(|| current_view.get_untracked().map(|view| view.last_sequence))
.unwrap_or_else(|| last_seen_sequence.get_untracked());
set_pending_until_sequence.set(Some(base_sequence.saturating_add(1)));
increment_action.dispatch(IncrementCount { amount: 1 });
};
view! {
<button on:click=apply_optimistic_increment>
"+1"
</button>
<div>{move || optimistic_count.get().unwrap_or_default()}</div>
}
}