Browse Source

drop hooks before contexts

Evan Almloff 1 year ago
parent
commit
8f786d85cd
2 changed files with 31 additions and 2 deletions
  1. 6 2
      packages/core/src/scope_context.rs
  2. 25 0
      packages/core/tests/miri_simple.rs

+ 6 - 2
packages/core/src/scope_context.rs

@@ -17,9 +17,13 @@ pub(crate) struct ScopeContext {
     pub(crate) height: u32,
     pub(crate) height: u32,
     pub(crate) render_count: Cell<usize>,
     pub(crate) render_count: Cell<usize>,
     pub(crate) suspended: Cell<bool>,
     pub(crate) suspended: Cell<bool>,
-    pub(crate) shared_contexts: RefCell<Vec<Box<dyn Any>>>,
+
+    // Note: the order of the hook and context fields is important. The hooks field must be dropped before the contexts field in case a hook drop implementation tries to access a context.
     pub(crate) hooks: RefCell<Vec<Box<dyn Any>>>,
     pub(crate) hooks: RefCell<Vec<Box<dyn Any>>>,
     pub(crate) hook_index: Cell<usize>,
     pub(crate) hook_index: Cell<usize>,
+
+    pub(crate) shared_contexts: RefCell<Vec<Box<dyn Any>>>,
+
     pub(crate) spawned_tasks: RefCell<FxHashSet<Task>>,
     pub(crate) spawned_tasks: RefCell<FxHashSet<Task>>,
 }
 }
 
 
@@ -69,7 +73,7 @@ impl ScopeContext {
 
 
     /// Schedule an update for any component given its [`ScopeId`].
     /// Schedule an update for any component given its [`ScopeId`].
     ///
     ///
-    /// A component's [`ScopeId`] can be obtained from `use_hook` or the [`ScopeState::scope_id`] method.
+    /// A component's [`ScopeId`] can be obtained from `use_hook` or the [`current_scope_id`] method.
     ///
     ///
     /// This method should be used when you want to schedule an update for a component
     /// This method should be used when you want to schedule an update for a component
     pub fn schedule_update_any(&self) -> Arc<dyn Fn(ScopeId) + Send + Sync> {
     pub fn schedule_update_any(&self) -> Arc<dyn Fn(ScopeId) + Send + Sync> {

+ 25 - 0
packages/core/tests/miri_simple.rs

@@ -116,3 +116,28 @@ fn diffing_drops_old() {
 
 
     _ = dom.render_immediate_to_vec();
     _ = dom.render_immediate_to_vec();
 }
 }
+
+#[test]
+fn hooks_drop_before_contexts() {
+    fn app() -> Element {
+        provide_context(123i32);
+        use_hook(|| {
+            #[derive(Clone)]
+            struct ReadsContextOnDrop;
+
+            impl Drop for ReadsContextOnDrop {
+                fn drop(&mut self) {
+                    let _ = consume_context::<i32>();
+                }
+            }
+        });
+
+        rsx! { div {} }
+    }
+
+    let mut dom = VirtualDom::new(app);
+
+    dom.rebuild(&mut dioxus_core::NoOpMutations);
+    dom.mark_dirty(ScopeId::ROOT);
+    _ = dom.render_immediate_to_vec();
+}