mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
tests: fix Effect
doctests not being executed, and test-related issues (#2886)
This commit is contained in:
parent
a083b57260
commit
96a1f80daf
5 changed files with 69 additions and 47 deletions
|
@ -13,7 +13,7 @@ use reactive_graph::{
|
|||
effect::RenderEffect,
|
||||
owner::{provide_context, use_context, Owner},
|
||||
signal::ArcRwSignal,
|
||||
traits::{Get, Read, Track, With},
|
||||
traits::{Dispose, Get, Read, Track, With},
|
||||
};
|
||||
use slotmap::{DefaultKey, SlotMap};
|
||||
use tachys::{
|
||||
|
@ -286,7 +286,7 @@ where
|
|||
self.children.dry_resolve();
|
||||
|
||||
// check the set of tasks to see if it is empty, now or later
|
||||
let eff = reactive_graph::effect::RenderEffect::new_isomorphic({
|
||||
let eff = reactive_graph::effect::Effect::new_isomorphic({
|
||||
move |_| {
|
||||
tasks.track();
|
||||
if tasks.read().is_empty() {
|
||||
|
@ -338,7 +338,7 @@ where
|
|||
}
|
||||
children = children => {
|
||||
// clean up the (now useless) effect
|
||||
drop(eff);
|
||||
eff.dispose();
|
||||
|
||||
Some(OwnedView::new_with_owner(children, owner))
|
||||
}
|
||||
|
|
|
@ -163,10 +163,10 @@ where
|
|||
#[deprecated = "This function is being removed to conform to Rust idioms. \
|
||||
Please use `Selector::new()` instead."]
|
||||
pub fn create_selector<T>(
|
||||
source: impl Fn() -> T + Clone + 'static,
|
||||
source: impl Fn() -> T + Clone + Send + Sync + 'static,
|
||||
) -> Selector<T>
|
||||
where
|
||||
T: PartialEq + Eq + Clone + std::hash::Hash + 'static,
|
||||
T: PartialEq + Eq + Send + Sync + Clone + std::hash::Hash + 'static,
|
||||
{
|
||||
Selector::new(source)
|
||||
}
|
||||
|
@ -178,11 +178,11 @@ where
|
|||
#[deprecated = "This function is being removed to conform to Rust idioms. \
|
||||
Please use `Selector::new_with_fn()` instead."]
|
||||
pub fn create_selector_with_fn<T>(
|
||||
source: impl Fn() -> T + Clone + 'static,
|
||||
source: impl Fn() -> T + Clone + Send + Sync + 'static,
|
||||
f: impl Fn(&T, &T) -> bool + Send + Sync + Clone + 'static,
|
||||
) -> Selector<T>
|
||||
where
|
||||
T: PartialEq + Eq + Clone + std::hash::Hash + 'static,
|
||||
T: PartialEq + Eq + Send + Sync + Clone + std::hash::Hash + 'static,
|
||||
{
|
||||
Selector::new_with_fn(source, f)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ use std::{
|
|||
/// let a = RwSignal::new(0);
|
||||
/// let is_selected = Selector::new(move || a.get());
|
||||
/// let total_notifications = StoredValue::new(0);
|
||||
/// Effect::new({
|
||||
/// Effect::new_isomorphic({
|
||||
/// let is_selected = is_selected.clone();
|
||||
/// move |_| {
|
||||
/// if is_selected.selected(5) {
|
||||
|
@ -55,7 +55,7 @@ use std::{
|
|||
///
|
||||
/// # any_spawner::Executor::tick().await;
|
||||
/// assert_eq!(is_selected.selected(5), false);
|
||||
/// # });
|
||||
/// # }).await;
|
||||
/// # });
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
|
@ -74,17 +74,17 @@ where
|
|||
|
||||
impl<T> Selector<T>
|
||||
where
|
||||
T: PartialEq + Eq + Clone + Hash + 'static,
|
||||
T: PartialEq + Send + Sync + Eq + Clone + Hash + 'static,
|
||||
{
|
||||
/// Creates a new selector that compares values using [`PartialEq`].
|
||||
pub fn new(source: impl Fn() -> T + Clone + 'static) -> Self {
|
||||
pub fn new(source: impl Fn() -> T + Send + Sync + Clone + 'static) -> Self {
|
||||
Self::new_with_fn(source, PartialEq::eq)
|
||||
}
|
||||
|
||||
/// Creates a new selector that compares values by returning `true` from a comparator function
|
||||
/// if the values are the same.
|
||||
pub fn new_with_fn(
|
||||
source: impl Fn() -> T + Clone + 'static,
|
||||
source: impl Fn() -> T + Clone + Send + Sync + 'static,
|
||||
f: impl Fn(&T, &T) -> bool + Send + Sync + Clone + 'static,
|
||||
) -> Self {
|
||||
let subs: Arc<RwLock<FxHashMap<T, ArcRwSignal<bool>>>> =
|
||||
|
@ -92,7 +92,7 @@ where
|
|||
let v: Arc<RwLock<Option<T>>> = Default::default();
|
||||
let f = Arc::new(f) as Arc<dyn Fn(&T, &T) -> bool + Send + Sync>;
|
||||
|
||||
let effect = Arc::new(RenderEffect::new({
|
||||
let effect = Arc::new(RenderEffect::new_isomorphic({
|
||||
let subs = Arc::clone(&subs);
|
||||
let f = Arc::clone(&f);
|
||||
let v = Arc::clone(&v);
|
||||
|
|
|
@ -43,6 +43,7 @@ use std::{
|
|||
/// # use reactive_graph::owner::StoredValue;
|
||||
/// # tokio_test::block_on(async move {
|
||||
/// # tokio::task::LocalSet::new().run_until(async move {
|
||||
/// # any_spawner::Executor::init_tokio();
|
||||
/// let a = RwSignal::new(0);
|
||||
/// let b = RwSignal::new(0);
|
||||
///
|
||||
|
@ -52,7 +53,9 @@ use std::{
|
|||
/// println!("Value: {}", a.get());
|
||||
/// });
|
||||
///
|
||||
/// # assert_eq!(a.get(), 0);
|
||||
/// a.set(1);
|
||||
/// # assert_eq!(a.get(), 1);
|
||||
/// // ✅ because it's subscribed to `a`, the effect reruns and prints "Value: 1"
|
||||
///
|
||||
/// // ❌ don't use effects to synchronize state within the reactive system
|
||||
|
@ -61,7 +64,7 @@ use std::{
|
|||
/// // and easily lead to problems like infinite loops
|
||||
/// b.set(a.get() + 1);
|
||||
/// });
|
||||
/// # });
|
||||
/// # }).await;
|
||||
/// # });
|
||||
/// ```
|
||||
/// ## Web-Specific Notes
|
||||
|
@ -182,6 +185,7 @@ impl Effect<LocalStorage> {
|
|||
/// # use reactive_graph::signal::signal;
|
||||
/// # tokio_test::block_on(async move {
|
||||
/// # tokio::task::LocalSet::new().run_until(async move {
|
||||
/// # any_spawner::Executor::init_tokio();
|
||||
/// #
|
||||
/// let (num, set_num) = signal(0);
|
||||
///
|
||||
|
@ -192,13 +196,16 @@ impl Effect<LocalStorage> {
|
|||
/// },
|
||||
/// false,
|
||||
/// );
|
||||
/// # assert_eq!(num.get(), 0);
|
||||
///
|
||||
/// set_num.set(1); // > "Number: 1; Prev: Some(0)"
|
||||
/// # assert_eq!(num.get(), 1);
|
||||
///
|
||||
/// effect.stop(); // stop watching
|
||||
///
|
||||
/// set_num.set(2); // (nothing happens)
|
||||
/// # });
|
||||
/// # assert_eq!(num.get(), 2);
|
||||
/// # }).await;
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
|
@ -210,6 +217,7 @@ impl Effect<LocalStorage> {
|
|||
/// # use reactive_graph::signal::signal;
|
||||
/// # tokio_test::block_on(async move {
|
||||
/// # tokio::task::LocalSet::new().run_until(async move {
|
||||
/// # any_spawner::Executor::init_tokio();
|
||||
/// #
|
||||
/// let (num, set_num) = signal(0);
|
||||
/// let (cb_num, set_cb_num) = signal(0);
|
||||
|
@ -222,12 +230,17 @@ impl Effect<LocalStorage> {
|
|||
/// false,
|
||||
/// );
|
||||
///
|
||||
/// # assert_eq!(num.get(), 0);
|
||||
/// set_num.set(1); // > "Number: 1; Cb: 0"
|
||||
/// # assert_eq!(num.get(), 1);
|
||||
///
|
||||
/// # assert_eq!(cb_num.get(), 0);
|
||||
/// set_cb_num.set(1); // (nothing happens)
|
||||
/// # assert_eq!(cb_num.get(), 1);
|
||||
///
|
||||
/// set_num.set(2); // > "Number: 2; Cb: 1"
|
||||
/// # });
|
||||
/// # assert_eq!(num.get(), 2);
|
||||
/// # }).await;
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
|
@ -243,6 +256,7 @@ impl Effect<LocalStorage> {
|
|||
/// # use reactive_graph::signal::signal;
|
||||
/// # tokio_test::block_on(async move {
|
||||
/// # tokio::task::LocalSet::new().run_until(async move {
|
||||
/// # any_spawner::Executor::init_tokio();
|
||||
/// #
|
||||
/// let (num, set_num) = signal(0);
|
||||
///
|
||||
|
@ -254,8 +268,10 @@ impl Effect<LocalStorage> {
|
|||
/// true,
|
||||
/// ); // > "Number: 0; Prev: None"
|
||||
///
|
||||
/// # assert_eq!(num.get(), 0);
|
||||
/// set_num.set(1); // > "Number: 1; Prev: Some(0)"
|
||||
/// # });
|
||||
/// # assert_eq!(num.get(), 1);
|
||||
/// # }).await;
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn watch<D, T>(
|
||||
|
|
|
@ -135,44 +135,50 @@ where
|
|||
{
|
||||
/// Creates a render effect that will run whether the `effects` feature is enabled or not.
|
||||
pub fn new_isomorphic(
|
||||
mut fun: impl FnMut(Option<T>) -> T + Send + 'static,
|
||||
fun: impl FnMut(Option<T>) -> T + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
let (mut observer, mut rx) = channel();
|
||||
observer.notify();
|
||||
fn erased<T: Send + Sync + 'static>(
|
||||
mut fun: Box<dyn FnMut(Option<T>) -> T + Send + Sync + 'static>,
|
||||
) -> RenderEffect<T> {
|
||||
let (observer, mut rx) = channel();
|
||||
let value = Arc::new(RwLock::new(None::<T>));
|
||||
let owner = Owner::new();
|
||||
let inner = Arc::new(RwLock::new(EffectInner {
|
||||
dirty: false,
|
||||
observer,
|
||||
sources: SourceSet::new(),
|
||||
}));
|
||||
|
||||
let value = Arc::new(RwLock::new(None::<T>));
|
||||
let owner = Owner::new();
|
||||
let inner = Arc::new(RwLock::new(EffectInner {
|
||||
dirty: false,
|
||||
observer,
|
||||
sources: SourceSet::new(),
|
||||
}));
|
||||
let mut first_run = true;
|
||||
let initial_value = owner
|
||||
.with(|| inner.to_any_subscriber().with_observer(|| fun(None)));
|
||||
*value.write().or_poisoned() = Some(initial_value);
|
||||
|
||||
Executor::spawn({
|
||||
let value = Arc::clone(&value);
|
||||
let subscriber = inner.to_any_subscriber();
|
||||
Executor::spawn({
|
||||
let value = Arc::clone(&value);
|
||||
let subscriber = inner.to_any_subscriber();
|
||||
|
||||
async move {
|
||||
while rx.next().await.is_some() {
|
||||
if first_run
|
||||
|| subscriber
|
||||
async move {
|
||||
while rx.next().await.is_some() {
|
||||
if subscriber
|
||||
.with_observer(|| subscriber.update_if_necessary())
|
||||
{
|
||||
first_run = false;
|
||||
subscriber.clear_sources(&subscriber);
|
||||
{
|
||||
subscriber.clear_sources(&subscriber);
|
||||
|
||||
let old_value =
|
||||
mem::take(&mut *value.write().or_poisoned());
|
||||
let new_value = owner.with_cleanup(|| {
|
||||
subscriber.with_observer(|| fun(old_value))
|
||||
});
|
||||
*value.write().or_poisoned() = Some(new_value);
|
||||
let old_value =
|
||||
mem::take(&mut *value.write().or_poisoned());
|
||||
let new_value = owner.with_cleanup(|| {
|
||||
subscriber.with_observer(|| fun(old_value))
|
||||
});
|
||||
*value.write().or_poisoned() = Some(new_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
RenderEffect { value, inner }
|
||||
});
|
||||
|
||||
RenderEffect { value, inner }
|
||||
}
|
||||
|
||||
erased(Box::new(fun))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue