瀏覽代碼

fix constructing no argument components

Evan Almloff 1 年之前
父節點
當前提交
bcbb647d02

+ 10 - 10
packages/core/src/any_props.rs

@@ -1,5 +1,5 @@
-use crate::{nodes::RenderReturn, Element};
-use std::{any::Any, ops::Deref, panic::AssertUnwindSafe};
+use crate::{nodes::RenderReturn, properties::HasProps};
+use std::{any::Any, ops::Deref, panic::AssertUnwindSafe, rc::Rc};
 
 /// A boxed version of AnyProps that can be cloned
 pub(crate) struct BoxedAnyProps {
@@ -38,22 +38,22 @@ pub(crate) trait AnyProps {
     fn duplicate(&self) -> Box<dyn AnyProps>;
 }
 
-pub(crate) struct VProps<P> {
-    pub render_fn: fn(P) -> Element,
+pub(crate) struct VProps<P: 'static, Phantom: 'static> {
+    pub render_fn: Rc<dyn HasProps<Phantom, Props = P>>,
     pub memo: fn(&P, &P) -> bool,
     pub props: P,
     pub name: &'static str,
 }
 
-impl<P> VProps<P> {
+impl<P: 'static, Phantom: 'static> VProps<P, Phantom> {
     pub(crate) fn new(
-        render_fn: fn(P) -> Element,
+        render_fn: impl HasProps<Phantom, Props = P> + 'static,
         memo: fn(&P, &P) -> bool,
         props: P,
         name: &'static str,
     ) -> Self {
         Self {
-            render_fn,
+            render_fn: Rc::new(render_fn),
             memo,
             props,
             name,
@@ -61,7 +61,7 @@ impl<P> VProps<P> {
     }
 }
 
-impl<P: Clone + 'static> AnyProps for VProps<P> {
+impl<P: Clone + 'static, Phantom> AnyProps for VProps<P, Phantom> {
     fn memoize(&self, other: &dyn Any) -> bool {
         match other.downcast_ref::<P>() {
             Some(other) => (self.memo)(&self.props, other),
@@ -76,7 +76,7 @@ impl<P: Clone + 'static> AnyProps for VProps<P> {
     fn render(&self) -> RenderReturn {
         let res = std::panic::catch_unwind(AssertUnwindSafe(move || {
             // Call the render function directly
-            (self.render_fn)(self.props.clone())
+            self.render_fn.call(self.props.clone())
         }));
 
         match res {
@@ -92,7 +92,7 @@ impl<P: Clone + 'static> AnyProps for VProps<P> {
 
     fn duplicate(&self) -> Box<dyn AnyProps> {
         Box::new(Self {
-            render_fn: self.render_fn,
+            render_fn: self.render_fn.clone(),
             memo: self.memo,
             props: self.props.clone(),
             name: self.name,

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

@@ -102,8 +102,8 @@ pub fn once<State: Clone + 'static>(initializer: impl FnOnce() -> State) -> Stat
 /// Get the current render since the inception of this component
 ///
 /// This can be used as a helpful diagnostic when debugging hooks/renders, etc
-pub fn generation() -> Option<usize> {
-    with_current_scope(|cx| Some(cx.generation())).expect("to be in a dioxus runtime")
+pub fn generation() -> usize {
+    with_current_scope(|cx| cx.generation()).expect("to be in a dioxus runtime")
 }
 
 /// Get the parent of the current scope if it exists

+ 11 - 5
packages/core/src/nodes.rs

@@ -1,5 +1,6 @@
 use crate::any_props::{BoxedAnyProps, VProps};
 use crate::innerlude::{ElementRef, EventHandler, MountId, ScopeState};
+use crate::properties::HasProps;
 use crate::{arena::ElementId, Element, Event};
 use crate::{Properties, VirtualDom};
 use std::ops::Deref;
@@ -443,7 +444,7 @@ pub struct VComponent {
     /// The function pointer of the component, known at compile time
     ///
     /// It is possible that components get folded at compile time, so these shouldn't be really used as a key
-    pub(crate) render_fn: *const (),
+    pub(crate) render_fn: TypeId,
 
     pub(crate) props: BoxedAnyProps,
 }
@@ -463,16 +464,21 @@ impl VComponent {
     /// fn(Scope<Props>) -> Element;
     /// async fn(Scope<Props<'_>>) -> Element;
     /// ```
-    pub fn new<P>(component: fn(P) -> Element, props: P, fn_name: &'static str) -> Self
+    pub fn new<F: HasProps<P> + 'static, P: 'static>(
+        component: F,
+        props: F::Props,
+        fn_name: &'static str,
+    ) -> Self
     where
         // The properties must be valid until the next bump frame
-        P: Properties,
+        F::Props: Properties + 'static,
     {
-        let vcomp = VProps::new(component, P::memoize, props, fn_name);
+        let render_fn_id = TypeId::of::<F>();
+        let vcomp = VProps::new(component, F::Props::memoize, props, fn_name);
 
         VComponent {
             name: fn_name,
-            render_fn: component as *const (),
+            render_fn: render_fn_id,
             props: BoxedAnyProps::new(vcomp),
         }
     }

+ 16 - 5
packages/core/src/properties.rs

@@ -67,25 +67,36 @@ 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<F: HasProps<P>, P>(
-    _: F,
-) -> <<F as HasProps<P>>::Props as Properties>::Builder {
+pub fn fc_to_builder<F: HasProps<P>, P>(_: F) -> <<F as HasProps<P>>::Props as Properties>::Builder
+where
+    F::Props: Properties,
+{
     F::Props::builder()
 }
 
 /// A function pointer that can be used to create a component.
 pub trait HasProps<P> {
-    type Props: Properties;
+    type Props: 'static;
+
+    fn call(&self, props: Self::Props) -> Element;
 }
 
-impl<T: Properties, F: Fn(T) -> Element> HasProps<(T,)> for F {
+impl<T: 'static, F: Fn(T) -> Element> HasProps<(T,)> for F {
     type Props = T;
+
+    fn call(&self, props: T) -> Element {
+        self(props)
+    }
 }
 
 #[doc(hidden)]
 pub struct ZeroElementMarker;
 impl<F: Fn() -> Element> HasProps<ZeroElementMarker> for F {
     type Props = ();
+
+    fn call(&self, _: ()) -> Element {
+        self()
+    }
 }
 
 #[test]

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

@@ -4,7 +4,7 @@ use dioxus::prelude::*;
 #[test]
 fn state_shares() {
     fn app() -> Element {
-        cx.provide_context(generation() as i32);
+        cx.provide_context(generation().unwrap() as i32);
 
         render!(child_1 {})
     }