Răsfoiți Sursa

Merge pull request #1546 from DioxusLabs/jk/loop-allocation-strategy

Change the semantics of exprs/for loops allocations strategy
Jonathan Kelley 1 an în urmă
părinte
comite
c7963a0344
4 a modificat fișierele cu 52 adăugiri și 10 ștergeri
  1. 23 1
      examples/signals.rs
  2. 3 3
      packages/core/src/lib.rs
  3. 19 6
      packages/rsx/src/node.rs
  4. 7 0
      packages/signals/src/signal.rs

+ 23 - 1
examples/signals.rs

@@ -6,11 +6,17 @@ fn main() {
 }
 
 fn app(cx: Scope) -> Element {
+    let running = dioxus_signals::use_signal(cx, || true);
     let mut count = dioxus_signals::use_signal(cx, || 0);
+    let saved_values = dioxus_signals::use_signal(cx, || vec![0.to_string()]);
 
+    // Signals can be used in async functions without an explicit clone since they're 'static and Copy
+    // Signals are backed by a runtime that is designed to deeply integrate with Dioxus apps
     use_future!(cx, || async move {
         loop {
-            count += 1;
+            if running.value() {
+                count += 1;
+            }
             tokio::time::sleep(Duration::from_millis(400)).await;
         }
     });
@@ -19,9 +25,25 @@ fn app(cx: Scope) -> Element {
         h1 { "High-Five counter: {count}" }
         button { onclick: move |_| count += 1, "Up high!" }
         button { onclick: move |_| count -= 1, "Down low!" }
+        button { onclick: move |_| running.toggle(), "Toggle counter" }
+        button { onclick: move |_| saved_values.push(count.value().to_string()), "Save this value" }
+        button { onclick: move |_| saved_values.write().clear(), "Clear saved values" }
 
+        // We can do boolean operations on the current signal value
         if count.value() > 5 {
             rsx!{ h2 { "High five!" } }
         }
+
+        // We can cleanly map signals with iterators
+        for value in saved_values.read().iter() {
+            h3 { "Saved value: {value}" }
+        }
+
+        // We can also use the signal value as a slice
+        if let [ref first, .., ref last] = saved_values.read().as_slice() {
+            rsx! { li { "First and last: {first}, {last}" } }
+        } else {
+            rsx! { "No saved values" }
+        }
     })
 }

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

@@ -91,9 +91,9 @@ pub mod prelude {
         consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, has_context,
         provide_context, provide_context_to_scope, provide_root_context, push_future,
         remove_future, schedule_update_any, spawn, spawn_forever, suspend, throw, AnyValue,
-        Component, Element, Event, EventHandler, Fragment, IntoAttributeValue, LazyNodes,
-        Properties, Runtime, RuntimeGuard, Scope, ScopeId, ScopeState, Scoped, TaskId, Template,
-        TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
+        Component, Element, Event, EventHandler, Fragment, IntoAttributeValue, IntoDynNode,
+        LazyNodes, Properties, Runtime, RuntimeGuard, Scope, ScopeId, ScopeState, Scoped, TaskId,
+        Template, TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
     };
 }
 

+ 19 - 6
packages/rsx/src/node.rs

@@ -125,7 +125,10 @@ impl ToTokens for BodyNode {
                 __cx.text_node(#txt)
             }),
             BodyNode::RawExpr(exp) => tokens.append_all(quote! {
-                 __cx.make_node(#exp)
+                {
+                    let ___nodes = (#exp).into_vnode(__cx);
+                    ___nodes
+                }
             }),
             BodyNode::ForLoop(exp) => {
                 let ForLoop {
@@ -137,16 +140,23 @@ impl ToTokens for BodyNode {
                     location: None,
                 };
 
+                // Signals expose an issue with temporary lifetimes
+                // We need to directly render out the nodes first to collapse their lifetime to <'a>
+                // And then we can return them into the dyn loop
                 tokens.append_all(quote! {
-                     __cx.make_node(
-                        (#expr).into_iter().map(|#pat| { #renderer })
-                     )
+                    {
+                        let ___nodes =(#expr).into_iter().map(|#pat| { #renderer }).into_vnode(__cx);
+                        ___nodes
+                    }
                 })
             }
             BodyNode::IfChain(chain) => {
                 if is_if_chain_terminated(chain) {
                     tokens.append_all(quote! {
-                         __cx.make_node(#chain)
+                        {
+                            let ___nodes = (#chain).into_vnode(__cx);
+                            ___nodes
+                        }
                     });
                 } else {
                     let ExprIf {
@@ -200,7 +210,10 @@ impl ToTokens for BodyNode {
                     });
 
                     tokens.append_all(quote! {
-                        __cx.make_node(#body)
+                        {
+                            let ___nodes = (#body).into_vnode(__cx);
+                            ___nodes
+                        }
                     });
                 }
             }

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

@@ -264,6 +264,13 @@ impl<T: Clone + 'static> Signal<T> {
     }
 }
 
+impl Signal<bool> {
+    /// Invert the boolean value of the signal. This will trigger an update on all subscribers.
+    pub fn toggle(&self) {
+        self.set(!self.value());
+    }
+}
+
 impl<T: 'static> PartialEq for Signal<T> {
     fn eq(&self, other: &Self) -> bool {
         self.inner == other.inner