Jelajahi Sumber

fix components that take no arguments

Evan Almloff 1 tahun lalu
induk
melakukan
1794debf79

+ 2 - 2
packages/core/compile_tests/props_safety.rs

@@ -17,8 +17,8 @@ struct Testing<'a> {
     borrowed: &'a RefCell<Vec<Element>>,
 }
 
-fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element {
-    let Testing { borrowed } = cx.props;
+fn unsafe_child_component<'a>(cx: Testing) -> Element {
+    let Testing { borrowed } = cx;
     let borrowed_temporary_data =
         cx.use_hook(|| String::from("This data is only valid for the lifetime of the child"));
 

+ 2 - 2
packages/core/compile_tests/props_safety_temporary_values.rs

@@ -17,8 +17,8 @@ struct Testing<'a> {
     borrowed: &'a Vec<u32>,
 }
 
-fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element {
+fn unsafe_child_component<'a>(cx: Testing) -> Element {
     cx.render(rsx! {
-        div { "{cx.props.borrowed:?}" }
+        div { "{cx.borrowed:?}" }
     })
 }

+ 3 - 3
packages/core/src/error_boundary.rs

@@ -139,7 +139,7 @@ impl ErrorBoundary {
 ///
 /// ```rust, ignore
 /// #[component]
-/// fn App(cx: Scope, count: String) -> Element {
+/// fn App( count: String) -> Element {
 ///     let id: i32 = count.parse().throw()?;
 ///
 ///     cx.render(rsx! {
@@ -164,7 +164,7 @@ pub trait Throw<S = ()>: Sized {
     ///
     /// ```rust, ignore
     /// #[component]
-    /// fn App(cx: Scope, count: String) -> Element {
+    /// fn App( count: String) -> Element {
     ///     let id: i32 = count.parse().throw()?;
     ///
     ///     cx.render(rsx! {
@@ -187,7 +187,7 @@ pub trait Throw<S = ()>: Sized {
     ///
     /// ```rust, ignore
     /// #[component]
-    /// fn App(cx: Scope, count: String) -> Element {
+    /// fn App( count: String) -> Element {
     ///     let id: i32 = count.parse().throw()?;
     ///
     ///     cx.render(rsx! {

+ 2 - 2
packages/core/src/events.rs

@@ -145,10 +145,10 @@ impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
 ///     onclick: EventHandler<'a, MouseEvent>,
 /// }
 ///
-/// fn MyComponent(cx: Scope<'a, MyProps<'a>>) -> Element {
+/// fn MyComponent(cx: MyProps) -> Element {
 ///     cx.render(rsx!{
 ///         button {
-///             onclick: move |evt| cx.props.onclick.call(evt),
+///             onclick: move |evt| cx.onclick.call(evt),
 ///         }
 ///     })
 /// }

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

@@ -80,7 +80,7 @@ impl<const A: bool> FragmentBuilder<A> {
 ///     cx.render(rsx!{
 ///         div {
 ///             h1 {"Title card"}
-///             {cx.props.children}
+///             {cx.children}
 ///         }
 ///     })
 /// }

+ 33 - 2
packages/core/src/properties.rs

@@ -67,8 +67,39 @@ 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>(_: fn(T) -> Element) -> T::Builder {
-    T::builder()
+pub fn fc_to_builder<F: HasProps<P>, P>(
+    _: F,
+) -> <<F as HasProps<P>>::Props as Properties>::Builder {
+    F::Props::builder()
+}
+
+/// A function pointer that can be used to create a component.
+pub trait HasProps<P> {
+    type Props: Properties;
+}
+
+impl<T: Properties, F: Fn(T) -> Element> HasProps<(T,)> for F {
+    type Props = T;
+}
+
+#[doc(hidden)]
+pub struct ZeroElementMarker;
+impl<F: Fn() -> Element> HasProps<ZeroElementMarker> for F {
+    type Props = ();
+}
+
+#[test]
+fn test_empty_builder() {
+    fn app() -> Element {
+        render!(div {})
+    }
+    fn app2(_: ()) -> Element {
+        render!(div {})
+    }
+    let builder = fc_to_builder(app);
+    builder.build();
+    let builder = fc_to_builder(app2);
+    builder.build();
 }
 
 #[cfg(not(miri))]

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

@@ -132,7 +132,7 @@ impl Runtime {
 /// }
 ///
 /// fn Component(cx: Scope<ComponentProps>) -> Element {
-///     cx.use_hook(|| RuntimeGuard::new(cx.props.runtime.clone()));
+///     cx.use_hook(|| RuntimeGuard::new(cx.runtime.clone()));
 ///
 ///     render! { div {} }
 /// }

+ 7 - 7
packages/core/src/virtual_dom.rs

@@ -36,7 +36,7 @@ use std::{any::Any, cell::Cell, collections::BTreeSet, future::Future, rc::Rc};
 ///
 /// fn App(cx: Scope<AppProps>) -> Element {
 ///     cx.render(rsx!(
-///         div {"hello, {cx.props.title}"}
+///         div {"hello, {cx.title}"}
 ///     ))
 /// }
 /// ```
@@ -58,25 +58,25 @@ use std::{any::Any, cell::Cell, collections::BTreeSet, future::Future, rc::Rc};
 /// fn App(cx: Scope<AppProps>) -> Element {
 ///     cx.render(rsx!(
 ///         NavBar { routes: ROUTES }
-///         Title { "{cx.props.title}" }
+///         Title { "{cx.title}" }
 ///         Footer {}
 ///     ))
 /// }
 ///
 /// #[component]
-/// fn NavBar(cx: Scope, routes: &'static str) -> Element {
+/// fn NavBar( routes: &'static str) -> Element {
 ///     cx.render(rsx! {
 ///         div { "Routes: {routes}" }
 ///     })
 /// }
 ///
 /// #[component]
-/// fn Footer(cx: Scope) -> Element {
+/// fn Footer() -> Element {
 ///     cx.render(rsx! { div { "Footer" } })
 /// }
 ///
 /// #[component]
-/// fn Title<'a>(cx: Scope<'a>, children: Element) -> Element {
+/// fn Title<'a>( children: Element) -> Element {
 ///     cx.render(rsx! {
 ///         div { id: "title", children }
 ///     })
@@ -218,7 +218,7 @@ impl VirtualDom {
     ///
     /// # Example
     /// ```rust, ignore
-    /// fn Example(cx: Scope) -> Element  {
+    /// fn Example() -> Element  {
     ///     cx.render(rsx!( div { "hello world" } ))
     /// }
     ///
@@ -248,7 +248,7 @@ impl VirtualDom {
     /// }
     ///
     /// fn Example(cx: Scope<SomeProps>) -> Element  {
-    ///     cx.render(rsx!{ div{ "hello {cx.props.name}" } })
+    ///     cx.render(rsx!{ div{ "hello {cx.name}" } })
     /// }
     ///
     /// let dom = VirtualDom::new(Example);

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

@@ -23,7 +23,7 @@ fn attrs_cycle() {
     let bump = Bump::new();
 
     assert_eq!(
-        dom.rebuild_to_vec_to_vec().santize().edits,
+        dom.rebuild_to_vec().santize().edits,
         [
             LoadTemplate { name: "template", index: 0, id: ElementId(1,) },
             AppendChildren { m: 1, id: ElementId(0) },

+ 5 - 5
packages/core/tests/borrowedstate.rs

@@ -21,7 +21,7 @@ fn test_borrowed_state() {
     );
 }
 
-fn Parent(cx: Scope) -> Element {
+fn Parent() -> Element {
     let w1 = cx.use_hook(|| String::from("w1"));
 
     render! {
@@ -34,11 +34,11 @@ struct ChildProps<'a> {
     name: &'a str,
 }
 
-fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element {
+fn Child<'a>(cx: ChildProps) -> Element {
     render! {
         div {
             h1 { "it's nested" }
-            Child2 { name: cx.props.name }
+            Child2 { name: cx.name }
         }
     }
 }
@@ -48,6 +48,6 @@ struct Grandchild<'a> {
     name: &'a str,
 }
 
-fn Child2<'a>(cx: Scope<'a, Grandchild<'a>>) -> Element {
-    render!( div { "Hello {cx.props.name}!" } )
+fn Child2<'a>(cx: Grandchild) -> Element {
+    render!( div { "Hello {cx.name}!" } )
 }

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

@@ -9,11 +9,11 @@ fn state_shares() {
         render!(child_1 {})
     }
 
-    fn child_1(cx: Scope) -> Element {
+    fn child_1() -> Element {
         render!(child_2 {})
     }
 
-    fn child_2(cx: Scope) -> Element {
+    fn child_2() -> Element {
         let value = cx.consume_context::<i32>().unwrap();
         render!("Value is {value}")
     }

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

@@ -134,10 +134,10 @@ fn create_components() {
         children: Element,
     }
 
-    fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element {
+    fn Child<'a>(cx: ChildProps) -> Element {
         render! {
             h1 {}
-            div { &cx.props.children }
+            div { &cx.children }
             p {}
         }
     }

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

@@ -75,7 +75,7 @@ fn fragments_across_components() {
         }
     }
 
-    fn demo_child(cx: Scope) -> Element {
+    fn demo_child() -> Element {
         let world = "world";
         render! { "hellO!", world }
     }

+ 2 - 5
packages/core/tests/create_passthru.rs

@@ -5,7 +5,6 @@ use dioxus_core::ElementId;
 /// Should push the text node onto the stack and modify it
 #[test]
 fn nested_passthru_creates() {
-    #[component]
     fn App() -> Element {
         render! {
             PassThru {
@@ -17,7 +16,7 @@ fn nested_passthru_creates() {
     }
 
     #[component]
-    fn PassThru<'a>(cx: Scope<'a>, children: Element) -> Element {
+    fn PassThru<'a>(children: Element) -> Element {
         render!(children)
     }
 
@@ -38,7 +37,6 @@ fn nested_passthru_creates() {
 /// Take note on how we don't spit out the template for child_comp since it's entirely dynamic
 #[test]
 fn nested_passthru_creates_add() {
-    #[component]
     fn App() -> Element {
         render! {
             ChildComp {
@@ -55,7 +53,7 @@ fn nested_passthru_creates_add() {
     }
 
     #[component]
-    fn ChildComp<'a>(cx: Scope, children: Element) -> Element {
+    fn ChildComp<'a>(children: Element) -> Element {
         render! {children}
     }
 
@@ -80,7 +78,6 @@ fn nested_passthru_creates_add() {
 /// note that the template is all dynamic roots - so it doesn't actually get cached as a template
 #[test]
 fn dynamic_node_as_root() {
-    #[component]
     fn App() -> Element {
         let a = 123;
         let b = 456;

+ 4 - 4
packages/core/tests/diff_component.rs

@@ -37,21 +37,21 @@ fn component_swap() {
         }
     }
 
-    fn nav_bar(cx: Scope) -> Element {
+    fn nav_bar() -> Element {
         render! {
             h1 { "NavBar", (0..3).map(|_| render!(nav_link {})) }
         }
     }
 
-    fn nav_link(cx: Scope) -> Element {
+    fn nav_link() -> Element {
         render!( h1 { "nav_link" } )
     }
 
-    fn dash_board(cx: Scope) -> Element {
+    fn dash_board() -> Element {
         render!( div { "dashboard" } )
     }
 
-    fn dash_results(cx: Scope) -> Element {
+    fn dash_results() -> Element {
         render!( div { "results" } )
     }
 

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

@@ -19,11 +19,11 @@ fn app() -> Element {
     }
 }
 
-fn NoneChild(_cx: Scope) -> Element {
+fn NoneChild(_) -> Element {
     None
 }
 
-fn ThrowChild(cx: Scope) -> Element {
+fn ThrowChild() -> Element {
     Err(std::io::Error::new(std::io::ErrorKind::AddrInUse, "asd")).throw()?;
 
     let _g: i32 = "123123".parse().throw()?;

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

@@ -67,7 +67,7 @@ fn app() -> Element {
     }
 }
 
-fn problematic_child(cx: Scope) -> Element {
+fn problematic_child() -> Element {
     render! {
         button { onclick: move |evt| {
                 println!("bottom clicked");

+ 5 - 7
packages/core/tests/fuzzing.rs

@@ -238,10 +238,10 @@ struct BorrowedDepthProps<'a> {
     inner: DepthProps,
 }
 
-fn create_random_element_borrowed<'a>(cx: Scope<'a, BorrowedDepthProps<'a>>) -> Element {
-    println!("{}", cx.props.borrow);
+fn create_random_element_borrowed<'a>(cx: BorrowedDepthProps) -> Element {
+    println!("{}", cx.borrow);
     let bump = cx.bump();
-    let allocated = bump.alloc(Scoped { scope: cx, props: &cx.props.inner });
+    let allocated = bump.alloc(Scoped { scope: cx, props: &cx.inner });
     create_random_element(allocated)
 }
 
@@ -255,7 +255,7 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
     if rand::random::<usize>() % 10 == 0 {
         cx.needs_update();
     }
-    let range = if cx.props.root { 2 } else { 3 };
+    let range = if cx.root { 2 } else { 3 };
     let node = match rand::random::<usize>() % range {
         0 | 1 => {
             let (template, dynamic_node_types) = create_random_template(Box::leak(
@@ -283,9 +283,7 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
                             DynamicNodeType::Text => DynamicNode::Text(VText::new(Box::leak(
                                 format!("{}", rand::random::<usize>()).into_boxed_str(),
                             ))),
-                            DynamicNodeType::Other => {
-                                create_random_dynamic_node(cx, cx.props.depth + 1)
-                            }
+                            DynamicNodeType::Other => create_random_dynamic_node(cx, cx.depth + 1),
                         })
                         .collect();
                     cx.bump().alloc(dynamic_nodes)

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

@@ -2,7 +2,7 @@ use bumpalo::Bump;
 use dioxus::core::{ElementId, Mutation};
 use dioxus::prelude::*;
 
-fn basic_syntax_is_a_template(cx: Scope) -> Element {
+fn basic_syntax_is_a_template() -> Element {
     let asd = 123;
     let var = 123;
 

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

@@ -17,7 +17,7 @@ fn manual_diffing() {
     }
 
     fn app(cx: Scope<AppProps>) -> Element {
-        let val = cx.props.value.lock().unwrap();
+        let val = cx.value.lock().unwrap();
         render! { div { "{val}" } }
     };
 
@@ -96,7 +96,7 @@ fn events_generate() {
 //         })
 //     };
 
-//     fn Child(cx: Scope) -> Element {
+//     fn Child() -> Element {
 //         println!("Running child");
 //         render_without_templates! {
 //             h1 {}

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

@@ -25,7 +25,7 @@ fn miri_rollover() {
 
 #[component]
 fn App() -> Element {
-    let mut idx = use_state(cx, || 0);
+    let mut idx = use_signal(|| 0);
     let onhover = |_| println!("go!");
 
     render! {
@@ -48,6 +48,6 @@ fn App() -> Element {
 }
 
 #[component]
-fn ChildExample<'a>(cx: Scope<'a>, i: i32, onhover: EventHandler<'a, MouseEvent>) -> Element {
+fn ChildExample<'a>(i: i32, onhover: EventHandler<'a, MouseEvent>) -> Element {
     render! { li { onmouseover: move |e| onhover.call(e), "{i}" } }
 }

+ 4 - 9
packages/core/tests/miri_simple.rs

@@ -2,7 +2,6 @@ use dioxus::prelude::*;
 
 #[test]
 fn app_drops() {
-    #[component]
     fn App() -> Element {
         render! { div {} }
     }
@@ -16,7 +15,6 @@ fn app_drops() {
 
 #[test]
 fn hooks_drop() {
-    #[component]
     fn App() -> Element {
         cx.use_hook(|| String::from("asd"));
         cx.use_hook(|| String::from("asd"));
@@ -35,7 +33,6 @@ fn hooks_drop() {
 
 #[test]
 fn contexts_drop() {
-    #[component]
     fn App() -> Element {
         cx.provide_context(String::from("asd"));
 
@@ -45,7 +42,7 @@ fn contexts_drop() {
     }
 
     #[component]
-    fn ChildComp(cx: Scope) -> Element {
+    fn ChildComp() -> Element {
         let el = cx.consume_context::<String>().unwrap();
 
         render! { div { "hello {el}" } }
@@ -60,7 +57,6 @@ fn contexts_drop() {
 
 #[test]
 fn tasks_drop() {
-    #[component]
     fn App() -> Element {
         cx.spawn(async {
             // tokio::time::sleep(std::time::Duration::from_millis(100000)).await;
@@ -81,7 +77,7 @@ fn root_props_drop() {
     struct RootProps(String);
 
     let mut dom = VirtualDom::new_with_props(
-        |cx| render!( div { "{cx.props.0}" } ),
+        |cx| render!( div { "{cx.0}" } ),
         RootProps("asdasd".to_string()),
     );
 
@@ -92,7 +88,6 @@ fn root_props_drop() {
 
 #[test]
 fn diffing_drops_old() {
-    #[component]
     fn App() -> Element {
         render! {
             div {
@@ -106,12 +101,12 @@ fn diffing_drops_old() {
     }
 
     #[component]
-    fn ChildComp1(cx: Scope, name: String) -> Element {
+    fn ChildComp1(name: String) -> Element {
         render! {"Hello {name}"}
     }
 
     #[component]
-    fn ChildComp2(cx: Scope, name: String) -> Element {
+    fn ChildComp2(name: String) -> Element {
         render! {"Goodbye {name}"}
     }
 

+ 10 - 10
packages/core/tests/miri_stress.rs

@@ -38,22 +38,22 @@ fn test_memory_leak() {
         )
     }
 
-    #[derive(Props)]
-    struct BorrowedProps<'a> {
-        name: &'a str,
+    #[derive(Props, Clone, PartialEq)]
+    struct BorrowedProps {
+        name: String,
     }
 
-    fn BorrowedChild<'a>(cx: Scope<'a, BorrowedProps<'a>>) -> Element {
+    fn BorrowedChild(cx: BorrowedProps) -> Element {
         render! {
             div {
-                "goodbye {cx.props.name}"
+                "goodbye {cx.name}"
                 Child {}
                 Child {}
             }
         }
     }
 
-    fn Child(cx: Scope) -> Element {
+    fn Child() -> Element {
         render!( div { "goodbye world" } )
     }
 
@@ -117,12 +117,12 @@ fn free_works_on_root_hooks() {
     }
 
     fn app(cx: Scope<AppProps>) -> Element {
-        let name: &AppProps = cx.use_hook(|| cx.props.clone());
+        let name: &AppProps = cx.use_hook(|| cx.clone());
         render!(child_component { inner: name.inner.clone() })
     }
 
     fn child_component(cx: Scope<AppProps>) -> Element {
-        render!( div { "{cx.props.inner}" } )
+        render!( div { "{cx.inner}" } )
     }
 
     let ptr = Rc::new("asdasd".to_string());
@@ -143,8 +143,8 @@ fn supports_async() {
     use tokio::time::sleep;
 
     fn app() -> Element {
-        let colors = use_state(cx, || vec!["green", "blue", "red"]);
-        let padding = use_state(cx, || 10);
+        let colors = use_signal(|| vec!["green", "blue", "red"]);
+        let padding = use_signal(|| 10);
 
         use_effect(cx, colors, |colors| async move {
             sleep(Duration::from_millis(1000)).await;

+ 3 - 4
packages/core/tests/suspense.rs

@@ -28,11 +28,10 @@ fn app() -> Element {
     )
 }
 
-fn suspended_child(cx: Scope) -> Element {
-    let val = use_state(cx, || 0);
+fn suspended_child() -> Element {
+    let mut val = use_signal(|| 0);
 
-    if **val < 3 {
-        let mut val = val.clone();
+    if *val() < 3 {
         cx.spawn(async move {
             val += 1;
         });