Quellcode durchsuchen

wip: move the functions around a bit

Jonathan Kelley vor 4 Jahren
Ursprung
Commit
36542b4
3 geänderte Dateien mit 167 neuen und 104 gelöschten Zeilen
  1. 21 20
      packages/core/examples/borrowed.rs
  2. 6 6
      packages/core/src/hooks.rs
  3. 140 78
      packages/core/src/virtual_dom.rs

+ 21 - 20
packages/core/examples/borrowed.rs

@@ -20,28 +20,29 @@ struct ListItem {
 }
 
 fn app(cx: Context<AppProps>) -> VNode {
-    let (val, set_val) = use_state_classic(&cx, || 0);
+    let (val, set_val) = use_state_classic(cx, || 0);
 
     cx.render(LazyNodes::new(move |_nodecx| {
-        builder::ElementBuilder::new(_nodecx, "div")
-            .iter_child({
-                cx.items.iter().map(|child| {
-                    builder::virtual_child(
-                        _nodecx,
-                        ChildItem,
-                        ChildProps {
-                            item: child.clone(),
-                            item_handler: set_val.clone(),
-                        },
-                        None,
-                        &[],
-                    )
-                })
-            })
-            .iter_child([builder::ElementBuilder::new(_nodecx, "div")
-                .iter_child([builder::text3(_nodecx.bump(), format_args!("{}", val))])
-                .finish()])
-            .finish()
+        todo!()
+        // builder::ElementBuilder::new(_nodecx, "div")
+        //     .iter_child({
+        //         cx.items.iter().map(|child| {
+        //             builder::virtual_child(
+        //                 _nodecx,
+        //                 ChildItem,
+        //                 ChildProps {
+        //                     item: child.clone(),
+        //                     item_handler: set_val.clone(),
+        //                 },
+        //                 None,
+        //                 &[],
+        //             )
+        //         })
+        //     })
+        //     .iter_child([builder::ElementBuilder::new(_nodecx, "div")
+        //         .iter_child([builder::text3(_nodecx.bump(), format_args!("{}", val))])
+        //         .finish()])
+        //     .finish()
     }))
 }
 

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

@@ -37,7 +37,7 @@ use std::{
 /// }
 /// ```
 pub fn use_state_classic<'a, 'c, T: 'static, F: FnOnce() -> T>(
-    cx: &impl Scoped<'a>,
+    cx: impl Scoped<'a>,
     initial_state_fn: F,
 ) -> (&'a T, &'a Rc<dyn Fn(T)>) {
     struct UseState<T: 'static> {
@@ -159,7 +159,7 @@ 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>,
+    cx: impl Scoped<'a>,
     initial_state_fn: F,
 ) -> &'a UseState<T> {
     cx.use_hook(
@@ -231,7 +231,7 @@ pub fn use_state<'a, 'c, T: 'static, F: FnOnce() -> T>(
 /// 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>,
+    cx: impl Scoped<'a>,
     initial_state_fn: impl FnOnce() -> T + 'static,
 ) -> &'a RefCell<T> {
     cx.use_hook(|| RefCell::new(initial_state_fn()), |state| &*state, |_| {})
@@ -250,7 +250,7 @@ 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>,
+    cx: impl Scoped<'a>,
     initial_state_fn: impl FnOnce() -> State,
     _reducer: impl Fn(&mut State, Action),
 ) -> (&'a State, &'a Box<dyn Fn(Action)>) {
@@ -292,7 +292,7 @@ pub fn use_reducer<'a, 'c, State: 'static, Action: 'static>(
 /// 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>,
+    cx: impl Scoped<'a>,
     f: impl FnOnce() -> T,
 ) -> &'a UseModel<T> {
     cx.use_hook(
@@ -382,7 +382,7 @@ mod tests {
 }
 
 pub fn use_is_initialized<P>(cx: Context<P>) -> bool {
-    let val = use_ref(&cx, || false);
+    let val = use_ref(cx, || false);
     match *val.borrow() {
         true => true,
         false => {

+ 140 - 78
packages/core/src/virtual_dom.rs

@@ -571,97 +571,43 @@ impl Scope {
         Ok(())
     }
 
-    pub fn next_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
+    pub(crate) fn next_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
         self.frames.current_head_node()
     }
 
-    pub fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
+    pub(crate) fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
         self.frames.prev_head_node()
     }
 
-    pub fn cur_frame(&self) -> &BumpFrame {
+    pub(crate) fn cur_frame(&self) -> &BumpFrame {
         self.frames.cur_frame()
     }
 
-    pub fn root<'a>(&'a self) -> &'a VNode<'a> {
+    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, T> Scoped<'src> for Context<'src, T> {
-    fn get_scope(&self) -> &'src Scope {
-        self.scope
-    }
-}
-
-pub trait Scoped<'src>: Sized {
-    fn get_scope(&self) -> &'src Scope;
 
     /// Access the children elements passed into the component
-    fn children(&self) -> &'src [VNode<'src>] {
+    pub fn children(&self) -> &[VNode] {
         // We're re-casting the nodes back out
         // They don't really have a static lifetime
         unsafe {
-            let scope = self.get_scope();
+            let scope = self;
             let nodes = scope.child_nodes;
             nodes
         }
     }
 
     /// Create a subscription that schedules a future render for the reference component
-    fn schedule_update(&self) -> Rc<dyn Fn() + 'static> {
-        self.get_scope().event_channel.clone()
+    pub fn schedule_update(&self) -> Rc<dyn Fn() + 'static> {
+        self.event_channel.clone()
     }
 
-    fn schedule_effect(&self) -> Rc<dyn Fn() + 'static> {
+    pub fn schedule_effect(&self) -> Rc<dyn Fn() + 'static> {
         todo!()
     }
 
-    fn schedule_layout_effect(&self) {
+    pub fn schedule_layout_effect(&self) {
         todo!()
     }
 
@@ -680,11 +626,11 @@ pub trait Scoped<'src>: Sized {
     ///     cx.render(lazy_tree)
     /// }
     ///```
-    fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
-        self,
+    pub fn render<'src, F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
+        &'src self,
         lazy_nodes: LazyNodes<'src, F>,
     ) -> VNode<'src> {
-        let scope_ref = self.get_scope();
+        let scope_ref = self;
         let listener_id = &scope_ref.listener_idx;
         lazy_nodes.into_vnode(NodeFactory {
             scope_ref,
@@ -692,7 +638,6 @@ pub trait Scoped<'src>: Sized {
         })
     }
 
-    // impl<'scope> Context<'scope> {
     /// Store a value between renders
     ///
     /// - Initializer: closure used to create the initial hook state
@@ -709,8 +654,8 @@ pub trait Scoped<'src>: Sized {
     ///     )
     /// }
     /// ```
-    fn use_hook<InternalHookState: 'static, Output: 'src>(
-        &self,
+    pub fn use_hook<'src, InternalHookState: 'static, Output: 'src>(
+        &'src self,
 
         // The closure that builds the hook state
         initializer: impl FnOnce() -> InternalHookState,
@@ -722,7 +667,7 @@ pub trait Scoped<'src>: Sized {
         // TODO: add this to the "clean up" group for when the component is dropped
         _cleanup: impl FnOnce(InternalHookState),
     ) -> Output {
-        let scope = self.get_scope();
+        let scope = self;
 
         let idx = scope.hookidx.get();
 
@@ -771,7 +716,7 @@ Any function prefixed with "use" should not be called conditionally.
     ///
     ///
     fn use_create_context<T: 'static>(&self, init: impl Fn() -> T) {
-        let scope = self.get_scope();
+        let scope = self;
         let mut cxs = scope.shared_contexts.borrow_mut();
         let ty = TypeId::of::<T>();
 
@@ -800,12 +745,12 @@ Any function prefixed with "use" should not be called conditionally.
     }
 
     /// There are hooks going on here!
-    fn use_context<T: 'static>(&self) -> &'src Rc<T> {
+    pub fn use_context<'src, T: 'static>(&'src self) -> &'src Rc<T> {
         self.try_use_context().unwrap()
     }
 
     /// Uses a context, storing the cached value around
-    fn try_use_context<T: 'static>(&self) -> Result<&'src Rc<T>> {
+    pub fn try_use_context<'src, T: 'static>(&'src self) -> Result<&'src Rc<T>> {
         struct UseContextHook<C> {
             par: Option<Rc<C>>,
             we: Option<Weak<C>>,
@@ -817,8 +762,7 @@ Any function prefixed with "use" should not be called conditionally.
                 we: None as Option<Weak<T>>,
             },
             move |hook| {
-                let scope = self.get_scope();
-                let mut scope = Some(scope);
+                let mut scope = Some(self);
 
                 if let Some(we) = &hook.we {
                     if let Some(re) = we.upgrade() {
@@ -863,8 +807,12 @@ Any function prefixed with "use" should not be called conditionally.
         )
     }
 
-    fn suspend<Output: 'src, Fut: FnOnce(SuspendedContext, Output) -> VNode<'src> + 'src>(
-        &self,
+    pub fn suspend<
+        'src,
+        Output: 'src,
+        Fut: FnOnce(SuspendedContext, Output) -> VNode<'src> + 'src,
+    >(
+        &'src self,
         fut: &'src mut Pin<Box<dyn Future<Output = Output> + 'static>>,
         callback: Fut,
     ) -> VNode<'src> {
@@ -884,6 +832,120 @@ 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 {}