use std::{ops::Deref, rc::Rc};
use yew::functional::*;
use crate::{
dispatch::{self, Dispatch},
store::Store,
};
#[hook]
pub fn use_store<S: Store>() -> (Rc<S>, Dispatch<S>) {
let state = use_state(|| dispatch::get::<S>());
let dispatch = {
let state = state.clone();
use_state(move || Dispatch::<S>::subscribe_silent(move |val| state.set(val)))
};
(Rc::clone(&state), dispatch.deref().clone())
}
#[hook]
pub fn use_store_value<S: Store>() -> Rc<S> {
let (state, _dispatch) = use_store();
state
}
#[hook]
pub fn use_selector<S, F, R>(selector: F) -> Rc<R>
where
S: Store,
R: PartialEq + 'static,
F: Fn(&S) -> R + 'static,
{
use_selector_eq(selector, |a, b| a == b)
}
#[hook]
pub fn use_selector_eq<S, F, R, E>(selector: F, eq: E) -> Rc<R>
where
S: Store,
R: 'static,
F: Fn(&S) -> R + 'static,
E: Fn(&R, &R) -> bool + 'static,
{
use_selector_eq_with_deps(move |state, _| selector(state), eq, ())
}
#[hook]
pub fn use_selector_with_deps<S, F, R, D>(selector: F, deps: D) -> Rc<R>
where
S: Store,
R: PartialEq + 'static,
D: Clone + PartialEq + 'static,
F: Fn(&S, &D) -> R + 'static,
{
use_selector_eq_with_deps(selector, |a, b| a == b, deps)
}
#[hook]
pub fn use_selector_eq_with_deps<S, F, R, D, E>(selector: F, eq: E, deps: D) -> Rc<R>
where
S: Store,
R: 'static,
D: Clone + PartialEq + 'static,
F: Fn(&S, &D) -> R + 'static,
E: Fn(&R, &R) -> bool + 'static,
{
let selected = {
let state = dispatch::get::<S>();
let value = selector(&state, &deps);
use_state(|| Rc::new(value))
};
let current = {
let value = Rc::clone(&selected);
use_mut_ref(|| value)
};
let _dispatch = {
let selected = selected.clone();
use_memo(
move |deps| {
let deps = deps.clone();
Dispatch::subscribe(move |val: Rc<S>| {
let value = selector(&val, &deps);
if !eq(¤t.borrow(), &value) {
let value = Rc::new(value);
selected.set(Rc::clone(&value));
*current.borrow_mut() = Rc::clone(&value);
}
})
},
deps,
)
};
Rc::clone(&selected)
}