Pārlūkot izejas kodu

wip: remove cx.children. start to move towards a "children" field

Jonathan Kelley 3 gadi atpakaļ
vecāks
revīzija
7b97e009ec

+ 9 - 62
packages/core/examples/syntax2.rs

@@ -233,65 +233,12 @@ fn Child2<'a>((cx, props): Scope<'a, Child2Props>) -> Element<'a> {
     let b = cx.bump();
     let node: &'a VNode<'a> = b.alloc(node);
 
-    let children = ChildList { pthru: node };
-
-    // let c = VComponent {
-    //     key: todo!(),
-    //     associated_scope: todo!(),
-    //     is_static: todo!(),
-    //     user_fc: todo!(),
-    //     caller: todo!(),
-    //     children: todo!(),
-    //     comparator: todo!(),
-    //     drop_props: todo!(),
-    //     can_memoize: todo!(),
-    //     raw_props: todo!(),
-    // };
-
-    // Vcomp
-    // - borrowed
-    // - memoized
-
-    // cx.render({
-    //     NodeFactory::annotate_lazy(move |__cx: NodeFactory| -> VNode {
-    //         use dioxus_elements::{GlobalAttributes, SvgAttributes};
-    //         __cx.element(
-    //             dioxus_elements::div,
-    //             [],
-    //             [],
-    //             [
-    //                 __cx.component(ChildrenMemo, (), None, []),
-    //                 __cx.component(
-    //                     ChildrenComp,
-    //                     //
-    //                     ChildrenTest { node: children },
-    //                     None,
-    //                     [],
-    //                 ),
-    //                 // {
-    //                 //     let _props: &_ = __cx.bump().alloc(ChildrenTest { node: children });
-    //                 //     __cx.component_v2_borrowed(
-    //                 //         //
-    //                 //         move |c| ChildrenComp((c, _props)),
-    //                 //         ChildrenComp,
-    //                 //         _props,
-    //                 //     )
-    //                 // },
-    //                 // {
-    //                 //     let _props: &_ = __cx.bump().alloc(());
-    //                 //     __cx.component_v2_borrowed(move |c| ChildrenMemo((c, _props)))
-    //                 // },
-    //             ],
-    //             None,
-    //         )
-    //     })
-    // })
+    let children = Children { pthru: node };
+
     cx.render(rsx! {
         div {
             ChildrenComp {
-                ..ChildrenTest {
-                    node: children,
-                }
+                children: children
             }
         }
     })
@@ -299,21 +246,21 @@ fn Child2<'a>((cx, props): Scope<'a, Child2Props>) -> Element<'a> {
 
 #[derive(Props)]
 struct ChildrenTest<'a> {
-    node: ChildList<'a>,
+    children: Children<'a>,
 }
 
-struct ChildList<'a> {
+struct Children<'a> {
     pthru: &'a VNode<'a>,
 }
 
-impl<'a> Clone for ChildList<'a> {
+impl<'a> Clone for Children<'a> {
     fn clone(&self) -> Self {
         Self { pthru: self.pthru }
     }
 }
-impl<'a> Copy for ChildList<'a> {}
+impl<'a> Copy for Children<'a> {}
 
-impl<'a> IntoVNode<'a> for ChildList<'a> {
+impl<'a> IntoVNode<'a> for Children<'a> {
     fn into_vnode(self, _: NodeFactory<'a>) -> VNode<'a> {
         match self.pthru {
             VNode::Text(f) => VNode::Text(*f),
@@ -338,7 +285,7 @@ fn ChildrenComp<'a>((cx, props): Scope<'a, ChildrenTest<'a>>) -> Element<'a> {
                 // if the node's id is already assigned, then it's being passed in as a child
                 // in these instances, we don't worry about re-checking the node?
 
-                {Some(props.node)}
+                {Some(props.children)}
             }
         }
     })

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

@@ -2,8 +2,8 @@ use std::time::Duration;
 
 use dioxus_core::prelude::*;
 
-#[async_std::main]
-async fn main() {
+// #[async_std::main]
+fn main() {
     static App: FC<()> =
         |(cx, props)| cx.render(Some(Box::new(move |f| f.text(format_args!("hello")))));
 
@@ -11,7 +11,7 @@ async fn main() {
 
     dom.rebuild();
 
-    let deadline = async_std::task::sleep(Duration::from_millis(50));
+    // let deadline = async_std::task::sleep(Duration::from_millis(50));
 
     // let _fut = dom.run_with_deadline(|| deadline.);
 }

+ 1 - 1
packages/core/src/component.rs

@@ -138,6 +138,6 @@ impl EmptyBuilder {
 
 /// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern
 /// to initialize a component's props.
-pub fn fc_to_builder<T: Properties>(_: FC<T>) -> T::Builder {
+pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element<'a>) -> T::Builder {
     T::builder()
 }

+ 1 - 62
packages/core/src/context.rs

@@ -54,49 +54,6 @@ impl<'a> Deref for Context<'a> {
 }
 
 impl<'src> Context<'src> {
-    /// Access the children elements passed into the component
-    ///
-    /// This enables patterns where a component is passed children from its parent.
-    ///
-    /// ## Details
-    ///
-    /// Unlike React, Dioxus allows *only* lists of children to be passed from parent to child - not arbitrary functions
-    /// or classes. If you want to generate nodes instead of accepting them as a list, consider declaring a closure
-    /// on the props that takes Context.
-    ///
-    /// If a parent passes children into a component, the child will always re-render when the parent re-renders. In other
-    /// words, a component cannot be automatically memoized if it borrows nodes from its parent, even if the component's
-    /// props are valid for the static lifetime.
-    ///
-    /// ## Example
-    ///
-    /// ```rust
-    /// const App: FC<()> = |(cx, props)|{
-    ///     cx.render(rsx!{
-    ///         CustomCard {
-    ///             h1 {}
-    ///             p {}
-    ///         }
-    ///     })
-    /// }
-    ///
-    /// const CustomCard: FC<()> = |(cx, props)|{
-    ///     cx.render(rsx!{
-    ///         div {
-    ///             h1 {"Title card"}
-    ///             {cx.children()}
-    ///         }
-    ///     })
-    /// }
-    /// ```
-    ///
-    /// ## Notes:
-    ///
-    /// This method returns a "ScopeChildren" object. This object is copy-able and preserve the correct lifetime.
-    pub fn children(&self) -> ScopeChildren<'src> {
-        self.scope.child_nodes()
-    }
-
     /// Create a subscription that schedules a future render for the reference component
     ///
     /// ## Notice: you should prefer using prepare_update and get_scope_id
@@ -147,28 +104,10 @@ impl<'src> Context<'src> {
     pub fn render(
         self,
         lazy_nodes: Option<Box<dyn FnOnce(NodeFactory<'src>) -> VNode<'src> + '_>>,
-        // lazy_nodes: Option<Box<dyn FnOnce(NodeFactory) -> VNode + '_>>,
-        // lazy_nodes: Box<dyn FnOnce(NodeFactory<'src>) -> VNode<'src> + '_>,
     ) -> Option<VNode<'src>> {
-        // pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
-        //     self,
-        //     lazy_nodes: LazyNodes<'src, F>,
-        // ) -> Option<VNode<'src>> {
         let bump = &self.scope.frames.wip_frame().bump;
-        // Some(lazy_nodes.into_vnode(NodeFactory { bump }))
-
         let factory = NodeFactory { bump };
-        // let vnode = lazy_nodes(factory);
-
-        match lazy_nodes {
-            Some(f) => Some(f(factory)),
-            None => None,
-        }
-
-        // match lazy_nodes {
-        //     None => todo!(),
-        // }
-        // Some(lazy_nodes)
+        lazy_nodes.map(|f| f(factory))
     }
 
     /// `submit_task` will submit the future to be polled.

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

@@ -348,7 +348,6 @@ impl<'bump> DiffMachine<'bump> {
                 Some(parent_idx),
                 parent_scope.height + 1,
                 parent_scope.subtree(),
-                ScopeChildren(vcomponent.children),
                 shared,
             )
         });
@@ -555,7 +554,7 @@ impl<'bump> DiffMachine<'bump> {
 
             // make sure the component's caller function is up to date
             let scope = self.vdom.get_scope_mut(scope_addr).unwrap();
-            scope.update_scope_dependencies(new.caller, ScopeChildren(new.children));
+            scope.update_scope_dependencies(new.caller);
 
             // React doesn't automatically memoize, but we do.
             let props_are_the_same = old.comparator.unwrap();

+ 25 - 81
packages/core/src/nodes.rs

@@ -638,47 +638,6 @@ pub trait IntoVNode<'a> {
     fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;
 }
 
-/// Child nodes of the parent component.
-///
-/// # Example
-///
-/// ```rust
-/// let children = cx.children();
-/// let first_node = &children[0];
-/// rsx!{
-///     h1 { {first_node} }
-///     p { {&children[1..]} }
-/// }
-/// ```
-///
-pub struct ScopeChildren<'a>(pub &'a [VNode<'a>]);
-
-impl Copy for ScopeChildren<'_> {}
-
-impl<'a> Clone for ScopeChildren<'a> {
-    fn clone(&self) -> Self {
-        ScopeChildren(self.0)
-    }
-}
-
-impl ScopeChildren<'_> {
-    // dangerous method - used to fix the associated lifetime
-    pub(crate) unsafe fn extend_lifetime(self) -> ScopeChildren<'static> {
-        std::mem::transmute(self)
-    }
-
-    // dangerous method - used to fix the associated lifetime
-    pub(crate) unsafe fn shorten_lifetime<'a>(self) -> ScopeChildren<'a> {
-        std::mem::transmute(self)
-    }
-}
-
-// impl IntoVNodeList for ScopeChildren<'_> {
-//     fn into_vnode_list<'a>(self, _: NodeFactory<'a>) -> &'a [VNode<'a>] {
-//         self.0
-//     }
-// }
-
 // For the case where a rendered VNode is passed into the rsx! macro through curly braces
 impl<'a> IntoIterator for VNode<'a> {
     type Item = VNode<'a>;
@@ -690,34 +649,31 @@ impl<'a> IntoIterator for VNode<'a> {
 
 // TODO: do we even need this? It almost seems better not to
 // // For the case where a rendered VNode is passed into the rsx! macro through curly braces
-// impl IntoVNode for VNode<'_> {
-//     fn into_vnode<'a>(self, _: NodeFactory<'a>) -> VNode<'a> {
-//         self
-//     }
-// }
+impl<'a> IntoVNode<'a> for VNode<'a> {
+    fn into_vnode(self, _: NodeFactory<'a>) -> VNode<'a> {
+        self
+    }
+}
 
 // Conveniently, we also support "null" (nothing) passed in
-// impl IntoVNode for () {
-//     fn into_vnode(self, cx: NodeFactory) -> VNode {
-//         cx.fragment_from_iter(None as Option<VNode>)
-//     }
-// }
-
-// // Conveniently, we also support "None"
-// impl IntoVNode for Option<()> {
-//     fn into_vnode(self, cx: NodeFactory) -> VNode {
-//         cx.fragment_from_iter(None as Option<VNode>)
-//     }
-// }
-
-// impl IntoVNode for Option<VNode<'_>> {
-//     fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
-//         match self {
-//             Some(n) => n,
-//             None => cx.fragment_from_iter(None as Option<VNode>),
-//         }
-//     }
-// }
+impl IntoVNode<'_> for () {
+    fn into_vnode(self, cx: NodeFactory) -> VNode {
+        cx.fragment_from_iter(None as Option<VNode>)
+    }
+}
+
+// Conveniently, we also support "None"
+impl IntoVNode<'_> for Option<()> {
+    fn into_vnode(self, cx: NodeFactory) -> VNode {
+        cx.fragment_from_iter(None as Option<VNode>)
+    }
+}
+
+impl<'a> IntoVNode<'a> for Option<VNode<'a>> {
+    fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
+        self.unwrap_or_else(|| cx.fragment_from_iter(None as Option<VNode>))
+    }
+}
 
 pub fn annotate_lazy<'a, 'b, F>(f: F) -> Option<Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b>>
 where
@@ -729,11 +685,7 @@ where
 impl<'a> IntoVNode<'a> for Option<Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + '_>> {
     fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
         match self {
-            Some(n) => {
-                //
-                // n.into_vnode(cx)
-                n(cx)
-            }
+            Some(lazy) => lazy(cx),
             None => VNode::Fragment(VFragment {
                 children: &[],
                 is_static: false,
@@ -749,20 +701,12 @@ impl<'a> IntoVNode<'a> for Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + '_> {
     }
 }
 
-// impl<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>> IntoVNode<'a> for Option<LazyNodes<'a, F>> {
-//     fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
-//         match self {
-//             Some(n) => n.into_vnode(cx),
-//             None => cx.fragment_from_iter(None as Option<VNode>),
-//         }
-//     }
-// }
-
 impl IntoVNode<'_> for &'static str {
     fn into_vnode(self, cx: NodeFactory) -> VNode {
         cx.static_text(self)
     }
 }
+
 impl IntoVNode<'_> for Arguments<'_> {
     fn into_vnode(self, cx: NodeFactory) -> VNode {
         cx.text(self)

+ 0 - 13
packages/core/src/scope.rs

@@ -29,7 +29,6 @@ pub struct ScopeInner {
     // Nodes
     pub(crate) frames: ActiveFrame,
     pub(crate) caller: *const dyn for<'b> Fn(&'b ScopeInner) -> Element<'b>,
-    pub(crate) child_nodes: ScopeChildren<'static>,
 
     /*
     we care about:
@@ -181,11 +180,8 @@ impl ScopeInner {
         parent_idx: Option<ScopeId>,
         height: u32,
         subtree: u32,
-        child_nodes: ScopeChildren,
         shared: EventChannel,
     ) -> Self {
-        let child_nodes = unsafe { child_nodes.extend_lifetime() };
-
         let schedule_any_update = shared.schedule_any_immediate.clone();
 
         let memoized_updater = Rc::new(move || schedule_any_update(our_arena_idx));
@@ -198,7 +194,6 @@ impl ScopeInner {
         Self {
             memoized_updater,
             shared,
-            child_nodes,
             caller,
             parent_idx,
             our_arena_idx,
@@ -218,18 +213,10 @@ impl ScopeInner {
     pub(crate) fn update_scope_dependencies<'creator_node>(
         &mut self,
         caller: &'creator_node dyn for<'b> Fn(&'b ScopeInner) -> Element<'b>,
-        child_nodes: ScopeChildren,
     ) {
         log::debug!("Updating scope dependencies {:?}", self.our_arena_idx);
         let caller = caller as *const _;
         self.caller = unsafe { std::mem::transmute(caller) };
-
-        let child_nodes = unsafe { child_nodes.extend_lifetime() };
-        self.child_nodes = child_nodes;
-    }
-
-    pub(crate) fn child_nodes(&self) -> ScopeChildren {
-        unsafe { self.child_nodes.shorten_lifetime() }
     }
 
     /// This method cleans up any references to data held within our hook list. This prevents mutable aliasing from

+ 14 - 7
packages/core/src/test_dom.rs

@@ -21,7 +21,10 @@ impl TestDom {
         NodeFactory::new(&self.bump)
     }
 
-    pub fn render_direct<'a>(&'a self, lazy_nodes: Element<'a>) -> VNode<'a>
+    pub fn render_direct<'a>(
+        &'a self,
+        lazy_nodes: Option<Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + '_>>,
+    ) -> VNode<'a>
 // where
     //     F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
     {
@@ -29,7 +32,10 @@ impl TestDom {
         // lazy_nodes.into_vnode(NodeFactory::new(&self.bump))
     }
 
-    pub fn render<'a>(&'a self, lazy_nodes: Element<'a>) -> &'a VNode<'a>
+    pub fn render<'a>(
+        &'a self,
+        lazy_nodes: Option<Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + '_>>,
+    ) -> &'a VNode<'a>
 // where
     //     F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
     {
@@ -45,7 +51,10 @@ impl TestDom {
         machine.mutations
     }
 
-    pub fn create<'a>(&'a self, left: Element<'a>) -> Mutations<'a>
+    pub fn create<'a>(
+        &'a self,
+        left: Option<Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + '_>>,
+    ) -> Mutations<'a>
 // pub fn create<'a, F1>(&'a self, left: LazyNodes<'a, F1>) -> Mutations<'a>
     // where
     //     F1: FnOnce(NodeFactory<'a>) -> VNode<'a>,
@@ -63,10 +72,8 @@ impl TestDom {
 
     pub fn lazy_diff<'a>(
         &'a self,
-        left: Element<'a>,
-        right: Element<'a>,
-        // left: LazyNodes<'a, F1>,
-        // right: LazyNodes<'a, F2>,
+        left: Option<Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + '_>>,
+        right: Option<Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a> + '_>>,
     ) -> (Mutations<'a>, Mutations<'a>)
 // where
     //     F1: FnOnce(NodeFactory<'a>) -> VNode<'a>,

+ 1 - 2
packages/core/src/virtual_dom.rs

@@ -158,7 +158,6 @@ impl VirtualDom {
                 None,
                 0,
                 0,
-                ScopeChildren(&[]),
                 scheduler.pool.channel.clone(),
             )
         });
@@ -226,7 +225,7 @@ impl VirtualDom {
                     std::mem::transmute(root((Context { scope }, props)))
                 });
 
-            root_scope.update_scope_dependencies(&root_caller, ScopeChildren(&[]));
+            root_scope.update_scope_dependencies(&root_caller);
 
             drop(root_props);
 

+ 30 - 16
packages/core/tests/create_dom.rs

@@ -22,13 +22,13 @@ fn new_dom<P: 'static + Send>(app: FC<P>, props: P) -> VirtualDom {
 #[test]
 fn test_original_diff() {
     static APP: FC<()> = |(cx, props)| {
-        rsx! {
+        cx.render(rsx! {
             div {
                 div {
                     "Hello, world!"
                 }
             }
-        }
+        })
     };
 
     let mut dom = new_dom(APP, ());
@@ -58,7 +58,7 @@ fn test_original_diff() {
 #[test]
 fn create() {
     static APP: FC<()> = |(cx, props)| {
-        rsx! {
+        cx.render(rsx! {
             div {
                 div {
                     "Hello, world!"
@@ -72,7 +72,7 @@ fn create() {
                     }
                 }
             }
-        }
+        })
     };
 
     let mut dom = new_dom(APP, ());
@@ -121,11 +121,11 @@ fn create() {
 #[test]
 fn create_list() {
     static APP: FC<()> = |(cx, props)| {
-        rsx! {
+        cx.render(rsx! {
             {(0..3).map(|f| rsx!{ div {
                 "hello"
             }})}
-        }
+        })
     };
 
     let mut dom = new_dom(APP, ());
@@ -170,12 +170,12 @@ fn create_list() {
 #[test]
 fn create_simple() {
     static APP: FC<()> = |(cx, props)| {
-        rsx! {
+        cx.render(rsx! {
             div {}
             div {}
             div {}
             div {}
-        }
+        })
     };
 
     let mut dom = new_dom(APP, ());
@@ -208,19 +208,19 @@ fn create_simple() {
 #[test]
 fn create_components() {
     static App: FC<()> = |(cx, props)| {
-        rsx! {
+        cx.render(rsx! {
             Child { "abc1" }
             Child { "abc2" }
             Child { "abc3" }
-        }
+        })
     };
 
     static Child: FC<()> = |(cx, props)| {
-        rsx! {
+        cx.render(rsx! {
             h1 {}
             div { {cx.children()} }
             p {}
-        }
+        })
     };
 
     let mut dom = new_dom(App, ());
@@ -269,10 +269,10 @@ fn create_components() {
 #[test]
 fn anchors() {
     static App: FC<()> = |(cx, props)| {
-        rsx! {
+        cx.render(rsx! {
             {true.then(|| rsx!{ div { "hello" } })}
             {false.then(|| rsx!{ div { "goodbye" } })}
-        }
+        })
     };
 
     let mut dom = new_dom(App, ());
@@ -303,9 +303,23 @@ fn suspended() {
             || async {
                 //
             },
-            |cx, p| rsx! { "hi "},
+            |cx, p| todo!(),
+            // |cx, p| rsx! { "hi "},
         );
-        rsx! { {val} }
+
+        // let prom = use_task(fetch());
+
+        // Value {
+        //     a: value.await,
+        //     b: value.await,
+        //     f: a.await
+        //     div {
+        //         div {
+        //             hidden: should_hide.await,
+        //         }
+        //     }
+        // }
+        cx.render(rsx! { {val} })
     };
 
     let mut dom = new_dom(App, ());

+ 15 - 14
packages/core/tests/diffing.rs

@@ -433,11 +433,11 @@ fn keyed_diffing_order() {
     let dom = new_dom();
 
     let left = rsx!(
-        {(0..5).map(|f| {rsx! { div { key: "{f}"  }}})}
+        // {(0..5).map(|f| {rsx! { div { key: "{f}"  }}})}
         p {"e"}
     );
     let right = rsx!(
-        {(0..2).map(|f| {rsx! { div { key: "{f}" }}})}
+        {(0..2).map(|f| rsx! { div { key: "{f}" }})}
         p {"e"}
     );
 
@@ -807,16 +807,17 @@ fn controlled_keyed_diffing_out_of_order_max_test() {
 fn suspense() {
     let dom = new_dom();
 
-    let edits = dom.create(Some(LazyNodes::new(|f| {
-        use std::cell::{Cell, RefCell};
-        VNode::Suspended(f.bump().alloc(VSuspended {
-            task_id: 0,
-            callback: RefCell::new(None),
-            dom_id: Cell::new(None),
-        }))
-    })));
-    assert_eq!(
-        edits.edits,
-        [CreatePlaceholder { root: 0 }, AppendChildren { many: 1 }]
-    );
+    todo!()
+    // let edits = dom.create(Some(LazyNodes::new(|f| {
+    //     use std::cell::{Cell, RefCell};
+    //     VNode::Suspended(f.bump().alloc(VSuspended {
+    //         task_id: 0,
+    //         callback: RefCell::new(None),
+    //         dom_id: Cell::new(None),
+    //     }))
+    // })));
+    // assert_eq!(
+    //     edits.edits,
+    //     [CreatePlaceholder { root: 0 }, AppendChildren { many: 1 }]
+    // );
 }

+ 1 - 1
packages/core/tests/lifecycle.rs

@@ -22,7 +22,7 @@ fn manual_diffing() {
 
     static App: FC<AppProps> = |(cx, props)| {
         let val = props.value.lock().unwrap();
-        rsx! { div { "{val}" } }
+        cx.render(rsx! { div { "{val}" } })
     };
 
     let value = Arc::new(Mutex::new("Hello"));

+ 2 - 2
packages/core/tests/sharedstate.rs

@@ -15,12 +15,12 @@ fn shared_state_test() {
 
     static App: FC<()> = |(cx, props)| {
         cx.provide_state(MySharedState("world!"));
-        rsx!(Child {})
+        cx.render(rsx!(Child {}))
     };
 
     static Child: FC<()> = |(cx, props)| {
         let shared = cx.consume_state::<MySharedState>()?;
-        rsx!("Hello, {shared.0}")
+        cx.render(rsx!("Hello, {shared.0}"))
     };
 
     let mut dom = VirtualDom::new(App);

+ 14 - 13
packages/core/tests/vdom_rebuild.rs

@@ -19,7 +19,7 @@ use dioxus_html as dioxus_elements;
 fn app_runs() {
     static App: FC<()> = |(cx, props)| {
         //
-        rsx!( div{"hello"} )
+        cx.render(rsx!( div{"hello"} ))
     };
     let mut vdom = VirtualDom::new(App);
     let edits = vdom.rebuild();
@@ -29,10 +29,10 @@ fn app_runs() {
 #[test]
 fn fragments_work() {
     static App: FC<()> = |(cx, props)| {
-        rsx!(
+        cx.render(rsx!(
             div{"hello"}
             div{"goodbye"}
-        )
+        ))
     };
     let mut vdom = VirtualDom::new(App);
     let edits = vdom.rebuild();
@@ -43,10 +43,10 @@ fn fragments_work() {
 #[test]
 fn lists_work() {
     static App: FC<()> = |(cx, props)| {
-        rsx!(
+        cx.render(rsx!(
             h1 {"hello"}
             {(0..6).map(|f| rsx!(span{ "{f}" }))}
-        )
+        ))
     };
     let mut vdom = VirtualDom::new(App);
     let edits = vdom.rebuild();
@@ -56,11 +56,11 @@ fn lists_work() {
 #[test]
 fn conditional_rendering() {
     static App: FC<()> = |(cx, props)| {
-        rsx!(
+        cx.render(rsx!(
             h1 {"hello"}
             {true.then(|| rsx!(span{ "a" }))}
             {false.then(|| rsx!(span{ "b" }))}
-        )
+        ))
     };
     let mut vdom = VirtualDom::new(App);
 
@@ -73,16 +73,16 @@ fn conditional_rendering() {
 #[test]
 fn child_components() {
     static App: FC<()> = |(cx, props)| {
-        rsx!(
+        cx.render(rsx!(
             {true.then(|| rsx!(Child { }))}
             {false.then(|| rsx!(Child { }))}
-        )
+        ))
     };
     static Child: FC<()> = |(cx, props)| {
-        rsx!(
+        cx.render(rsx!(
             h1 {"hello"}
             h1 {"goodbye"}
-        )
+        ))
     };
     let mut vdom = VirtualDom::new(App);
     let edits = vdom.rebuild();
@@ -92,8 +92,9 @@ fn child_components() {
 #[test]
 fn suspended_works() {
     static App: FC<()> = |(cx, props)| {
-        let title = use_suspense(cx, || async { "bob" }, move |cx, f| rsx! { "{f}"});
-        rsx!("hello" { title })
+        let title = use_suspense(cx, || async { "bob" }, move |cx, f| todo!());
+        // let title = use_suspense(cx, || async { "bob" }, move |cx, f| rsx! { "{f}"});
+        cx.render(rsx!("hello" { title }))
     };
 
     let mut vdom = VirtualDom::new(App);