Browse Source

create a way to hoist ownership to a different scope

Evan Almloff 1 năm trước cách đây
mục cha
commit
dce418140a

+ 5 - 5
packages/core/src/lib.rs

@@ -84,11 +84,11 @@ pub use crate::innerlude::{
 /// This includes types like [`Scope`], [`Element`], and [`Component`].
 pub mod prelude {
     pub use crate::innerlude::{
-        consume_context, current_scope_id, fc_to_builder, has_context, provide_context,
-        provide_root_context, schedule_update_any, suspend, throw, AnyValue, Component, Element,
-        Event, EventHandler, Fragment, IntoAttributeValue, LazyNodes, Properties, Scope, ScopeId,
-        ScopeState, Scoped, TaskId, Template, TemplateAttribute, TemplateNode, Throw, VNode,
-        VirtualDom,
+        consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, has_context,
+        provide_context, provide_context_to_scope, provide_root_context, schedule_update_any,
+        suspend, throw, AnyValue, Component, Element, Event, EventHandler, Fragment,
+        IntoAttributeValue, LazyNodes, Properties, Scope, ScopeId, ScopeState, Scoped, TaskId,
+        Template, TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
     };
 }
 

+ 14 - 0
packages/core/src/scope_context.rs

@@ -268,6 +268,15 @@ pub fn consume_context<T: 'static + Clone>() -> Option<T> {
     with_current_scope(|cx| cx.consume_context::<T>()).flatten()
 }
 
+/// Consume context from the current scope
+pub fn consume_context_from_scope<T: 'static + Clone>(scope_id: ScopeId) -> Option<T> {
+    with_runtime(|rt| {
+        rt.get_context(scope_id)
+            .and_then(|cx| cx.consume_context::<T>())
+    })
+    .flatten()
+}
+
 /// Check if the current scope has a context
 pub fn has_context<T: 'static + Clone>() -> Option<T> {
     with_current_scope(|cx| cx.has_context::<T>()).flatten()
@@ -278,6 +287,11 @@ pub fn provide_context<T: 'static + Clone>(value: T) -> Option<T> {
     with_current_scope(|cx| cx.provide_context(value))
 }
 
+/// Provide context to the the given scope
+pub fn provide_context_to_scope<T: 'static + Clone>(scope_id: ScopeId, value: T) -> Option<T> {
+    with_runtime(|rt| rt.get_context(scope_id).map(|cx| cx.provide_context(value))).flatten()
+}
+
 /// Provide a context to the root scope
 pub fn provide_root_context<T: 'static + Clone>(value: T) -> Option<T> {
     with_current_scope(|cx| cx.provide_root_context(value))

+ 4 - 0
packages/signals/src/lib.rs

@@ -70,6 +70,10 @@ impl<T: 'static> Signal<T> {
         }
     }
 
+    pub fn origin_scope(&self) -> ScopeId {
+        self.inner.origin_scope()
+    }
+
     pub fn read(&self) -> Ref<T> {
         let inner = self.inner.read();
         if let Some(current_scope_id) = current_scope_id() {

+ 30 - 1
packages/signals/src/rt.rs

@@ -2,7 +2,11 @@ use std::cell::{Ref, RefMut};
 
 use std::rc::Rc;
 
-use dioxus_core::prelude::{consume_context, provide_root_context};
+use dioxus_core::prelude::{
+    consume_context, consume_context_from_scope, current_scope_id, provide_context_to_scope,
+    provide_root_context,
+};
+use dioxus_core::ScopeId;
 
 use dioxus_copy::{CopyHandle, Owner, Store};
 
@@ -26,8 +30,19 @@ fn current_owner() -> Rc<Owner> {
     }
 }
 
+fn owner_in_scope(scope: ScopeId) -> Rc<Owner> {
+    match consume_context_from_scope(scope) {
+        Some(rt) => rt,
+        None => {
+            let owner = Rc::new(current_store().owner());
+            provide_context_to_scope(scope, owner).expect("in a virtual dom")
+        }
+    }
+}
+
 pub struct CopyValue<T: 'static> {
     pub value: CopyHandle<T>,
+    origin_scope: ScopeId,
 }
 
 impl<T: 'static> CopyValue<T> {
@@ -36,9 +51,23 @@ impl<T: 'static> CopyValue<T> {
 
         Self {
             value: owner.insert(value),
+            origin_scope: current_scope_id().expect("in a virtual dom"),
         }
     }
 
+    pub fn new_in_scope(value: T, scope: ScopeId) -> Self {
+        let owner = owner_in_scope(scope);
+
+        Self {
+            value: owner.insert(value),
+            origin_scope: scope,
+        }
+    }
+
+    pub fn origin_scope(&self) -> ScopeId {
+        self.origin_scope
+    }
+
     pub fn try_read(&self) -> Option<Ref<'_, T>> {
         self.value.try_read()
     }