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

Change the semantics of exprs/for loops allocations strategy
This commit is contained in:
Jonathan Kelley 2023-10-17 16:30:20 -07:00 committed by GitHub
commit c7963a0344
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 10 deletions

View file

@ -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" }
}
})
}

View file

@ -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,
};
}

View file

@ -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
}
});
}
}

View file

@ -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