瀏覽代碼

Fix global signal owner

Jonathan Kelley 1 年之前
父節點
當前提交
60f5697e8e
共有 6 個文件被更改,包括 94 次插入101 次删除
  1. 33 51
      examples/all_events.rs
  2. 15 22
      examples/calculator.rs
  3. 1 1
      examples/compose.rs
  4. 20 18
      examples/crm.rs
  5. 15 7
      packages/signals/src/global.rs
  6. 10 2
      packages/signals/src/lib.rs

+ 33 - 51
examples/all_events.rs

@@ -1,78 +1,60 @@
+use std::{collections::VecDeque, fmt::Debug, rc::Rc};
+
 use dioxus::{events::*, html::MouseEvent, prelude::*};
 
 fn main() {
     launch(app);
 }
 
-#[derive(Debug)]
-enum Event {
-    MouseMove(MouseEvent),
-    MouseClick(MouseEvent),
-    MouseDoubleClick(MouseEvent),
-    MouseDown(MouseEvent),
-    MouseUp(MouseEvent),
-
-    Wheel(WheelEvent),
-
-    KeyDown(KeyboardEvent),
-    KeyUp(KeyboardEvent),
-    KeyPress(KeyboardEvent),
-
-    FocusIn(FocusEvent),
-    FocusOut(FocusEvent),
-}
-
 const MAX_EVENTS: usize = 8;
 
 const CONTAINER_STYLE: &str = r#"
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-    "#;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+"#;
 
 const RECT_STYLE: &str = r#"
-        background: deepskyblue;
-        height: 50vh;
-        width: 50vw;
-        color: white;
-        padding: 20px;
-        margin: 20px;
-        text-aligh: center;
-    "#;
+    background: deepskyblue;
+    height: 50vh;
+    width: 50vw;
+    color: white;
+    padding: 20px;
+    margin: 20px;
+    text-aligh: center;
+"#;
 
 fn app() -> Element {
-    let mut events = use_signal(std::collections::VecDeque::new);
+    let mut events = use_signal(|| std::collections::VecDeque::new() as VecDeque<Rc<dyn Debug>>);
 
-    let mut log_event = move |event: Event| {
+    let mut log_event = move |event: Rc<dyn Debug>| {
         let mut events = events.write();
 
         if events.len() >= MAX_EVENTS {
             events.pop_front();
         }
+
         events.push_back(event);
     };
 
     rsx! {
         div { style: "{CONTAINER_STYLE}",
-            div {
-                style: "{RECT_STYLE}",
-                // focusing is necessary to catch keyboard events
-                tabindex: "0",
-
-                onmousemove: move |event| log_event(Event::MouseMove(event)),
-                onclick: move |event| log_event(Event::MouseClick(event)),
-                ondoubleclick: move |event| log_event(Event::MouseDoubleClick(event)),
-                onmousedown: move |event| log_event(Event::MouseDown(event)),
-                onmouseup: move |event| log_event(Event::MouseUp(event)),
-
-                onwheel: move |event| log_event(Event::Wheel(event)),
-
-                onkeydown: move |event| log_event(Event::KeyDown(event)),
-                onkeyup: move |event| log_event(Event::KeyUp(event)),
-                onkeypress: move |event| log_event(Event::KeyPress(event)),
-
-                onfocusin: move |event| log_event(Event::FocusIn(event)),
-                onfocusout: move |event| log_event(Event::FocusOut(event)),
+            // focusing is necessary to catch keyboard events
+            div { style: "{RECT_STYLE}", tabindex: "0",
+                onmousemove: move |event| log_event(event.inner().clone()),
+                onclick: move |event| log_event(event.inner().clone()),
+                ondoubleclick: move |event| log_event(event.inner().clone()),
+                onmousedown: move |event| log_event(event.inner().clone()),
+                onmouseup: move |event| log_event(event.inner().clone()),
+
+                onwheel: move |event| log_event(event.inner().clone()),
+
+                onkeydown: move |event| log_event(event.inner().clone()),
+                onkeyup: move |event| log_event(event.inner().clone()),
+                onkeypress: move |event| log_event(event.inner().clone()),
+
+                onfocusin: move |event| log_event(event.inner().clone()),
+                onfocusout: move |event| log_event(event.inner().clone()),
 
                 "Hover, click, type or scroll to see the info down below"
             }

+ 15 - 22
examples/calculator.rs

@@ -9,24 +9,26 @@ use dioxus::prelude::*;
 use dioxus_desktop::{Config, LogicalSize, WindowBuilder};
 
 fn main() {
-    let config = Config::new().with_window(
-        WindowBuilder::default()
-            .with_title("Calculator")
-            .with_inner_size(LogicalSize::new(300.0, 525.0)),
-    );
-
-    LaunchBuilder::desktop().with_cfg(config).launch(app);
+    LaunchBuilder::desktop()
+        .with_cfg(
+            Config::new().with_window(
+                WindowBuilder::default()
+                    .with_title("Calculator")
+                    .with_inner_size(LogicalSize::new(300.0, 525.0)),
+            ),
+        )
+        .launch(app);
 }
 
 fn app() -> Element {
     let mut val = use_signal(|| String::from("0"));
 
-    let mut input_digit = move |num: u8| {
-        if val.cloned() == "0" {
+    let mut input_digit = move |num: String| {
+        if val() == "0" {
             val.set(String::new());
         }
 
-        val.write().push_str(num.to_string().as_str());
+        val.write().push_str(num.as_str());
     };
 
     let mut input_operator = move |key: &str| val.write().push_str(key);
@@ -42,16 +44,7 @@ fn app() -> Element {
             "-" => input_operator("-"),
             "/" => input_operator("/"),
             "*" => input_operator("*"),
-            "0" => input_digit(0),
-            "1" => input_digit(1),
-            "2" => input_digit(2),
-            "3" => input_digit(3),
-            "4" => input_digit(4),
-            "5" => input_digit(5),
-            "6" => input_digit(6),
-            "7" => input_digit(7),
-            "8" => input_digit(8),
-            "9" => input_digit(9),
+            "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" => input_digit(character),
             _ => {}
         },
         _ => {}
@@ -99,7 +92,7 @@ fn app() -> Element {
                             div { class: "digit-keys",
                                 button {
                                     class: "calculator-key key-0",
-                                    onclick: move |_| input_digit(0),
+                                    onclick: move |_| input_digit(0.to_string()),
                                     "0"
                                 }
                                 button {
@@ -111,7 +104,7 @@ fn app() -> Element {
                                     button {
                                         class: "calculator-key {k}",
                                         name: "key-{k}",
-                                        onclick: move |_| input_digit(k),
+                                        onclick: move |_| input_digit(k.to_string()),
                                         "{k}"
                                     }
                                 }

+ 1 - 1
examples/compose.rs

@@ -19,7 +19,7 @@ fn app() -> Element {
         }
     });
 
-    let open_compose_window = move |evt: MouseEvent| {
+    let open_compose_window = move |_evt: MouseEvent| {
         let tx = handle.tx();
         dioxus_desktop::window().new_window(
             VirtualDom::new_with_props(compose, Rc::new(move |s| tx.unbounded_send(s).unwrap())),

+ 20 - 18
examples/crm.rs

@@ -3,17 +3,13 @@ use dioxus::prelude::*;
 use dioxus_router::prelude::*;
 
 fn main() {
-    launch_desktop(app);
+    launch(app);
 }
 
-/// A type alias that reprsents a shared context between components
-///
-/// Normally we'd wrap the Context in a newtype, but we only have one Signal<Vec<Client>> in this app
-type Clients = Signal<Vec<Client>>;
+/// We only have one list of clients for the whole app, so we can use a global signal.
+static CLIENTS: GlobalSignal<Vec<Client>> = Signal::global(|| Vec::new());
 
 fn app() -> Element {
-    use_context_provider::<Clients>(|| Signal::new(vec![]));
-
     rsx! {
         link {
             rel: "stylesheet",
@@ -37,7 +33,6 @@ fn app() -> Element {
 }
 
 #[derive(Routable, Clone)]
-#[rustfmt::skip]
 enum Route {
     #[route("/")]
     ClientList {},
@@ -58,7 +53,9 @@ pub struct Client {
 
 #[component]
 fn ClientList() -> Element {
-    let mut clients = use_context::<Clients>();
+    let clients = use_hook(|| CLIENTS.signal());
+
+    println!("Clients: {:?}", clients.read());
 
     rsx! {
         h2 { "List of Clients" }
@@ -80,21 +77,25 @@ fn ClientAdd() -> Element {
     let mut description = use_signal(String::new);
 
     let submit_client = move |_: FormEvent| {
-        consume_context::<Clients>().write().push(Client {
-            first_name: first_name.to_string(),
-            last_name: last_name.to_string(),
-            description: description.to_string(),
+        // Write the client
+        CLIENTS.write().push(Client {
+            first_name: first_name(),
+            last_name: last_name(),
+            description: description(),
         });
+
+        println!("Added client: {:?}", CLIENTS.read());
+
+        // And then navigate back to the client list
         dioxus_router::router().push(Route::ClientList {});
     };
 
     rsx! {
         h2 { "Add new Client" }
         form { class: "pure-form pure-form-aligned", onsubmit: submit_client,
-
             fieldset {
                 div { class: "pure-control-group",
-                    label { "for": "first_name", "First Name" }
+                    label { r#for: "first_name", "First Name" }
                     input {
                         id: "first_name",
                         r#type: "text",
@@ -140,13 +141,14 @@ fn ClientAdd() -> Element {
 fn Settings() -> Element {
     rsx! {
         h2 { "Settings" }
-
         button {
             class: "pure-button pure-button-primary red",
-            onclick: move |_| consume_context::<Clients>().write().clear(),
+            onclick: move |_| {
+                CLIENTS.write().clear();
+                dioxus_router::router().push(Route::ClientList {});
+            },
             "Remove all Clients"
         }
-
         Link { to: Route::ClientList {}, class: "pure-button", "Go back" }
     }
 }

+ 15 - 7
packages/signals/src/global.rs

@@ -8,7 +8,7 @@ use std::{
 };
 
 use dioxus_core::{
-    prelude::{provide_context, try_consume_context, IntoAttributeValue},
+    prelude::{provide_context, provide_root_context, try_consume_context, IntoAttributeValue},
     ScopeId,
 };
 use generational_box::{GenerationalRef, GenerationalRefMut};
@@ -32,7 +32,7 @@ fn get_global_context() -> GlobalSignalContext {
             let context = GlobalSignalContext {
                 signal: Rc::new(RefCell::new(HashMap::new())),
             };
-            provide_context(context)
+            provide_root_context(context).unwrap()
         }
     }
 }
@@ -46,19 +46,27 @@ impl<T: 'static> GlobalSignal<T> {
     /// Get the signal that backs this global.
     pub fn signal(&self) -> Signal<T> {
         let key = self as *const _ as *const ();
-
         let context = get_global_context();
-
         let read = context.signal.borrow();
 
         match read.get(&key) {
-            Some(signal) => *signal.downcast_ref::<Signal<T>>().unwrap(),
+            Some(signal) => {
+                let signal = signal.downcast_ref::<Signal<T>>().unwrap();
+                dbg!(signal.id());
+
+                *signal
+            }
             None => {
                 drop(read);
+
                 // Constructors are always run in the root scope
+                // The signal also exists in the root scope
                 let value = ScopeId::ROOT.in_runtime(self.initializer);
-                let signal = Signal::new(value);
-                context.signal.borrow_mut().insert(key, Box::new(signal));
+                let signal = Signal::new_in_scope(value, ScopeId::ROOT);
+
+                let entry = context.signal.borrow_mut().insert(key, Box::new(signal));
+                debug_assert!(entry.is_none(), "Global signal already exists");
+
                 signal
             }
         }

+ 10 - 2
packages/signals/src/lib.rs

@@ -6,19 +6,27 @@
 
 mod rt;
 pub use rt::*;
+
 mod effect;
 pub use effect::*;
-mod impls;
+
 mod selector;
 pub use selector::*;
+
 pub(crate) mod signal;
 pub use signal::*;
+
 mod dependency;
 pub use dependency::*;
+
 mod map;
-pub use generational_box::{Storage, SyncStorage, UnsyncStorage};
 pub use map::*;
+
 mod comparer;
 pub use comparer::*;
+
 mod global;
 pub use global::*;
+
+mod impls;
+pub use generational_box::{Storage, SyncStorage, UnsyncStorage};