add a way to add manual dependency tuple to memos and effects

This commit is contained in:
Evan Almloff committed 2024-03-13 09:54:48 -05:00
1 parent 2bbc609082
commit 0951a389f7
7 files changed
+106 -105

No files matched your search

+67
View File
@@ -0,0 +1,67 @@
/// A dependency is a trait that can be used to determine if a effect or selector should be re-run.
pub trait Dependency: Sized + Clone {
/// The output of the dependency
type Out: Clone + PartialEq + 'static;
/// Returns the output of the dependency.
fn out(&self) -> Self::Out;
/// Returns true if the dependency has changed.
fn changed(&self, other: &Self::Out) -> bool {
self.out() != *other
}
}
impl Dependency for () {
type Out = ();
fn out(&self) -> Self::Out {}
}
/// A dependency is a trait that can be used to determine if a effect or selector should be re-run.
pub trait DependencyElement: 'static + PartialEq + Clone {}
impl<T> DependencyElement for T where T: 'static + PartialEq + Clone {}
impl<A: DependencyElement> Dependency for &A {
type Out = A;
fn out(&self) -> Self::Out {
(*self).clone()
}
}
macro_rules! impl_dep {
(
$($el:ident=$name:ident $other:ident,)*
) => {
impl< $($el),* > Dependency for ($(&$el,)*)
where
$(
$el: DependencyElement
),*
{
type Out = ($($el,)*);
fn out(&self) -> Self::Out {
let ($($name,)*) = self;
($((*$name).clone(),)*)
}
fn changed(&self, other: &Self::Out) -> bool {
let ($($name,)*) = self;
let ($($other,)*) = other;
$(
if *$name != $other {
return true;
}
)*
false
}
}
};
}
impl_dep!(A = a1 a2,);
impl_dep!(A = a1 a2, B = b1 b2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2, G = g1 g2,);
impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2, G = g1 g2, H = h1 h2,);
+3
View File
@@ -19,6 +19,9 @@ pub use map::*;
// mod comparer;
// pub use comparer::*;
mod dependency;
pub use dependency::*;
mod memo;
pub use memo::*;
+35 -1
View File
@@ -1,6 +1,6 @@
use crate::write::Writable;
use crate::{read::Readable, ReactiveContext, ReadableRef, Signal};
use crate::{CopyValue, ReadOnlySignal};
use crate::{CopyValue, Dependency, ReadOnlySignal};
use std::rc::Rc;
use std::{
cell::RefCell,
@@ -153,6 +153,40 @@ impl<T: 'static> Memo<T> {
pub fn id(&self) -> generational_box::GenerationalBoxId {
self.inner.id()
}
/// Adds an explicit dependency to the memo. If the dependency changes, the memo will rerun.
///
/// Signals will automatically be added as dependencies, so you don't need to call this method for them.
///
/// NOTE: You must follow the rules of hooks when calling this method.
///
/// ```rust
/// # use dioxus::prelude::*;
/// # async fn sleep(delay: u32) {}
///
/// #[component]
/// fn Comp(count: u32) -> Element {
/// // Because the resource subscribes to `delay` by adding it as a dependency, the memo will rerun every time `count` changes.
/// let new_count = use_memo(move || async move {
/// count + 1
/// })
/// .use_dependencies((&count,));
///
/// todo!()
/// }
/// ```
pub fn use_dependencies(self, dependency: impl Dependency) -> Self
where
T: PartialEq,
{
let mut dependencies_signal = use_hook(|| CopyValue::new(dependency.out()));
let changed = { dependency.changed(&*dependencies_signal.read()) };
if changed {
dependencies_signal.set(dependency.out());
self.recompute();
}
self
}
}
impl<T> Readable for Memo<T>