From 86e3f4e6840edef37e4bb63a55b4441bce8a7c21 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Mon, 26 Jan 2026 16:58:44 +0100 Subject: [PATCH] Sync state (param passing) --- examples/hello_world.rs | 20 ++++++++++++-- src/macros.rs | 8 ++++++ src/state.rs | 60 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 75bd963..dc2ccc3 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -2,6 +2,8 @@ use std::sync::Arc; use osui::{prelude::*, rsx}; +pub struct Count(pub State); + fn main() { let console = Console::new(); console.run(app); @@ -9,7 +11,7 @@ fn main() { fn app(cx: &Arc) -> View { let count = use_state(0); - let mount = use_mount(); + let mount = use_mount_manual(); use_effect( { @@ -27,6 +29,18 @@ fn app(cx: &Arc) -> View { &[&mount], ); + // Pass the count to the children + use_effect( + { + let count = count.clone(); + let cx = cx.clone(); + move || { + cx.emit_event(&Count(count.clone())); + } + }, + &[&mount], + ); + rsx! { // Static scope my_component (ctx, view) { @@ -46,13 +60,15 @@ fn app(cx: &Arc) -> View { for %count (i in 0..count.get_dl()) { "{i}" @Point { x: 0, y: i }; } + + !mount mount } .view(cx.clone()) } fn my_component(cx: &Arc) -> View { - let count = use_state(0); let mount = use_mount(); + let count = use_sync_state(cx, 0, |Count(v)| v.get_dl()); use_effect( { diff --git a/src/macros.rs b/src/macros.rs index c5ca97f..23c3e7a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -106,6 +106,14 @@ macro_rules! rsx_scope { $crate::rsx_scope!($rsx, $($rest)*); }; + ($rsx:expr, !mount $mount:ident $($rest:tt)*) => { + { + $mount.mount(); + } + + $crate::rsx_scope!($rsx, $($rest)*); + }; + ($rsx:expr,) => {}; } diff --git a/src/state.rs b/src/state.rs index d4c083b..c8f2193 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,13 +1,16 @@ use std::{ + any::Any, fmt::{Debug, Display, Formatter, Result as FmtResult}, ops::{Deref, DerefMut}, sync::{Arc, Mutex, MutexGuard}, }; +use crate::prelude::Context; + #[derive(Clone)] pub struct HookEffect(Arc>); -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct State { value: Arc>, dependents: Arc>>, @@ -19,8 +22,8 @@ pub struct Inner<'a, T> { updated: bool, } -#[derive(Debug, Clone, Copy)] -pub struct Mount; +#[derive(Debug, Clone)] +pub struct Mount(Arc>, Arc>>); pub fn use_state(v: T) -> State { State { @@ -57,6 +60,13 @@ impl State { d.call(); } } + + pub fn clone(&self) -> Self { + Self { + dependents: self.dependents.clone(), + value: self.value.clone(), + } + } } impl Display for State { @@ -117,7 +127,21 @@ impl HookDependency for State { impl HookDependency for Mount { fn on_update(&self, hook: HookEffect) { - hook.call(); + if *self.0.lock().unwrap() { + hook.call(); + } else { + self.1.lock().unwrap().push(hook); + } + } +} + +impl Mount { + pub fn mount(&self) { + *self.0.lock().unwrap() = true; + for hook_effect in self.1.lock().unwrap().iter() { + hook_effect.call(); + } + self.1.lock().unwrap().clear(); } } @@ -137,5 +161,31 @@ pub fn use_effect(f: F, dependencies: &[&dyn } pub fn use_mount() -> Mount { - Mount + Mount(Arc::new(Mutex::new(true)), Arc::new(Mutex::new(Vec::new()))) +} + +pub fn use_mount_manual() -> Mount { + Mount( + Arc::new(Mutex::new(false)), + Arc::new(Mutex::new(Vec::new())), + ) +} + +pub fn use_sync_state< + T: Send + Sync + 'static, + E: Any + 'static, + D: Fn(&E) -> T + Send + Sync + 'static, +>( + cx: &Arc, + v: T, + decoder: D, +) -> State { + let state = use_state(v); + + cx.on_event({ + let state = state.clone(); + move |_, v: &E| state.set(decoder(v)) + }); + + state }