diff --git a/packages/hooks/src/lib.rs b/packages/hooks/src/lib.rs index 598442e19..e63353a4e 100644 --- a/packages/hooks/src/lib.rs +++ b/packages/hooks/src/lib.rs @@ -16,6 +16,9 @@ pub use usefuture::*; mod usecallback; pub use usecallback::*; +mod useeffect; +pub use useeffect::*; + #[macro_export] /// A helper macro for using hooks in async environements. /// diff --git a/packages/hooks/src/usecallback.rs b/packages/hooks/src/usecallback.rs index 1affd323f..94e74cf1c 100644 --- a/packages/hooks/src/usecallback.rs +++ b/packages/hooks/src/usecallback.rs @@ -7,7 +7,6 @@ use std::future::Future; pub fn use_callback + 'static>( cx: &ScopeState, - // g: G, f: impl FnMut(I, G::Out) -> F, ) -> &UseCallback @@ -26,7 +25,7 @@ where pub struct UseCallback { f: Rc>>>, - f2: Box, // f: Rc>>>, + f2: Box, } impl std::ops::Deref for UseCallback { @@ -37,10 +36,6 @@ impl std::ops::Deref for UseCallback { } } -trait MyThing {} -impl MyThing for Box {} -impl MyThing for Box {} - #[test] fn demo() { use dioxus_core::prelude::*; @@ -53,6 +48,7 @@ fn demo() { }); let onsubmit = use_callback(&cx, (name,), my_callback); + async fn my_callback(event: UiEvent<()>, name: (i32,)) { // } diff --git a/packages/hooks/src/useeffect.rs b/packages/hooks/src/useeffect.rs new file mode 100644 index 000000000..b6f6a01eb --- /dev/null +++ b/packages/hooks/src/useeffect.rs @@ -0,0 +1,81 @@ +use dioxus_core::{ScopeState, TaskId}; +use std::{any::Any, cell::Cell, future::Future}; + +use crate::UseFutureDep; + +/// A hook that provides a future that executes after the hooks have been applied +/// +/// Whenever the hooks dependencies change, the future will be re-evaluated. +/// If a future is pending when the dependencies change, the previous future +/// will be allowed to continue +/// +/// - dependencies: a tuple of references to values that are PartialEq + Clone +pub fn use_effect<'a, T: 'static, F: Future + 'static, D: UseFutureDep>( + cx: &'a ScopeState, + dependencies: D, + future: impl FnOnce(D::Out) -> F, +) -> &'a UseEffect { + let state = cx.use_hook(move |_| UseEffect { + needs_regen: Cell::new(true), + task: Cell::new(None), + dependencies: Vec::new(), + }); + + if dependencies.clone().apply(&mut state.dependencies) || state.needs_regen.get() { + // We don't need regen anymore + state.needs_regen.set(false); + + // Create the new future + let fut = future(dependencies.out()); + + state.task.set(Some(cx.push_future(async move { + fut.await; + }))); + } + + state +} + +pub struct UseEffect { + needs_regen: Cell, + task: Cell>, + dependencies: Vec>, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[allow(unused)] + #[test] + fn test_use_future() { + use dioxus_core::prelude::*; + + struct MyProps { + a: String, + b: i32, + c: i32, + d: i32, + e: i32, + } + + fn app(cx: Scope) -> Element { + // should only ever run once + use_effect(&cx, (), |_| async move { + // + }); + + // runs when a is changed + use_effect(&cx, (&cx.props.a,), |(a,)| async move { + // + }); + + // runs when a or b is changed + use_effect(&cx, (&cx.props.a, &cx.props.b), |(a, b)| async move { + // + }); + + None + } + } +}