1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
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
///
/// ## Examples
///
/// ```rust, ignore
///
/// #[inline_props]
/// fn app(cx: Scope, name: &str) -> Element {
/// use_effect(cx, (name,), |(name,)| async move {
/// set_title(name);
/// }))
/// }
/// ```
pub fn use_effect<T, F, D>(cx: &ScopeState, dependencies: D, future: impl FnOnce(D::Out) -> F)
where
T: 'static,
F: Future<Output = T> + 'static,
D: UseFutureDep,
{
struct UseEffect {
needs_regen: bool,
task: Cell<Option<TaskId>>,
dependencies: Vec<Box<dyn Any>>,
}
let state = cx.use_hook(move || UseEffect {
needs_regen: true,
task: Cell::new(None),
dependencies: Vec::new(),
});
if dependencies.clone().apply(&mut state.dependencies) || state.needs_regen {
// We don't need regen anymore
state.needs_regen = false;
// Create the new future
let fut = future(dependencies.out());
state.task.set(Some(cx.push_future(async move {
fut.await;
})));
}
}
#[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<MyProps>) -> 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 {
//
});
todo!()
}
}
}