소스 검색

feat: proper handling of events

Jonathan Kelley 3 년 전
부모
커밋
d7940aa
7개의 변경된 파일116개의 추가작업 그리고 62개의 파일을 삭제
  1. 3 2
      packages/core/examples/vdom_usage.rs
  2. 2 0
      packages/core/src/diff.rs
  3. 59 19
      packages/core/src/scheduler.rs
  4. 8 6
      packages/core/src/scope.rs
  5. 33 26
      packages/web/examples/basic.rs
  6. 9 9
      packages/web/src/dom.rs
  7. 2 0
      packages/web/src/lib.rs

+ 3 - 2
packages/core/examples/vdom_usage.rs

@@ -4,12 +4,13 @@ use dioxus_core::prelude::*;
 
 #[async_std::main]
 async fn main() {
-    static App: FC<()> = |cx, props|cx.render(LazyNodes::new(|f| f.text(format_args!("hello"))));
+    static App: FC<()> = |cx, props| cx.render(LazyNodes::new(|f| f.text(format_args!("hello"))));
 
     let mut dom = VirtualDom::new(App);
 
     dom.rebuild();
 
     let deadline = async_std::task::sleep(Duration::from_millis(50));
-    let _fut = dom.run_with_deadline(deadline);
+
+    // let _fut = dom.run_with_deadline(|| deadline.);
 }

+ 2 - 0
packages/core/src/diff.rs

@@ -185,6 +185,7 @@ impl<'bump> DiffMachine<'bump> {
     /// Returns a `bool` indicating that the work completed properly.
     pub fn work(&mut self, mut deadline_expired: impl FnMut() -> bool) -> bool {
         while let Some(instruction) = self.stack.pop() {
+            log::debug!("working {:?}", instruction);
             match instruction {
                 DiffInstruction::Diff { old, new } => self.diff_node(old, new),
                 DiffInstruction::Create { node } => self.create_node(node),
@@ -194,6 +195,7 @@ impl<'bump> DiffMachine<'bump> {
             };
 
             if deadline_expired() {
+                log::debug!("Deadling expired before we could finished!");
                 return false;
             }
         }

+ 59 - 19
packages/core/src/scheduler.rs

@@ -228,6 +228,12 @@ impl Scheduler {
             ScopeId(0)
         }) as FiberTask);
 
+        let saved_state = SavedDiffWork {
+            mutations: Mutations::new(),
+            stack: DiffStack::new(),
+            seen_scopes: Default::default(),
+        };
+
         Self {
             pool,
 
@@ -250,7 +256,7 @@ impl Scheduler {
             garbage_scopes: HashSet::new(),
 
             dirty_scopes: Default::default(),
-            saved_state: None,
+            saved_state: Some(saved_state),
             in_progress: false,
         }
     }
@@ -262,7 +268,7 @@ impl Scheduler {
         if let Some(scope) = self.pool.get_scope_mut(event.scope) {
             if let Some(element) = event.mounted_dom_id {
                 // TODO: bubble properly here
-                scope.call_listener(event.event, element);
+                scope.call_listener(event, element);
 
                 while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
                     //
@@ -321,7 +327,7 @@ impl Scheduler {
                 if let Some(scope) = self.pool.get_scope_mut(event.scope) {
                     if let Some(element) = event.mounted_dom_id {
                         // TODO: bubble properly here
-                        scope.call_listener(event.event, element);
+                        scope.call_listener(event, element);
 
                         while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
                             //
@@ -360,31 +366,55 @@ impl Scheduler {
                 h1.cmp(&h2)
             });
 
-            if let Some(scope) = self.dirty_scopes.pop() {
-                let component = self.pool.get_scope(scope).unwrap();
+            if let Some(scopeid) = self.dirty_scopes.pop() {
+                let component = self.pool.get_scope(scopeid).unwrap();
                 let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
+                // let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
+                machine.stack.scope_stack.push(scopeid);
                 machine.stack.push(DiffInstruction::Diff { new, old });
             }
         }
 
-        let deadline_expired = machine.work(deadline_reached);
+        let work_completed = machine.work(deadline_reached);
 
-        let machine: DiffMachine<'static> = unsafe { std::mem::transmute(machine) };
-        let mut saved = machine.save();
+        log::debug!("Working finished? {:?}", work_completed);
 
-        if deadline_expired {
-            self.save_work(saved);
-            false
-        } else {
-            for node in saved.seen_scopes.drain() {
+        log::debug!("raw edits {:?}", machine.mutations.edits);
+
+        let mut machine: DiffMachine<'static> = unsafe { std::mem::transmute(machine) };
+        // let mut saved = machine.save();
+
+        if work_completed {
+            for node in machine.seen_scopes.drain() {
+                // self.dirty_scopes.clear();
+                // self.ui_events.clear();
                 self.dirty_scopes.remove(&node);
+                // self.dirty_scopes.remove(&node);
             }
 
             let mut new_mutations = Mutations::new();
-            std::mem::swap(&mut new_mutations, &mut saved.mutations);
+
+            for edit in machine.mutations.edits.drain(..) {
+                new_mutations.edits.push(edit);
+            }
+
+            // for edit in saved.edits.drain(..) {
+            //     new_mutations.edits.push(edit);
+            // }
+
+            // std::mem::swap(&mut new_mutations, &mut saved.mutations);
 
             mutations.push(new_mutations);
+
+            log::debug!("saved edits {:?}", mutations);
+
+            let mut saved = machine.save();
             self.save_work(saved);
+            false
+
+            // self.save_work(saved);
+            // false
+        } else {
             true
         }
     }
@@ -429,18 +459,28 @@ impl Scheduler {
         */
         let mut committed_mutations = Vec::<Mutations<'static>>::new();
 
-        loop {
+        while self.has_any_work() {
             // switch our priority, pop off any work
             for event in self.ui_events.drain(..) {
                 if let Some(scope) = self.pool.get_scope_mut(event.scope) {
                     if let Some(element) = event.mounted_dom_id {
+                        log::info!("Calling listener {:?}, {:?}", event.scope, element);
+
                         // TODO: bubble properly here
-                        scope.call_listener(event.event, element);
+                        scope.call_listener(event, element);
 
                         while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
                             match dirty_scope {
                                 SchedulerMsg::Immediate(im) => {
-                                    self.dirty_scopes.insert(im);
+                                    log::debug!("Handling immediate {:?}", im);
+
+                                    if let Some(scope) = self.pool.get_scope_mut(im) {
+                                        if scope.run_scope(&self.pool) {
+                                            self.dirty_scopes.insert(im);
+                                        } else {
+                                            todo!()
+                                        }
+                                    }
                                 }
                                 _ => todo!(),
                             }
@@ -449,10 +489,10 @@ impl Scheduler {
                 }
             }
 
-            let finished_before_deadline =
+            let deadline_expired =
                 self.work_on_current_lane(&mut deadline, &mut committed_mutations);
 
-            if !finished_before_deadline {
+            if deadline_expired {
                 break;
             }
         }

+ 8 - 6
packages/core/src/scope.rs

@@ -238,22 +238,24 @@ impl Scope {
     }
 
     /// A safe wrapper around calling listeners
-    pub(crate) fn call_listener(&mut self, event: SyntheticEvent, element: ElementId) {
+    pub(crate) fn call_listener(&mut self, event: UserEvent, element: ElementId) {
         let listners = self.listeners.borrow_mut();
 
         let raw_listener = listners.iter().find(|lis| {
             let search = unsafe { &***lis };
-            let search_id = search.mounted_node.get();
-
-            // this assumes the node might not be mounted - should we assume that though?
-            search_id.map(|f| f == element).unwrap_or(false)
+            if search.event == event.name {
+                let search_id = search.mounted_node.get();
+                search_id.map(|f| f == element).unwrap_or(false)
+            } else {
+                false
+            }
         });
 
         if let Some(raw_listener) = raw_listener {
             let listener = unsafe { &**raw_listener };
             let mut cb = listener.callback.borrow_mut();
             if let Some(cb) = cb.as_mut() {
-                (cb)(event);
+                (cb)(event.event);
             }
         } else {
             log::warn!("An event was triggered but there was no listener to handle it");

+ 33 - 26
packages/web/examples/basic.rs

@@ -22,36 +22,43 @@ fn main() {
     dioxus_web::launch(APP, |c| c)
 }
 
-static APP: FC<()> = |cx, props|{
+static APP: FC<()> = |cx, props| {
     let mut count = use_state(cx, || 3);
 
     cx.render(rsx! {
-        div {
-            button {
-                onclick: move |_| count += 1,
-                "Click to add."
-                "Current count: {count}"
-            }
-            ul {
-                {(0..*count).map(|f| rsx!{
-                    li { "a - {f}" }
-                    li { "b - {f}" }
-                    li { "c - {f}" }
-                })}
-            }
-            Child {}
+        button {
+            // onclick: move |_| count += 1,
+            onmouseover: move |_| count += 5,
+            onmouseout: move |_| count -= 5,
+            "Click to add."
+            "Current count: {count}"
         }
+        // div {
+        //     button {
+        //         onclick: move |_| count += 1,
+        //         "Click to add."
+        //         "Current count: {count}"
+        //     }
+        //     ul {
+        //         {(0..*count).map(|f| rsx!{
+        //             li { "a - {f}" }
+        //             li { "b - {f}" }
+        //             li { "c - {f}" }
+        //         })}
+        //     }
+        //     Child {}
+        // }
     })
 };
 
-static Child: FC<()> = |cx, props|{
-    cx.render(rsx! {
-        div {
-            div {
-                div {
-                    "hello child"
-                }
-            }
-        }
-    })
-};
+// static Child: FC<()> = |cx, props| {
+//     cx.render(rsx! {
+//         div {
+//             div {
+//                 div {
+//                     "hello child"
+//                 }
+//             }
+//         }
+//     })
+// };

+ 9 - 9
packages/web/src/dom.rs

@@ -7,9 +7,9 @@ use dioxus_core::{
     DomEdit, ElementId, ScopeId,
 };
 use fxhash::FxHashMap;
-use wasm_bindgen::{closure::Closure, JsCast};
+use wasm_bindgen::{closure::Closure, JsCast, JsValue};
 use web_sys::{
-    window, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
+    window, Attr, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
     HtmlOptionElement, Node, NodeList, UiEvent,
 };
 
@@ -264,8 +264,8 @@ impl WebsysDom {
         )
         .unwrap();
 
-        el.set_attribute(&format!("dioxus-event"), &format!("{}", event))
-            .unwrap();
+        // el.set_attribute(&format!("dioxus-event"), &format!("{}", event))
+        //     .unwrap();
 
         // Register the callback to decode
 
@@ -532,11 +532,11 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
 
     log::debug!("Event type is {:?}", typ);
 
-    // let attrs = target.attributes();
-    // for x in 0..attrs.length() {
-    //     let attr = attrs.item(x).unwrap();
-    //     log::debug!("attrs include: {:#?}", attr);
-    // }
+    let attrs = target.attributes();
+    for x in 0..attrs.length() {
+        let attr: Attr = attrs.item(x).unwrap();
+        log::debug!("attrs include: {:#?}, {:#?}", attr.name(), attr.value());
+    }
 
     use anyhow::Context;
 

+ 2 - 0
packages/web/src/lib.rs

@@ -152,6 +152,8 @@ pub async fn run_with_props<T: Properties + 'static>(root: FC<T>, root_props: T,
         // run the virtualdom work phase until the frame deadline is reached
         let mutations = dom.run_with_deadline(|| (&mut deadline).now_or_never().is_some());
 
+        log::debug!("received mutations {:#?}", mutations);
+
         // wait for the animation frame to fire so we can apply our changes
         work_loop.wait_for_raf().await;