فهرست منبع

Fix warnings and compile errors

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

+ 1 - 1
packages/fullstack/examples/salvo-hello-world/src/main.rs

@@ -10,7 +10,7 @@ use dioxus_fullstack::{launch, prelude::*};
 use serde::{Deserialize, Serialize};
 
 fn app() -> Element {
-    let state = use_server_future(move || async move { get_server_data().await.unwrap() });
+    let state = use_server_future(move || async move { get_server_data().await.unwrap() })?;
 
     let mut count = use_signal(|| 0);
     let mut text = use_signal(|| "...".to_string());

+ 5 - 0
packages/hooks/src/use_resource.rs

@@ -147,6 +147,11 @@ impl<T> Resource<T> {
         self.state.into()
     }
 
+    /// Get the current value of the future.
+    pub fn value(&self) -> Option<ReadOnlySignal<T>> {
+        self.value.peek().as_ref().map(|sig| sig.clone().into())
+    }
+
     /// Wait for this async memo to resolve, returning the inner signal value
     /// If the value is pending, returns none and suspends the current component
     pub fn suspend(&self) -> Option<ReadOnlySignal<T>> {

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

@@ -1,202 +0,0 @@
-use crate::write::*;
-use crate::CopyValue;
-use core::{self, fmt::Debug};
-use dioxus_core::prelude::*;
-use futures_channel::mpsc::UnboundedSender;
-use futures_util::{future::Either, pin_mut, StreamExt};
-use generational_box::GenerationalBoxId;
-use parking_lot::RwLock;
-use rustc_hash::FxHashMap;
-use std::fmt::{self, Formatter};
-
-thread_local! {
-    pub(crate)static EFFECT_STACK: EffectStack = EffectStack::default();
-}
-
-#[derive(Default)]
-pub(crate) struct EffectStack {
-    pub(crate) effects: RwLock<Vec<Effect>>,
-    pub(crate) effect_mapping: RwLock<FxHashMap<GenerationalBoxId, Effect>>,
-}
-
-impl EffectStack {
-    pub(crate) fn current(&self) -> Option<Effect> {
-        self.effects.read().last().copied()
-    }
-}
-
-/// This is a thread safe reference to an effect stack running on another thread.
-#[derive(Clone)]
-pub(crate) struct EffectStackRef {
-    rerun_effect: UnboundedSender<GenerationalBoxId>,
-}
-
-impl EffectStackRef {
-    pub(crate) fn rerun_effect(&self, id: GenerationalBoxId) {
-        self.rerun_effect.unbounded_send(id).unwrap();
-    }
-}
-
-pub(crate) fn get_effect_ref() -> EffectStackRef {
-    if let Some(rt) = try_consume_context() {
-        return rt;
-    }
-
-    let (sender, receiver) = futures_channel::mpsc::unbounded();
-
-    spawn_forever(async move { effect_driver(receiver).await });
-
-    let stack_ref = EffectStackRef {
-        rerun_effect: sender,
-    };
-
-    provide_root_context(stack_ref.clone());
-
-    stack_ref
-}
-
-/// The primary top-level driver of all effects
-///
-/// In Dioxus, effects are neither react effects nor solidjs effects. They are a hybrid of the two, making our model
-/// more complex but also more powerful.
-///
-/// In react, when a component renders, it can queue up effects to be run after the component is done rendering.
-/// This is done *only during render* and determined by the dependency array attached to the effect. In Dioxus,
-/// we track effects using signals, so these effects can actually run multiple times after the component has rendered.
-///
-///
-async fn effect_driver(
-    mut receiver: futures_channel::mpsc::UnboundedReceiver<GenerationalBoxId>,
-) -> ! {
-    let mut queued_memos = Vec::new();
-
-    loop {
-        // Wait for a flush
-        // This gives a chance for effects to be updated in place and memos to compute their values
-        let flush_await = flush_sync();
-        pin_mut!(flush_await);
-
-        // Until the flush is ready, wait for a new effect to be queued
-        // We don't run the effects immediately because we want to batch them on the next call to flush
-        // todo: the queued memos should be unqueued when components are dropped
-        loop {
-            match futures_util::future::select(&mut flush_await, receiver.next()).await {
-                // VDOM is flushed and we can run the queued effects
-                Either::Left(_flushed) => break,
-
-                // A new effect was queued to be run after the next flush
-                // Marking components as dirty is handled syncrhonously on write, though we could try
-                // batching them here too
-                Either::Right((_queued, _)) => {
-                    if let Some(task) = _queued {
-                        queued_memos.push(task);
-                    }
-                }
-            }
-        }
-
-        EFFECT_STACK.with(|stack| {
-            for id in queued_memos.drain(..) {
-                let effect_mapping = stack.effect_mapping.read();
-                if let Some(mut effect) = effect_mapping.get(&id).copied() {
-                    tracing::trace!("Rerunning effect: {:?}", id);
-                    effect.try_run();
-                } else {
-                    tracing::trace!("Effect not found: {:?}", id);
-                }
-            }
-        });
-    }
-}
-
-/// 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 {
-    pub(crate) source: ScopeId,
-    pub(crate) inner: CopyValue<EffectInner>,
-}
-
-pub(crate) struct EffectInner {
-    pub(crate) callback: Box<dyn FnMut()>,
-    pub(crate) id: GenerationalBoxId,
-}
-
-impl EffectInner {
-    pub(crate) fn new(callback: Box<dyn FnMut()>) -> CopyValue<Self> {
-        let mut copy = CopyValue::invalid();
-        let inner = EffectInner {
-            callback: Box::new(callback),
-            id: copy.id(),
-        };
-        copy.set(inner);
-        copy
-    }
-}
-
-impl Drop for EffectInner {
-    fn drop(&mut self) {
-        EFFECT_STACK.with(|stack| {
-            tracing::trace!("Dropping effect: {:?}", self.id);
-            stack.effect_mapping.write().remove(&self.id);
-        });
-    }
-}
-
-impl Debug for Effect {
-    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        f.write_fmt(format_args!("{:?}", self.inner.value))
-    }
-}
-
-impl Effect {
-    pub(crate) fn current() -> Option<Self> {
-        EFFECT_STACK.with(|stack| stack.effects.read().last().copied())
-    }
-
-    /// 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.
-    fn new(mut callback: impl FnMut() + 'static) -> Self {
-        let source = current_scope_id().expect("in a virtual dom");
-        let myself = Self {
-            source,
-            #[allow(clippy::redundant_closure)]
-            inner: EffectInner::new(Box::new(move || source.in_runtime(|| callback()))),
-        };
-
-        EFFECT_STACK.with(|stack| {
-            stack
-                .effect_mapping
-                .write()
-                .insert(myself.inner.id(), myself);
-        });
-        tracing::trace!("Created effect: {:?}", myself);
-
-        get_effect_ref().rerun_effect(myself.inner.id());
-
-        myself
-    }
-
-    /// Run the effect callback immediately. Returns `true` if the effect was run. Returns `false` is the effect is dead.
-    pub fn try_run(&mut self) {
-        tracing::trace!("Running effect: {:?}", self);
-        if let Ok(mut inner) = self.inner.try_write() {
-            {
-                EFFECT_STACK.with(|stack| {
-                    stack.effects.write().push(*self);
-                });
-            }
-            (inner.callback)();
-            {
-                EFFECT_STACK.with(|stack| {
-                    stack.effects.write().pop();
-                });
-            }
-        }
-    }
-
-    /// Get the id of this effect.
-    pub fn id(&self) -> GenerationalBoxId {
-        self.inner.id()
-    }
-}

+ 0 - 3
packages/signals/src/lib.rs

@@ -7,9 +7,6 @@
 mod rt;
 pub use rt::*;
 
-mod effect;
-pub use effect::*;
-
 pub(crate) mod signal;
 pub use signal::*;
 

+ 6 - 0
packages/signals/src/rc.rs

@@ -23,6 +23,7 @@ thread_local! {
 }
 
 impl ReactiveContext {
+    /// Create a new reactive context
     pub fn new(scope: Option<ScopeId>) -> Self {
         let (tx, rx) = flume::unbounded();
 
@@ -104,6 +105,11 @@ impl ReactiveContext {
             .insert(signal, rc_list);
     }
 
+    /// Get the scope that inner CopyValue is associated with
+    pub fn origin_scope(&self) -> ScopeId {
+        self.inner.origin_scope()
+    }
+
     /// Wait for this reactive context to change
     pub async fn changed(&self) {
         let rx = self.inner.read().receiver.clone();

+ 10 - 25
packages/signals/src/rt.rs

@@ -13,9 +13,8 @@ use dioxus_core::ScopeId;
 
 use generational_box::{GenerationalBox, Owner, Storage};
 
-use crate::Effect;
-use crate::Readable;
 use crate::Writable;
+use crate::{ReactiveContext, Readable};
 
 /// Run a closure with the given owner.
 pub fn with_owner<S: AnyStorage, F: FnOnce() -> R, R>(owner: Owner<S>, f: F) -> R {
@@ -85,20 +84,15 @@ fn current_owner<S: Storage<T>, T>() -> Owner<S> {
         return owner;
     }
 
-    match Effect::current() {
-        // If we are inside of an effect, we should use the owner of the effect as the owner of the value.
-        Some(effect) => {
-            let scope_id = effect.source;
-            owner_in_scope(scope_id)
-        }
-        // Otherwise either get an owner from the current scope or create a new one.
-        None => match has_context() {
-            Some(rt) => rt,
-            None => {
-                let owner = S::owner();
-                provide_context(owner)
-            }
-        },
+    // If we are inside of an effect, we should use the owner of the effect as the owner of the value.
+    if let Some(scope) = ReactiveContext::current() {
+        return owner_in_scope(scope.origin_scope());
+    }
+
+    // Otherwise either get an owner from the current scope or create a new one.
+    match has_context() {
+        Some(rt) => rt,
+        None => provide_context(S::owner()),
     }
 }
 
@@ -206,15 +200,6 @@ impl<T: 'static, S: Storage<T>> CopyValue<T, S> {
             .expect("value is already dropped or borrowed")
     }
 
-    pub(crate) fn invalid() -> Self {
-        let owner = current_owner();
-
-        Self {
-            value: owner.invalid(),
-            origin_scope: current_scope_id().expect("in a virtual dom"),
-        }
-    }
-
     /// Get the scope this value was created in.
     pub fn origin_scope(&self) -> ScopeId {
         self.origin_scope

+ 4 - 10
packages/signals/src/signal.rs

@@ -1,23 +1,17 @@
 use crate::{
-    get_effect_ref, read::Readable, write::Writable, CopyValue, Effect, EffectInner,
-    EffectStackRef, GlobalMemo, GlobalSignal, MappedSignal, ReactiveContext, ReadOnlySignal,
-    EFFECT_STACK,
+    read::Readable, write::Writable, CopyValue, GlobalMemo, GlobalSignal, MappedSignal,
+    ReactiveContext, ReadOnlySignal,
 };
 use dioxus_core::{
-    prelude::{
-        current_scope_id, flush_sync, has_context, provide_context, schedule_update_any, spawn,
-        IntoAttributeValue,
-    },
+    prelude::{flush_sync, spawn, IntoAttributeValue},
     ScopeId,
 };
-use generational_box::{AnyStorage, GenerationalBoxId, Storage, SyncStorage, UnsyncStorage};
+use generational_box::{AnyStorage, Storage, SyncStorage, UnsyncStorage};
 use parking_lot::RwLock;
 use std::{
     any::Any,
-    cell::RefCell,
     collections::HashSet,
     ops::{Deref, DerefMut},
-    rc::Rc,
     sync::Arc,
 };