فهرست منبع

Remove push_future, get use_future kinda working again

Jonathan Kelley 1 سال پیش
والد
کامیت
a32ae8b112

+ 1 - 7
examples/pattern_reducer.rs

@@ -4,9 +4,6 @@
 //! This example shows how to encapsulate state in dioxus components with the reducer pattern.
 //! This pattern is very useful when a single component can handle many types of input that can
 //! be represented by an enum.
-//!
-//! Currently we don't have a reducer pattern hook. If you'd like to add it,
-//! feel free to make a PR.
 
 use dioxus::prelude::*;
 
@@ -15,7 +12,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let state = use_signal(PlayerState::new);
+    let state = use_signal(|| PlayerState { is_playing: false });
 
     rsx!(
         div {
@@ -38,9 +35,6 @@ struct PlayerState {
 }
 
 impl PlayerState {
-    fn new() -> Self {
-        Self { is_playing: false }
-    }
     fn reduce(&mut self, action: PlayerAction) {
         match action {
             PlayerAction::Pause => self.is_playing = false,

+ 2 - 7
packages/core/src/global_context.rs

@@ -62,14 +62,9 @@ pub fn suspend() -> Option<Element> {
     None
 }
 
-/// Pushes the future onto the poll queue to be polled after the component renders.
-pub fn push_future(fut: impl Future<Output = ()> + 'static) -> Option<Task> {
-    with_current_scope(|cx| cx.push_future(fut))
-}
-
 /// Spawns the future but does not return the [`TaskId`]
-pub fn spawn(fut: impl Future<Output = ()> + 'static) {
-    with_current_scope(|cx| cx.spawn(fut));
+pub fn spawn(fut: impl Future<Output = ()> + 'static) -> Task {
+    with_current_scope(|cx| cx.spawn(fut)).expect("to be in a dioxus runtime")
 }
 
 /// Spawn a future that Dioxus won't clean up when this component is unmounted

+ 3 - 3
packages/core/src/lib.rs

@@ -87,9 +87,9 @@ pub mod prelude {
     pub use crate::innerlude::{
         consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, generation,
         has_context, needs_update, parent_scope, provide_context, provide_root_context,
-        push_future, remove_future, schedule_update, schedule_update_any, spawn, spawn_forever,
-        suspend, try_consume_context, use_error_boundary, use_hook, AnyValue, Attribute, Component,
-        Element, ErrorBoundary, Event, EventHandler, Fragment, HasAttributes, IntoAttributeValue,
+        remove_future, schedule_update, schedule_update_any, spawn, spawn_forever, suspend,
+        try_consume_context, use_error_boundary, use_hook, AnyValue, Attribute, Component, Element,
+        ErrorBoundary, Event, EventHandler, Fragment, HasAttributes, IntoAttributeValue,
         IntoDynNode, Properties, Runtime, RuntimeGuard, ScopeId, ScopeState, Task, Template,
         TemplateAttribute, TemplateNode, Throw, VNode, VNodeInner, VirtualDom,
     };

+ 2 - 2
packages/core/src/scheduler/task.rs

@@ -1,7 +1,7 @@
 use futures_util::task::ArcWake;
 
 use super::SchedulerMsg;
-use crate::innerlude::{push_future, remove_future, Runtime};
+use crate::innerlude::{remove_future, spawn, Runtime};
 use crate::ScopeId;
 use std::cell::RefCell;
 use std::future::Future;
@@ -28,7 +28,7 @@ impl Task {
     /// Spawning a future onto the root scope will cause it to be dropped when the root component is dropped - which
     /// will only occur when the VirtualDom itself has been dropped.
     pub fn new(task: impl Future<Output = ()> + 'static) -> Self {
-        push_future(task).expect("to be in a dioxus runtime")
+        spawn(task)
     }
 
     /// Drop the task immediately.

+ 3 - 8
packages/core/src/scope_context.rs

@@ -225,18 +225,13 @@ impl ScopeContext {
         .expect("Runtime to exist")
     }
 
-    /// Pushes the future onto the poll queue to be polled after the component renders.
-    pub fn push_future(&self, fut: impl Future<Output = ()> + 'static) -> Task {
+    /// Spawns the future but does not return the [`TaskId`]
+    pub fn spawn(&self, fut: impl Future<Output = ()> + 'static) -> Task {
         let id = with_runtime(|rt| rt.spawn(self.id, fut)).expect("Runtime to exist");
         self.spawned_tasks.borrow_mut().insert(id);
         id
     }
 
-    /// Spawns the future but does not return the [`TaskId`]
-    pub fn spawn(&self, fut: impl Future<Output = ()> + 'static) {
-        self.push_future(fut);
-    }
-
     /// Spawn a future that Dioxus won't clean up when this component is unmounted
     ///
     /// This is good for tasks that need to be run after the component has been dropped.
@@ -369,7 +364,7 @@ impl ScopeId {
 
     /// Pushes the future onto the poll queue to be polled after the component renders.
     pub fn push_future(self, fut: impl Future<Output = ()> + 'static) -> Option<Task> {
-        with_scope(self, |cx| cx.push_future(fut))
+        with_scope(self, |cx| cx.spawn(fut))
     }
 
     /// Spawns the future but does not return the [`TaskId`]

+ 1 - 0
packages/hooks/Cargo.toml

@@ -21,6 +21,7 @@ tracing = { workspace = true }
 thiserror = { workspace = true }
 slab = { workspace = true }
 dioxus-debug-cell = "0.1.1"
+futures-util = { workspace = true}
 
 [dev-dependencies]
 futures-util = { workspace = true, default-features = false }

+ 37 - 12
packages/hooks/src/use_future.rs

@@ -1,7 +1,11 @@
 #![allow(missing_docs)]
-use dioxus_core::{ScopeState, Task};
+use dioxus_core::{
+    prelude::{spawn, use_hook},
+    ScopeState, Task,
+};
 use dioxus_signals::{use_effect, use_signal, Signal};
-use std::{any::Any, cell::Cell, future::Future, rc::Rc, sync::Arc};
+use futures_util::{future, pin_mut, FutureExt};
+use std::{any::Any, cell::Cell, future::Future, pin::Pin, rc::Rc, sync::Arc, task::Poll};
 
 /// A future that resolves to a value.
 ///
@@ -21,22 +25,43 @@ where
     T: 'static,
     F: Future<Output = T> + 'static,
 {
-    let task = use_signal(|| None);
+    let value = use_signal(|| None);
+    let state = use_signal(|| UseFutureState::Pending);
 
-    use_effect(|| {
-        // task.set();
+    let task = use_signal(|| {
+        // Create the user's task
+        let fut = future();
+
+        // Spawn a wrapper task that polls the innner future and watch its dependencies
+        let task = spawn(async move {
+            // move the future here and pin it so we can ppoll it
+            let mut fut = fut;
+            pin_mut!(fut);
+
+            let res = future::poll_fn(|cx| {
+                // Set the effect stack properly
+
+                // Poll the inner future
+                let ready = fut.poll_unpin(cx);
+
+                // add any dependencies to the effect stack
+
+                ready
+            })
+            .await;
+
+            // Set the value
+            value.set(Some(res));
+        });
+
+        Some(task)
     });
-    //
 
-    UseFuture {
-        value: todo!(),
-        task,
-        state: todo!(),
-    }
+    UseFuture { task, value, state }
 }
 
 pub struct UseFuture<T: 'static> {
-    value: Signal<T>,
+    value: Signal<Option<T>>,
     task: Signal<Option<Task>>,
     state: Signal<UseFutureState<T>>,
 }

+ 0 - 21
packages/signals/src/effect.rs

@@ -42,27 +42,6 @@ pub fn use_effect(callback: impl FnMut() + 'static) {
     use_hook(|| Effect::new(callback));
 }
 
-/// Create a new effect. The effect will be run immediately and whenever any signal it reads changes.
-/// The signal will be owned by the current component and will be dropped when the component is dropped.
-pub fn use_effect_with_dependencies<D: Dependency>(
-    dependencies: D,
-    mut callback: impl FnMut(D::Out) + 'static,
-) where
-    D::Out: 'static,
-{
-    let dependencies_signal = use_signal(|| dependencies.out());
-    use_hook(|| {
-        Effect::new(move || {
-            let deref = &*dependencies_signal.read();
-            callback(deref.clone());
-        });
-    });
-    let changed = { dependencies.changed(&*dependencies_signal.read()) };
-    if changed {
-        dependencies_signal.set(dependencies.out());
-    }
-}
-
 /// Effects allow you to run code when a signal changes. Effects are run immediately and whenever any signal it reads changes.
 #[derive(Copy, Clone, PartialEq)]
 pub struct Effect {