use crate::{ComponentUpdater, Hook, Hooks};
use core::hash::{Hash, Hasher};
use std::hash::DefaultHasher;
mod private {
pub trait Sealed {}
impl Sealed for crate::Hooks<'_, '_> {}
}
pub trait UseEffect: private::Sealed {
fn use_effect<F, D>(&mut self, f: F, deps: D)
where
F: FnOnce() + Send + Unpin + 'static,
D: Hash;
}
fn hash_deps<D: Hash>(deps: D) -> u64 {
let mut hasher = DefaultHasher::new();
deps.hash(&mut hasher);
hasher.finish()
}
impl UseEffect for Hooks<'_, '_> {
fn use_effect<F, D>(&mut self, f: F, deps: D)
where
F: FnOnce() + Send + Unpin + 'static,
D: Hash,
{
let deps_hash = hash_deps(deps);
let hook = self.use_hook(UseEffectImpl::<F>::default);
if hook.deps_hash != deps_hash {
hook.f = Some(f);
hook.deps_hash = deps_hash;
} else {
hook.f = None;
}
}
}
struct UseEffectImpl<F> {
deps_hash: u64,
f: Option<F>,
}
impl<F> Default for UseEffectImpl<F> {
fn default() -> Self {
Self {
deps_hash: 0,
f: None,
}
}
}
impl<F: FnOnce() + Send + Unpin> Hook for UseEffectImpl<F> {
fn post_component_update(&mut self, _updater: &mut ComponentUpdater) {
if let Some(f) = self.f.take() {
f();
}
}
}