Skip to content

Instantly share code, notes, and snippets.

@HurricanKai
Created April 7, 2022 21:02
Show Gist options
  • Save HurricanKai/9d1b30ac08168728db48e3c950d56d3c to your computer and use it in GitHub Desktop.
Save HurricanKai/9d1b30ac08168728db48e3c950d56d3c to your computer and use it in GitHub Desktop.
use gloo_timers::callback::Timeout;
use std::mem::replace;
use std::ops::DerefMut;
use yew::{
prelude::*,
suspense::{Suspension, SuspensionHandle, SuspensionResult},
};
#[hook]
fn use_delay(ms: u32) -> SuspensionResult<bool> {
enum TriggerState {
Done,
// I couldn't find a way to tie the knot here.
// This state exists only during the first initialization.
Initial,
Waiting(SuspensionHandle),
}
let is_initialized = use_state(|| false);
let trigger_state = use_mut_ref(|| TriggerState::Initial);
{
let is_initialized = is_initialized.clone();
let trigger_state = trigger_state.clone();
use_effect_with_deps(
move |_| {
let timeout = Timeout::new(ms, move || {
match replace(trigger_state.borrow_mut().deref_mut(), TriggerState::Done) {
TriggerState::Done | TriggerState::Initial => unreachable!("Impossible!"),
TriggerState::Waiting(handle) => handle.resume(),
}
});
is_initialized.set(true);
|| {
timeout.cancel();
}
},
(),
);
};
if !*is_initialized {
return Ok(true);
}
let mut trigger_state = trigger_state.borrow_mut();
if let TriggerState::Done = *trigger_state {
Ok(false)
} else {
let (suspense, handle) = Suspension::new();
*trigger_state = TriggerState::Waiting(handle);
Err(suspense)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment