Browse Source

hello world example working

Evan Almloff 1 year ago
parent
commit
4013341b6c

+ 0 - 1
packages/core-macro/Cargo.toml

@@ -17,7 +17,6 @@ proc-macro2 = { version = "1.0" }
 quote = "1.0"
 syn = { version = "2.0", features = ["full", "extra-traits"] }
 dioxus-rsx = { workspace = true }
-dioxus-core = { workspace = true }
 constcat = "0.3.0"
 prettyplease = "0.2.15"
 

+ 1 - 34
packages/core-macro/src/component_body/mod.rs

@@ -147,9 +147,7 @@ pub mod utils;
 
 pub use utils::DeserializerArgs;
 pub use utils::DeserializerOutput;
-pub use utils::TypeHelper;
 
-use dioxus_core::{Element, Scope};
 use syn::parse::{Parse, ParseStream};
 use syn::spanned::Spanned;
 use syn::*;
@@ -167,12 +165,6 @@ pub struct ComponentBody {
     /// Keep this in mind when creating deserializers, because you often might want to ignore it.
     /// That might be annoying, but it would be bad design for this kind of struct to not be parsable from itself.
     pub item_fn: ItemFn,
-    /// Parsing tries to ensure that this argument will be a [`Scope`].
-    /// **However, macros have limitations that prevent this from always working,
-    /// so don't take this for granted!**
-    pub cx_arg: FnArg,
-    /// The pattern (name) and type of the context argument.
-    pub cx_pat_type: PatType,
     /// If the function has any arguments other than the context.
     pub has_extra_args: bool,
 }
@@ -192,31 +184,8 @@ impl ComponentBody {
 impl Parse for ComponentBody {
     fn parse(input: ParseStream) -> Result<Self> {
         let item_fn: ItemFn = input.parse()?;
-        let scope_type_path = Scope::get_path_string();
 
-        let (cx_arg, cx_pat_type) = if let Some(first_arg) = item_fn.sig.inputs.first() {
-            let incorrect_first_arg_err = Err(Error::new(
-                first_arg.span(),
-                format!("First argument must be a <{}>", scope_type_path),
-            ));
-
-            match first_arg.to_owned() {
-                FnArg::Receiver(_) => {
-                    return incorrect_first_arg_err;
-                }
-                FnArg::Typed(f) => (first_arg.to_owned(), f),
-            }
-        } else {
-            return Err(Error::new(
-                item_fn.sig.ident.span(), // Or maybe just item_f.sig.span()?
-                format!(
-                    "Must have at least one argument that's a <{}>",
-                    scope_type_path
-                ),
-            ));
-        };
-
-        let element_type_path = Element::get_path_string();
+        let element_type_path = "::dioxus::core::Element";
 
         if item_fn.sig.output == ReturnType::Default {
             return Err(Error::new(
@@ -229,8 +198,6 @@ impl Parse for ComponentBody {
 
         Ok(Self {
             item_fn,
-            cx_arg,
-            cx_pat_type,
             has_extra_args,
         })
     }

+ 0 - 20
packages/core-macro/src/component_body/utils.rs

@@ -1,5 +1,4 @@
 use crate::component_body::ComponentBody;
-use dioxus_core::{Element, Scope};
 use quote::ToTokens;
 use syn::{parse_quote, Path};
 
@@ -36,22 +35,3 @@ where
     #[allow(unused_qualifications)]
     fn to_output(&self, component_body: &ComponentBody) -> syn::Result<TOutput>;
 }
-
-pub trait TypeHelper {
-    fn get_path() -> Path;
-    fn get_path_string() -> String {
-        Self::get_path().to_token_stream().to_string()
-    }
-}
-
-impl<'a> TypeHelper for Scope<'a> {
-    fn get_path() -> Path {
-        parse_quote!(::dioxus::core::Scope)
-    }
-}
-
-impl<'a> TypeHelper for Element<'a> {
-    fn get_path() -> Path {
-        parse_quote!(::dioxus::core::Element)
-    }
-}

+ 6 - 16
packages/core-macro/src/component_body_deserializers/component.rs

@@ -16,7 +16,7 @@ To ignore this check, pass the \"",
 
 const INNER_FN_NAME: &str = "__dx_inner_comp";
 
-fn get_out_comp_fn(orig_comp_fn: &ItemFn, cx_pat: &Pat) -> ItemFn {
+fn get_out_comp_fn(orig_comp_fn: &ItemFn) -> ItemFn {
     let inner_comp_ident = Ident::new(INNER_FN_NAME, orig_comp_fn.sig.ident.span());
 
     let inner_comp_fn = ItemFn {
@@ -34,7 +34,7 @@ fn get_out_comp_fn(orig_comp_fn: &ItemFn, cx_pat: &Pat) -> ItemFn {
                 #[allow(clippy::inline_always)]
                 #[inline(always)]
                 #inner_comp_fn
-                #inner_comp_ident (#cx_pat)
+                #inner_comp_ident(__props)
             }
         },
         ..orig_comp_fn.clone()
@@ -88,14 +88,9 @@ impl DeserializerArgs<ComponentDeserializerOutput> for ComponentDeserializerArgs
 
 impl ComponentDeserializerArgs {
     fn deserialize_no_props(component_body: &ComponentBody) -> ComponentDeserializerOutput {
-        let ComponentBody {
-            item_fn,
-            cx_pat_type,
-            ..
-        } = component_body;
-        let cx_pat = &cx_pat_type.pat;
+        let ComponentBody { item_fn, .. } = component_body;
 
-        let comp_fn = get_out_comp_fn(item_fn, cx_pat);
+        let comp_fn = get_out_comp_fn(item_fn);
 
         ComponentDeserializerOutput {
             comp_fn,
@@ -106,12 +101,7 @@ impl ComponentDeserializerArgs {
     fn deserialize_with_props(
         component_body: &ComponentBody,
     ) -> Result<ComponentDeserializerOutput> {
-        let ComponentBody {
-            item_fn,
-            cx_pat_type,
-            ..
-        } = component_body;
-        let cx_pat = &cx_pat_type.pat;
+        let ComponentBody { item_fn, .. } = component_body;
 
         let comp_parsed = match parse2::<ComponentBody>(quote!(#item_fn)) {
             Ok(comp_body) => comp_body,
@@ -130,7 +120,7 @@ impl ComponentDeserializerArgs {
         let props_struct = inlined_props_output.props_struct;
         let props_fn = inlined_props_output.comp_fn;
 
-        let comp_fn = get_out_comp_fn(&props_fn, cx_pat);
+        let comp_fn = get_out_comp_fn(&props_fn);
 
         Ok(ComponentDeserializerOutput {
             comp_fn,

+ 3 - 8
packages/core-macro/src/component_body_deserializers/inline_props.rs

@@ -225,11 +225,7 @@ fn get_props_docs(fn_ident: &Ident, inputs: Vec<&FnArg>) -> Vec<Attribute> {
 }
 
 fn get_function(component_body: &ComponentBody) -> ItemFn {
-    let ComponentBody {
-        item_fn,
-        cx_pat_type,
-        ..
-    } = component_body;
+    let ComponentBody { item_fn, .. } = component_body;
     let ItemFn {
         attrs: fn_attrs,
         vis,
@@ -246,7 +242,6 @@ fn get_function(component_body: &ComponentBody) -> ItemFn {
     } = sig;
     let Generics { where_clause, .. } = generics;
 
-    let cx_pat = &cx_pat_type.pat;
     let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span());
 
     // Skip first arg since that's the context
@@ -298,10 +293,10 @@ fn get_function(component_body: &ComponentBody) -> ItemFn {
     parse_quote! {
         #(#fn_attrs)*
         #(#props_docs)*
-        #asyncness #vis fn #fn_ident #fn_generics (#cx_pat: Scope<#scope_lifetime #struct_ident #generics_no_bounds>) #fn_output
+        #asyncness #vis fn #fn_ident #fn_generics (__props: #struct_ident #generics_no_bounds) #fn_output
         #where_clause
         {
-            let #struct_ident { #(#struct_field_names),* } = &#cx_pat.props;
+            let #struct_ident { #(#struct_field_names),* } = &__props;
             #fn_block
         }
     }

+ 1 - 1
packages/core/src/create.rs

@@ -155,7 +155,7 @@ impl VirtualDom {
                 }
                 Element { .. } => {
                     #[cfg(not(debug_assertions))]
-                    let id = self.write_element_root(node, idx, &mut attrs, &mut nodes, &[]);
+                    let id = self.write_element_root(node, idx, &mut attrs, &mut nodes, &[], to);
                     #[cfg(debug_assertions)]
                     let id = self.write_element_root(
                         node,

+ 15 - 10
packages/core/src/error_boundary.rs

@@ -37,11 +37,22 @@ impl Debug for ErrorBoundaryInner {
     }
 }
 
+/// A trait for any type that can be downcast to a concrete type and implements Debug. This is automatically implemented for all types that implement Any + Debug.
+pub trait AnyDebug: Any + Debug {
+    fn as_any(&self) -> &dyn Any;
+}
+
+impl<T: Any + Debug> AnyDebug for T {
+    fn as_any(&self) -> &dyn Any {
+        self
+    }
+}
+
 #[derive(Debug)]
 /// An instance of an error captured by a descendant component.
 pub struct CapturedError {
     /// The error captured by the error boundary
-    pub error: Box<dyn Debug + 'static>,
+    pub error: Box<dyn AnyDebug + 'static>,
 
     /// The backtrace of the error
     pub backtrace: Backtrace,
@@ -65,8 +76,7 @@ impl CapturedError {
     /// Downcast the error type into a concrete error type
     pub fn downcast<T: 'static>(&self) -> Option<&T> {
         if TypeId::of::<T>() == self.error.type_id() {
-            let raw = self.error.as_ref() as *const _ as *const T;
-            Some(unsafe { &*raw })
+            self.error.as_any().downcast_ref::<T>()
         } else {
             None
         }
@@ -100,14 +110,9 @@ impl ErrorBoundary {
     }
 
     /// Push an error into this Error Boundary
-    pub fn insert_error(
-        &self,
-        scope: ScopeId,
-        error: Box<dyn Debug + 'static>,
-        backtrace: Backtrace,
-    ) {
+    pub fn insert_error(&self, scope: ScopeId, error: impl Debug + 'static, backtrace: Backtrace) {
         self.inner.error.replace(Some(CapturedError {
-            error,
+            error: Box::new(error),
             scope,
             backtrace,
         }));

+ 20 - 0
packages/core/src/global_context.rs

@@ -1,3 +1,5 @@
+use std::sync::Arc;
+
 use futures_util::Future;
 
 use crate::{
@@ -113,3 +115,21 @@ pub fn parent_scope() -> Option<ScopeId> {
 pub fn needs_update() {
     with_current_scope(|cx| cx.needs_update());
 }
+
+/// Schedule an update for the current component
+///
+/// Note: Unlike [`needs_update`], the function returned by this method will work outside of the dioxus runtime.
+///
+/// You should prefer [`schedule_update_any`] if you need to update multiple components.
+pub fn schedule_update() -> Arc<dyn Fn() + Send + Sync> {
+    with_current_scope(|cx| cx.schedule_update()).expect("to be in a dioxus runtime")
+}
+
+/// Schedule an update for any component given its [`ScopeId`].
+///
+/// A component's [`ScopeId`] can be obtained from the [`current_scope_id`] method.
+///
+/// Note: Unlike [`needs_update`], the function returned by this method will work outside of the dioxus runtime.
+pub fn schedule_update_any() -> Arc<dyn Fn(ScopeId) + Send + Sync> {
+    with_current_scope(|cx| cx.schedule_update_any()).expect("to be in a dioxus runtime")
+}

+ 9 - 8
packages/core/src/lib.rs

@@ -74,10 +74,11 @@ pub(crate) mod innerlude {
 }
 
 pub use crate::innerlude::{
-    fc_to_builder, generation, once, vdom_is_rendering, AnyValue, Attribute, AttributeValue,
-    CapturedError, Component, DynamicNode, Element, ElementId, Event, Fragment, IntoDynNode,
-    Mutation, MutationsVec, Properties, RenderReturn, ScopeId, Task, Template, TemplateAttribute,
-    TemplateNode, VComponent, VNode, VPlaceholder, VText, VirtualDom, WriteMutations,
+    fc_to_builder, generation, once, schedule_update, schedule_update_any, vdom_is_rendering,
+    AnyValue, Attribute, AttributeValue, CapturedError, Component, DynamicNode, Element, ElementId,
+    Event, Fragment, IntoDynNode, Mutation, MutationsVec, Properties, RenderReturn, ScopeId, Task,
+    Template, TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText, VirtualDom,
+    WriteMutations,
 };
 
 /// The purpose of this module is to alleviate imports of many common types
@@ -87,9 +88,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, once, parent_scope, provide_context, provide_root_context,
-        push_future, remove_future, spawn, spawn_forever, suspend, use_error_boundary, AnyValue,
-        Component, Element, ErrorBoundary, Event, EventHandler, Fragment, IntoAttributeValue,
-        IntoDynNode, Properties, Runtime, RuntimeGuard, ScopeId, Task, Template, TemplateAttribute,
-        TemplateNode, Throw, VNode, VirtualDom,
+        push_future, remove_future, schedule_update, schedule_update_any, spawn, spawn_forever,
+        suspend, use_error_boundary, AnyValue, Component, Element, ErrorBoundary, Event,
+        EventHandler, Fragment, IntoAttributeValue, IntoDynNode, Properties, Runtime, RuntimeGuard,
+        ScopeId, Task, Template, TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
     };
 }

+ 28 - 0
packages/core/src/scope_context.rs

@@ -9,6 +9,7 @@ use std::{
     cell::{Cell, RefCell},
     future::Future,
     rc::Rc,
+    sync::Arc,
 };
 
 /// A component's state separate from its props.
@@ -69,6 +70,26 @@ impl ScopeContext {
             .expect("Scheduler to exist if scope exists");
     }
 
+    /// Create a subscription that schedules a future render for the reference component
+    ///
+    /// ## Notice: you should prefer using [`Self::schedule_update_any`] and [`Self::scope_id`]
+    pub fn schedule_update(&self) -> Arc<dyn Fn() + Send + Sync + 'static> {
+        let (chan, id) = (self.tasks.sender.clone(), self.id);
+        Arc::new(move || drop(chan.unbounded_send(SchedulerMsg::Immediate(id))))
+    }
+
+    /// Schedule an update for any component given its [`ScopeId`].
+    ///
+    /// A component's [`ScopeId`] can be obtained from `use_hook` or the [`ScopeState::scope_id`] method.
+    ///
+    /// This method should be used when you want to schedule an update for a component
+    pub fn schedule_update_any(&self) -> Arc<dyn Fn(ScopeId) + Send + Sync> {
+        let chan = self.tasks.sender.clone();
+        Arc::new(move |id| {
+            chan.unbounded_send(SchedulerMsg::Immediate(id)).unwrap();
+        })
+    }
+
     /// Return any context of type T if it exists on this scope
     pub fn has_context<T: 'static + Clone>(&self) -> Option<T> {
         self.shared_contexts
@@ -355,4 +376,11 @@ impl ScopeId {
     pub fn needs_update(self) {
         with_scope(self, |cx| cx.needs_update());
     }
+
+    /// Create a subscription that schedules a future render for the reference component. Unlike [`Self::needs_update`], this function will work outside of the dioxus runtime.
+    ///
+    /// ## Notice: you should prefer using [`dioxus_core::schedule_update_any`] and [`Self::scope_id`]
+    pub fn schedule_update(&self) -> Arc<dyn Fn() + Send + Sync + 'static> {
+        with_scope(*self, |cx| cx.schedule_update()).expect("to be in a dioxus runtime")
+    }
 }

+ 3 - 1
packages/core/src/virtual_dom.rs

@@ -549,7 +549,9 @@ impl VirtualDom {
     pub fn rebuild(&mut self, to: &mut impl WriteMutations) {
         self.flush_templates(to);
         let _runtime = RuntimeGuard::new(self.runtime.clone());
-        match self.run_scope(ScopeId::ROOT) {
+        let new_nodes = self.run_scope(ScopeId::ROOT);
+        self.scopes[ScopeId::ROOT.0].last_rendered_node = Some(new_nodes.clone());
+        match new_nodes {
             // Rebuilding implies we append the created elements to the root
             RenderReturn::Ready(node) => {
                 let m = self.create_scope(ScopeId::ROOT, &node, to);

+ 7 - 6
packages/desktop/src/eval.rs

@@ -2,6 +2,7 @@
 use async_trait::async_trait;
 use dioxus_core::prelude::consume_context;
 use dioxus_core::prelude::provide_context;
+use dioxus_core::ScopeId;
 use dioxus_html::prelude::{EvalError, EvalProvider, Evaluator};
 use std::{cell::RefCell, rc::Rc};
 
@@ -9,13 +10,13 @@ use crate::{query::Query, DesktopContext};
 
 /// Provides the DesktopEvalProvider through [`cx.provide_context`].
 pub fn init_eval() {
-    let desktop_ctx = consume_context::<DesktopContext>().unwrap();
+    let desktop_ctx = ScopeId::ROOT.consume_context::<DesktopContext>().unwrap();
     let provider: Rc<dyn EvalProvider> = Rc::new(DesktopEvalProvider { desktop_ctx });
-    provide_context(provider);
+    ScopeId::ROOT.provide_context(provider);
 }
 
-/// Reprents the desktop-target's provider of evaluators.
-pub struct DesktopEvalProvider {
+/// Represents the desktop-target's provider of evaluators.
+pub(crate) struct DesktopEvalProvider {
     desktop_ctx: DesktopContext,
 }
 
@@ -25,8 +26,8 @@ impl EvalProvider for DesktopEvalProvider {
     }
 }
 
-/// Reprents a desktop-target's JavaScript evaluator.
-pub struct DesktopEvaluator {
+/// Represents a desktop-target's JavaScript evaluator.
+pub(crate) struct DesktopEvaluator {
     query: Rc<RefCell<Query<serde_json::Value>>>,
 }
 

+ 27 - 27
packages/hooks/src/lib.rs

@@ -55,42 +55,42 @@ macro_rules! to_owned {
     };
 }
 
-pub mod computed;
+// pub mod computed;
 
-mod use_on_destroy;
-pub use use_on_destroy::*;
+// mod use_on_destroy;
+// pub use use_on_destroy::*;
 
-mod use_const;
-pub use use_const::*;
+// mod use_const;
+// pub use use_const::*;
 
-mod use_context;
-pub use use_context::*;
+// mod use_context;
+// pub use use_context::*;
 
-mod use_state;
-pub use use_state::{use_state, UseState};
+// mod use_state;
+// pub use use_state::{use_state, UseState};
 
-mod use_ref;
-pub use use_ref::*;
+// mod use_ref;
+// pub use use_ref::*;
 
-mod use_shared_state;
-pub use use_shared_state::*;
+// mod use_shared_state;
+// pub use use_shared_state::*;
 
-mod use_coroutine;
-pub use use_coroutine::*;
+// mod use_coroutine;
+// pub use use_coroutine::*;
 
-mod use_future;
-pub use use_future::*;
+// mod use_future;
+// pub use use_future::*;
 
-mod use_effect;
-pub use use_effect::*;
+// mod use_effect;
+// pub use use_effect::*;
 
-mod use_callback;
-pub use use_callback::*;
+// mod use_callback;
+// pub use use_callback::*;
 
-mod use_memo;
-pub use use_memo::*;
+// mod use_memo;
+// pub use use_memo::*;
 
-mod use_on_create;
-pub use use_on_create::*;
-mod use_root_context;
-pub use use_root_context::*;
+// mod use_on_create;
+// pub use use_on_create::*;
+// mod use_root_context;
+// pub use use_root_context::*;

+ 2 - 2
packages/rsx/src/attribute.rs

@@ -68,7 +68,7 @@ impl ToTokens for ElementAttrNamed {
                     let value = &self.attr.value;
                     let value = quote! { #value };
                     quote! {
-                        __cx.attr(
+                        ::dioxus::core::Attribute::new(
                             #attribute,
                             #value,
                             #ns,
@@ -79,7 +79,7 @@ impl ToTokens for ElementAttrNamed {
                 ElementAttrValue::EventTokens(tokens) => match &self.attr.name {
                     ElementAttrName::BuiltIn(name) => {
                         quote! {
-                            dioxus_elements::events::#name(__cx, #tokens)
+                            dioxus_elements::events::#name(#tokens)
                         }
                     }
                     ElementAttrName::Custom(_) => todo!(),

+ 4 - 4
packages/rsx/src/component.rs

@@ -189,11 +189,11 @@ impl ToTokens for Component {
         };
 
         tokens.append_all(quote! {
-            __cx.component(
+            ::dioxus::core::DynamicNode::Component(::dioxus::core::VComponent::new(
                 #gen_name,
                 #builder,
                 #fn_name
-            )
+            ))
         })
     }
 }
@@ -217,10 +217,10 @@ impl ToTokens for ContentField {
         match self {
             ContentField::ManExpr(e) => e.to_tokens(tokens),
             ContentField::Formatted(s) => tokens.append_all(quote! {
-                __cx.raw_text(#s)
+                #s.to_string()
             }),
             ContentField::OnHandlerRaw(e) => tokens.append_all(quote! {
-                __cx.event_handler(#e)
+                ::dioxus::core::Attribute::EventHandler(EventHandler::new(#e))
             }),
         }
     }

+ 4 - 4
packages/rsx/src/element.rs

@@ -184,11 +184,11 @@ impl ToTokens for Element {
             .filter(|f| !matches!(f.attr.value, ElementAttrValue::EventTokens { .. }));
 
         tokens.append_all(quote! {
-            __cx.element(
+            ::dioxus::core::Element::new(
                 #name,
-                __cx.bump().alloc([ #(#listeners),* ]),
-                __cx.bump().alloc([ #(#attr),* ]),
-                __cx.bump().alloc([ #(#children),* ]),
+                vec![ #(#listeners),* ],
+                vec![ #(#attr),* ],
+                vec![ #(#children),* ],
                 #key,
             )
         });

+ 7 - 8
packages/rsx/src/lib.rs

@@ -69,7 +69,7 @@ impl CallBody {
         &self,
         template: Option<CallBody>,
         location: &'static str,
-    ) -> Option<Template<'static>> {
+    ) -> Option<Template> {
         let mut renderer: TemplateRenderer = TemplateRenderer {
             roots: &self.roots,
             location: None,
@@ -138,7 +138,6 @@ impl ToTokens for RenderCallBody {
 
         out_tokens.append_all(quote! {
             Some({
-                let __cx = cx;
                 #body
             })
         })
@@ -156,7 +155,7 @@ impl<'a> TemplateRenderer<'a> {
         &mut self,
         previous_call: Option<CallBody>,
         location: &'static str,
-    ) -> Option<Template<'static>> {
+    ) -> Option<Template> {
         let mut mapping = previous_call.map(|call| DynamicMapping::from(call.roots));
 
         let mut context = DynamicContext::default();
@@ -202,7 +201,7 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
         };
 
         let key_tokens = match key {
-            Some(tok) => quote! { Some( __cx.raw_text(#tok) ) },
+            Some(tok) => quote! { Some( #tok.to_string() ) },
             None => quote! { None },
         };
 
@@ -257,9 +256,9 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
             ::dioxus::core::VNode::new(
                 #key_tokens,
                 TEMPLATE,
-                dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(#root_count, __cx.bump()),
-                __cx.bump().alloc([ #( #node_printer ),* ]),
-                __cx.bump().alloc([ #( #dyn_attr_printer ),* ]),
+                Vec::with_capacity(#root_count),
+                vec![ #( #node_printer ),* ],
+                vec![ #( #dyn_attr_printer ),* ],
             )
         });
     }
@@ -360,7 +359,7 @@ impl<'a> DynamicContext<'a> {
         &mut self,
         root: &'a BodyNode,
         mapping: &mut Option<DynamicMapping>,
-    ) -> Option<TemplateNode<'static>> {
+    ) -> Option<TemplateNode> {
         match root {
             BodyNode::Element(el) => {
                 let element_name_rust = el.name.to_string();

+ 5 - 5
packages/rsx/src/node.rs

@@ -122,11 +122,11 @@ impl ToTokens for BodyNode {
             BodyNode::Element(el) => el.to_tokens(tokens),
             BodyNode::Component(comp) => comp.to_tokens(tokens),
             BodyNode::Text(txt) => tokens.append_all(quote! {
-                __cx.text_node(#txt)
+                ::dioxus::core::DynamicNode::Text(::dioxus::core::VText::new(#txt.to_string()))
             }),
             BodyNode::RawExpr(exp) => tokens.append_all(quote! {
                 {
-                    let ___nodes = (#exp).into_dyn_node(__cx);
+                    let ___nodes = (#exp).into_dyn_node();
                     ___nodes
                 }
             }),
@@ -145,7 +145,7 @@ impl ToTokens for BodyNode {
                 // And then we can return them into the dyn loop
                 tokens.append_all(quote! {
                     {
-                        let ___nodes =(#expr).into_iter().map(|#pat| { #renderer }).into_dyn_node(__cx);
+                        let ___nodes = (#expr).into_iter().map(|#pat| { #renderer }).into_dyn_node();
                         ___nodes
                     }
                 })
@@ -154,7 +154,7 @@ impl ToTokens for BodyNode {
                 if is_if_chain_terminated(chain) {
                     tokens.append_all(quote! {
                         {
-                            let ___nodes = (#chain).into_dyn_node(__cx);
+                            let ___nodes = (#chain).into_dyn_node();
                             ___nodes
                         }
                     });
@@ -211,7 +211,7 @@ impl ToTokens for BodyNode {
 
                     tokens.append_all(quote! {
                         {
-                            let ___nodes = (#body).into_dyn_node(__cx);
+                            let ___nodes = (#body).into_dyn_node();
                             ___nodes
                         }
                     });

+ 4 - 5
packages/signals/src/effect.rs

@@ -38,21 +38,20 @@ pub(crate) fn get_effect_stack() -> EffectStack {
 
 /// 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(cx: &ScopeState, callback: impl FnMut() + 'static) {
-    cx.use_hook(|| Effect::new(callback));
+pub fn use_effect(callback: impl FnMut() + 'static) {
+    once(|| 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>(
-    cx: &ScopeState,
     dependencies: D,
     mut callback: impl FnMut(D::Out) + 'static,
 ) where
     D::Out: 'static,
 {
-    let dependencies_signal = use_signal(cx, || dependencies.out());
-    cx.use_hook(|| {
+    let dependencies_signal = use_signal(|| dependencies.out());
+    once(|| {
         Effect::new(move || {
             let deref = &*dependencies_signal.read();
             callback(deref.clone());

+ 1 - 1
packages/signals/src/rt.rs

@@ -44,7 +44,7 @@ fn owner_in_scope(scope: ScopeId) -> Rc<Owner> {
         Some(rt) => rt,
         None => {
             let owner = Rc::new(current_store().owner());
-            provide_context_to_scope(scope, owner).expect("in a virtual dom")
+            scope.provide_context(owner).expect("in a virtual dom")
         }
     }
 }

+ 5 - 9
packages/signals/src/selector.rs

@@ -22,11 +22,8 @@ use crate::{get_effect_stack, signal::SignalData, CopyValue, Effect, ReadOnlySig
 /// }
 /// ```
 #[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"]
-pub fn use_selector<R: PartialEq>(
-    cx: &ScopeState,
-    f: impl FnMut() -> R + 'static,
-) -> ReadOnlySignal<R> {
-    *cx.use_hook(|| selector(f))
+pub fn use_selector<R: PartialEq>(f: impl FnMut() -> R + 'static) -> ReadOnlySignal<R> {
+    once(|| selector(f))
 }
 
 /// Creates a new Selector with some local dependencies. The selector will be run immediately and whenever any signal it reads or any dependencies it tracks changes
@@ -47,15 +44,14 @@ pub fn use_selector<R: PartialEq>(
 /// ```
 #[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"]
 pub fn use_selector_with_dependencies<R: PartialEq, D: Dependency>(
-    cx: &ScopeState,
     dependencies: D,
     mut f: impl FnMut(D::Out) -> R + 'static,
 ) -> ReadOnlySignal<R>
 where
     D::Out: 'static,
 {
-    let dependencies_signal = use_signal(cx, || dependencies.out());
-    let selector = *cx.use_hook(|| {
+    let dependencies_signal = use_signal(|| dependencies.out());
+    let selector = once(|| {
         selector(move || {
             let deref = &*dependencies_signal.read();
             f(deref.clone())
@@ -87,9 +83,9 @@ pub fn selector<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> ReadOnlySig
     state.inner.value.set(SignalData {
         subscribers: Default::default(),
         effect_subscribers: Default::default(),
-        update_any: schedule_update_any().expect("in a virtual dom"),
         value: f(),
         effect_stack: get_effect_stack(),
+        update_any: schedule_update_any(),
     });
     {
         get_effect_stack().effects.write().pop();

+ 7 - 6
packages/signals/src/signal.rs

@@ -7,8 +7,9 @@ use std::{
 };
 
 use dioxus_core::{
+    once,
     prelude::{current_scope_id, has_context, provide_context, schedule_update_any},
-    ScopeId, ScopeState,
+    ScopeId,
 };
 use generational_box::{GenerationalRef, GenerationalRefMut};
 
@@ -47,11 +48,11 @@ use crate::{get_effect_stack, CopyValue, Effect, EffectStack};
 /// ```
 #[track_caller]
 #[must_use]
-pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> {
+pub fn use_signal<T: 'static>(f: impl FnOnce() -> T) -> Signal<T> {
     #[cfg(debug_assertions)]
     let caller = std::panic::Location::caller();
 
-    *cx.use_hook(|| {
+    once(|| {
         Signal::new_with_caller(
             f(),
             #[cfg(debug_assertions)]
@@ -155,7 +156,7 @@ impl<T: 'static> Signal<T> {
             inner: CopyValue::new(SignalData {
                 subscribers: Default::default(),
                 effect_subscribers: Default::default(),
-                update_any: schedule_update_any().expect("in a virtual dom"),
+                update_any: schedule_update_any(),
                 value,
                 effect_stack: get_effect_stack(),
             }),
@@ -172,7 +173,7 @@ impl<T: 'static> Signal<T> {
                 SignalData {
                     subscribers: Default::default(),
                     effect_subscribers: Default::default(),
-                    update_any: schedule_update_any().expect("in a virtual dom"),
+                    update_any: schedule_update_any(),
                     value,
                     effect_stack: get_effect_stack(),
                 },
@@ -189,7 +190,7 @@ impl<T: 'static> Signal<T> {
                 SignalData {
                     subscribers: Default::default(),
                     effect_subscribers: Default::default(),
-                    update_any: schedule_update_any().expect("in a virtual dom"),
+                    update_any: schedule_update_any(),
                     value,
                     effect_stack: get_effect_stack(),
                 },