Jonathan Kelley 4 лет назад
Родитель
Сommit
cca7c5fc3a
4 измененных файлов с 85 добавлено и 159 удалено
  1. 14 14
      packages/atoms/src/lib.rs
  2. 11 11
      packages/core/src/hooks.rs
  3. 0 1
      packages/core/src/lib.rs
  4. 60 133
      packages/core/src/virtual_dom.rs

+ 14 - 14
packages/atoms/src/lib.rs

@@ -32,7 +32,7 @@ mod traits {
     // Atoms, selectors, and their family variants are readable
     pub trait Readable<T: AtomValue>: Sized + Copy {
         fn use_read<'a, P: 'static>(self, cx: Context<'a, P>) -> &'a T {
-            hooks::use_read(&cx, self)
+            hooks::use_read(cx, self)
         }
 
         // This returns a future of the value
@@ -95,9 +95,9 @@ mod atoms {
             const EXAMPLE_ATOM: Atom<i32> = |_| 10;
 
             // ensure that atoms are both read and write
-            let _ = use_read(&cx, &EXAMPLE_ATOM);
-            let _ = use_read_write(&cx, &EXAMPLE_ATOM);
-            let _ = use_write(&cx, &EXAMPLE_ATOM);
+            let _ = use_read(cx, &EXAMPLE_ATOM);
+            let _ = use_read_write(cx, &EXAMPLE_ATOM);
+            let _ = use_write(cx, &EXAMPLE_ATOM);
         }
     }
 }
@@ -161,7 +161,7 @@ mod atomfamily {
 
         fn test(cx: Context<()>) {
             let title = Titles.select(&10).use_read(cx);
-            let t2 = use_read(&cx, &Titles.select(&10));
+            let t2 = use_read(cx, &Titles.select(&10));
         }
     }
 }
@@ -368,7 +368,7 @@ mod root {
 
 mod hooks {
     use super::*;
-    use dioxus_core::{hooks::use_ref, prelude::Context, virtual_dom::Scoped};
+    use dioxus_core::{hooks::use_ref, prelude::Context};
 
     pub fn use_init_recoil_root<P>(cx: Context<P>, cfg: impl Fn(())) {
         cx.use_create_context(move || RefCell::new(RecoilRoot::new()))
@@ -381,12 +381,12 @@ mod hooks {
     ///
     /// You can use this method to create controllers that perform much more complex actions than set/get
     /// However, be aware that "getting" values through this hook will not subscribe the component to any updates.
-    pub fn use_recoil_api<'a>(cx: &impl Scoped<'a>) -> &'a Rc<RecoilContext> {
+    pub fn use_recoil_api<'a, P>(cx: Context<'a, P>) -> &'a Rc<RecoilContext> {
         cx.use_context::<RecoilContext>()
     }
 
-    pub fn use_write<'a, T: AtomValue>(
-        cx: &impl Scoped<'a>,
+    pub fn use_write<'a, P, T: AtomValue>(
+        cx: Context<'a, P>,
         // todo: this shouldn't need to be static
         writable: impl Writable<T>,
     ) -> &'a Rc<dyn Fn(T)> {
@@ -412,8 +412,8 @@ mod hooks {
     /// Read the atom and get the Rc directly to the Atom's slot
     /// This is useful if you need the memoized Atom value. However, Rc<T> is not as easy to
     /// work with as
-    pub fn use_read_raw<'a, T: AtomValue>(
-        cx: &impl Scoped<'a>,
+    pub fn use_read_raw<'a, P, T: AtomValue>(
+        cx: Context<'a, P>,
         readable: impl Readable<T>,
     ) -> &'a Rc<T> {
         struct ReadHook<T> {
@@ -449,7 +449,7 @@ mod hooks {
     }
 
     ///
-    pub fn use_read<'a, T: AtomValue>(cx: &impl Scoped<'a>, readable: impl Readable<T>) -> &'a T {
+    pub fn use_read<'a, P, T: AtomValue>(cx: Context<'a, P>, readable: impl Readable<T>) -> &'a T {
         use_read_raw(cx, readable).as_ref()
     }
 
@@ -468,8 +468,8 @@ mod hooks {
     /// // equivalent to:
     /// let (title, set_title) = (use_read(cx, &Title), use_write(cx, &Title));
     /// ```
-    pub fn use_read_write<'a, T: AtomValue + 'static>(
-        cx: &impl Scoped<'a>,
+    pub fn use_read_write<'a, P, T: AtomValue + 'static>(
+        cx: Context<'a, P>,
         writable: impl Writable<T>,
     ) -> (&'a T, &'a Rc<dyn Fn(T)>) {
         (use_read(cx, writable), use_write(cx, writable))

+ 11 - 11
packages/core/src/hooks.rs

@@ -36,8 +36,8 @@ use std::{
 ///     }
 /// }
 /// ```
-pub fn use_state_classic<'a, 'c, T: 'static, F: FnOnce() -> T>(
-    cx: impl Scoped<'a>,
+pub fn use_state_classic<'a, 'c, T: 'static, F: FnOnce() -> T, P>(
+    cx: Context<'a, P>,
     initial_state_fn: F,
 ) -> (&'a T, &'a Rc<dyn Fn(T)>) {
     struct UseState<T: 'static> {
@@ -158,8 +158,8 @@ impl<'a, T: 'static + Display> std::fmt::Display for UseState<T> {
 ///     }
 /// }
 /// ```
-pub fn use_state<'a, 'c, T: 'static, F: FnOnce() -> T>(
-    cx: impl Scoped<'a>,
+pub fn use_state<'a, 'c, T: 'static, F: FnOnce() -> T, P>(
+    cx: Context<'a, P>,
     initial_state_fn: F,
 ) -> &'a UseState<T> {
     cx.use_hook(
@@ -230,8 +230,8 @@ pub fn use_state<'a, 'c, T: 'static, F: FnOnce() -> T>(
 /// To change it, use modify.
 /// Modifications to this value do not cause updates to the component
 /// Attach to inner context reference, so context can be consumed
-pub fn use_ref<'a, T: 'static>(
-    cx: impl Scoped<'a>,
+pub fn use_ref<'a, T: 'static, P>(
+    cx: Context<'a, P>,
     initial_state_fn: impl FnOnce() -> T + 'static,
 ) -> &'a RefCell<T> {
     cx.use_hook(|| RefCell::new(initial_state_fn()), |state| &*state, |_| {})
@@ -249,8 +249,8 @@ struct UseReducer<T: 'static, R: 'static> {
 ///
 /// This is behaves almost exactly the same way as React's "use_state".
 ///
-pub fn use_reducer<'a, 'c, State: 'static, Action: 'static>(
-    cx: impl Scoped<'a>,
+pub fn use_reducer<'a, 'c, State: 'static, Action: 'static, P>(
+    cx: Context<'a, P>,
     initial_state_fn: impl FnOnce() -> State,
     _reducer: impl Fn(&mut State, Action),
 ) -> (&'a State, &'a Box<dyn Fn(Action)>) {
@@ -291,8 +291,8 @@ pub fn use_reducer<'a, 'c, State: 'static, Action: 'static>(
 /// Use model makes it easy to use "models" as state for components. To modify the model, call "modify" and a clone of the
 /// current model will be made, with a RefMut lock on it. Dioxus will never run your components multithreaded, so you can
 /// be relatively sure that this won't fail in practice
-pub fn use_model<'a, T: ToOwned<Owned = T> + 'static>(
-    cx: impl Scoped<'a>,
+pub fn use_model<'a, T: ToOwned<Owned = T> + 'static, P>(
+    cx: Context<'a, P>,
     f: impl FnOnce() -> T,
 ) -> &'a UseModel<T> {
     cx.use_hook(
@@ -381,7 +381,7 @@ mod tests {
     // };
 }
 
-pub fn use_is_initialized<P>(cx: Context<P>) -> bool {
+pub fn use_is_initialized<'a, P>(cx: Context<'a, P>) -> bool {
     let val = use_ref(cx, || false);
     match *val.borrow() {
         true => true,

+ 0 - 1
packages/core/src/lib.rs

@@ -57,7 +57,6 @@ pub mod prelude {
     use crate::nodes;
     pub use crate::styles::{AsAttr, StyleBuilder};
     pub use crate::virtual_dom::Context;
-    pub use crate::virtual_dom::Scoped;
     pub use nodes::*;
 
     pub use crate::nodebuilder::LazyNodes;

+ 60 - 133
packages/core/src/virtual_dom.rs

@@ -586,13 +586,58 @@ impl Scope {
     pub(crate) fn root<'a>(&'a self) -> &'a VNode<'a> {
         &self.frames.cur_frame().head_node
     }
+}
+
+/// Components in Dioxus use the "Context" object to interact with their lifecycle.
+/// This lets components schedule updates, integrate hooks, and expose their context via the context api.
+///
+/// Properties passed down from the parent component are also directly accessible via the exposed "props" field.
+///
+/// ```ignore
+/// #[derive(Properties)]
+/// struct Props {
+///     name: String
+///
+/// }
+///
+/// fn example(cx: Context<Props>) -> VNode {
+///     html! {
+///         <div> "Hello, {cx.name}" </div>
+///     }
+/// }
+/// ```
+// todo: force lifetime of source into T as a valid lifetime too
+// it's definitely possible, just needs some more messing around
+pub struct Context<'src, T> {
+    pub props: &'src T,
+    pub scope: &'src Scope,
+}
+
+impl<'src, T> Copy for Context<'src, T> {}
+impl<'src, T> Clone for Context<'src, T> {
+    fn clone(&self) -> Self {
+        Self {
+            props: self.props,
+            scope: self.scope,
+        }
+    }
+}
+
+impl<'a, T> Deref for Context<'a, T> {
+    type Target = &'a T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.props
+    }
+}
 
+impl<'src, P> Context<'src, P> {
     /// Access the children elements passed into the component
-    pub fn children(&self) -> &[VNode] {
+    pub fn children(&self) -> &'src [VNode<'src>] {
         // We're re-casting the nodes back out
         // They don't really have a static lifetime
         unsafe {
-            let scope = self;
+            let scope = self.scope;
             let nodes = scope.child_nodes;
             nodes
         }
@@ -600,7 +645,7 @@ impl Scope {
 
     /// Create a subscription that schedules a future render for the reference component
     pub fn schedule_update(&self) -> Rc<dyn Fn() + 'static> {
-        self.event_channel.clone()
+        self.scope.event_channel.clone()
     }
 
     pub fn schedule_effect(&self) -> Rc<dyn Fn() + 'static> {
@@ -626,11 +671,11 @@ impl Scope {
     ///     cx.render(lazy_tree)
     /// }
     ///```
-    pub fn render<'src, F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
-        &'src self,
+    pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
+        self,
         lazy_nodes: LazyNodes<'src, F>,
     ) -> VNode<'src> {
-        let scope_ref = self;
+        let scope_ref = self.scope;
         let listener_id = &scope_ref.listener_idx;
         lazy_nodes.into_vnode(NodeFactory {
             scope_ref,
@@ -654,8 +699,8 @@ impl Scope {
     ///     )
     /// }
     /// ```
-    pub fn use_hook<'src, InternalHookState: 'static, Output: 'src>(
-        &'src self,
+    pub fn use_hook<InternalHookState: 'static, Output: 'src>(
+        self,
 
         // The closure that builds the hook state
         initializer: impl FnOnce() -> InternalHookState,
@@ -667,7 +712,7 @@ impl Scope {
         // TODO: add this to the "clean up" group for when the component is dropped
         _cleanup: impl FnOnce(InternalHookState),
     ) -> Output {
-        let scope = self;
+        let scope = self.scope;
 
         let idx = scope.hookidx.get();
 
@@ -715,8 +760,8 @@ Any function prefixed with "use" should not be called conditionally.
     ///
     ///
     ///
-    fn use_create_context<T: 'static>(&self, init: impl Fn() -> T) {
-        let scope = self;
+    pub fn use_create_context<T: 'static>(&self, init: impl Fn() -> T) {
+        let mut scope = self.scope;
         let mut cxs = scope.shared_contexts.borrow_mut();
         let ty = TypeId::of::<T>();
 
@@ -745,12 +790,12 @@ Any function prefixed with "use" should not be called conditionally.
     }
 
     /// There are hooks going on here!
-    pub fn use_context<'src, T: 'static>(&'src self) -> &'src Rc<T> {
+    pub fn use_context<T: 'static>(self) -> &'src Rc<T> {
         self.try_use_context().unwrap()
     }
 
     /// Uses a context, storing the cached value around
-    pub fn try_use_context<'src, T: 'static>(&'src self) -> Result<&'src Rc<T>> {
+    pub fn try_use_context<T: 'static>(self) -> Result<&'src Rc<T>> {
         struct UseContextHook<C> {
             par: Option<Rc<C>>,
             we: Option<Weak<C>>,
@@ -762,7 +807,7 @@ Any function prefixed with "use" should not be called conditionally.
                 we: None as Option<Weak<T>>,
             },
             move |hook| {
-                let mut scope = Some(self);
+                let mut scope = Some(self.scope);
 
                 if let Some(we) = &hook.we {
                     if let Some(re) = we.upgrade() {
@@ -807,11 +852,7 @@ Any function prefixed with "use" should not be called conditionally.
         )
     }
 
-    pub fn suspend<
-        'src,
-        Output: 'src,
-        Fut: FnOnce(SuspendedContext, Output) -> VNode<'src> + 'src,
-    >(
+    pub fn suspend<Output: 'src, Fut: FnOnce(SuspendedContext, Output) -> VNode<'src> + 'src>(
         &'src self,
         fut: &'src mut Pin<Box<dyn Future<Output = Output> + 'static>>,
         callback: Fut,
@@ -832,120 +873,6 @@ Any function prefixed with "use" should not be called conditionally.
     }
 }
 
-/// Components in Dioxus use the "Context" object to interact with their lifecycle.
-/// This lets components schedule updates, integrate hooks, and expose their context via the context api.
-///
-/// Properties passed down from the parent component are also directly accessible via the exposed "props" field.
-///
-/// ```ignore
-/// #[derive(Properties)]
-/// struct Props {
-///     name: String
-///
-/// }
-///
-/// fn example(cx: Context<Props>) -> VNode {
-///     html! {
-///         <div> "Hello, {cx.name}" </div>
-///     }
-/// }
-/// ```
-// todo: force lifetime of source into T as a valid lifetime too
-// it's definitely possible, just needs some more messing around
-pub struct Context<'src, T> {
-    pub props: &'src T,
-    pub scope: &'src Scope,
-}
-
-impl<'src, T> Copy for Context<'src, T> {}
-impl<'src, T> Clone for Context<'src, T> {
-    fn clone(&self) -> Self {
-        Self {
-            props: self.props,
-            scope: self.scope,
-        }
-    }
-}
-
-impl<'a, T> Deref for Context<'a, T> {
-    type Target = &'a T;
-
-    fn deref(&self) -> &Self::Target {
-        &self.props
-    }
-}
-/// The `Scoped` trait makes it slightly less cumbersome for hooks to use the underlying `Scope` without having to make
-/// their hooks generic over the [`Props`] type that [`Context`] is
-///
-/// ## Example:
-///
-/// ```
-/// fn use_raw<T>(cx: impl Scoped) -> &mut T {
-///     
-/// }
-/// ```
-///
-pub trait Scoped<'src>: Sized + Clone + Copy {
-    ///
-    ///
-    ///
-    ///
-    ///
-    ///
-    ///
-    fn get_scope(self) -> &'src Scope;
-
-    #[inline]
-    fn children(self) -> &'src [VNode<'src>] {
-        self.get_scope().children()
-    }
-
-    #[inline]
-    fn schedule_update(self) -> Rc<dyn Fn() + 'static> {
-        self.get_scope().schedule_update()
-    }
-
-    #[inline]
-    fn use_hook<InternalHookState: 'static, Output: 'src>(
-        self,
-        initializer: impl FnOnce() -> InternalHookState,
-        runner: impl FnOnce(&'src mut InternalHookState) -> Output,
-        _cleanup: impl FnOnce(InternalHookState),
-    ) -> Output {
-        self.get_scope().use_hook(initializer, runner, _cleanup)
-    }
-
-    /// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator.
-    ///
-    /// This function consumes the context and absorb the lifetime, so these VNodes *must* be returned.
-    ///
-    /// ## Example
-    ///
-    /// ```ignore
-    /// fn Component(cx: Context<()>) -> VNode {
-    ///     // Lazy assemble the VNode tree
-    ///     let lazy_tree = html! {<div> "Hello World" </div>};
-    ///     
-    ///     // Actually build the tree and allocate it
-    ///     cx.render(lazy_tree)
-    /// }
-    ///```
-    #[inline]
-    fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
-        self,
-        lazy_nodes: LazyNodes<'src, F>,
-    ) -> VNode<'src> {
-        self.get_scope().render(lazy_nodes)
-    }
-}
-
-impl<'src, T> Scoped<'src> for Context<'src, T> {
-    #[inline]
-    fn get_scope(self) -> &'src Scope {
-        self.scope
-    }
-}
-
 #[derive(Clone)]
 pub struct SuspendedContext {}