fix constructing no argument components
This commit is contained in:
1 parent
1794debf79
commit
bcbb647d02
5 files changed
+40
-23
No files matched your search
@@ -1,5 +1,5 @@
|
|||||||
use crate::{nodes::RenderReturn, Element};
|
use crate::{nodes::RenderReturn, properties::HasProps};
|
||||||
use std::{any::Any, ops::Deref, panic::AssertUnwindSafe};
|
use std::{any::Any, ops::Deref, panic::AssertUnwindSafe, rc::Rc};
|
||||||
|
|
||||||
/// A boxed version of AnyProps that can be cloned
|
/// A boxed version of AnyProps that can be cloned
|
||||||
pub(crate) struct BoxedAnyProps {
|
pub(crate) struct BoxedAnyProps {
|
||||||
@@ -38,22 +38,22 @@ pub(crate) trait AnyProps {
|
|||||||
fn duplicate(&self) -> Box<dyn AnyProps>;
|
fn duplicate(&self) -> Box<dyn AnyProps>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct VProps<P> {
|
pub(crate) struct VProps<P: 'static, Phantom: 'static> {
|
||||||
pub render_fn: fn(P) -> Element,
|
pub render_fn: Rc<dyn HasProps<Phantom, Props = P>>,
|
||||||
pub memo: fn(&P, &P) -> bool,
|
pub memo: fn(&P, &P) -> bool,
|
||||||
pub props: P,
|
pub props: P,
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P> VProps<P> {
|
impl<P: 'static, Phantom: 'static> VProps<P, Phantom> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
render_fn: fn(P) -> Element,
|
render_fn: impl HasProps<Phantom, Props = P> + 'static,
|
||||||
memo: fn(&P, &P) -> bool,
|
memo: fn(&P, &P) -> bool,
|
||||||
props: P,
|
props: P,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
render_fn,
|
render_fn: Rc::new(render_fn),
|
||||||
memo,
|
memo,
|
||||||
props,
|
props,
|
||||||
name,
|
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 {
|
fn memoize(&self, other: &dyn Any) -> bool {
|
||||||
match other.downcast_ref::<P>() {
|
match other.downcast_ref::<P>() {
|
||||||
Some(other) => (self.memo)(&self.props, other),
|
Some(other) => (self.memo)(&self.props, other),
|
||||||
@@ -76,7 +76,7 @@ impl<P: Clone + 'static> AnyProps for VProps<P> {
|
|||||||
fn render(&self) -> RenderReturn {
|
fn render(&self) -> RenderReturn {
|
||||||
let res = std::panic::catch_unwind(AssertUnwindSafe(move || {
|
let res = std::panic::catch_unwind(AssertUnwindSafe(move || {
|
||||||
// Call the render function directly
|
// Call the render function directly
|
||||||
(self.render_fn)(self.props.clone())
|
self.render_fn.call(self.props.clone())
|
||||||
}));
|
}));
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
@@ -92,7 +92,7 @@ impl<P: Clone + 'static> AnyProps for VProps<P> {
|
|||||||
|
|
||||||
fn duplicate(&self) -> Box<dyn AnyProps> {
|
fn duplicate(&self) -> Box<dyn AnyProps> {
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
render_fn: self.render_fn,
|
render_fn: self.render_fn.clone(),
|
||||||
memo: self.memo,
|
memo: self.memo,
|
||||||
props: self.props.clone(),
|
props: self.props.clone(),
|
||||||
name: self.name,
|
name: self.name,
|
||||||
|
|||||||
@@ -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
|
/// Get the current render since the inception of this component
|
||||||
///
|
///
|
||||||
/// This can be used as a helpful diagnostic when debugging hooks/renders, etc
|
/// This can be used as a helpful diagnostic when debugging hooks/renders, etc
|
||||||
pub fn generation() -> Option<usize> {
|
pub fn generation() -> usize {
|
||||||
with_current_scope(|cx| Some(cx.generation())).expect("to be in a dioxus runtime")
|
with_current_scope(|cx| cx.generation()).expect("to be in a dioxus runtime")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the parent of the current scope if it exists
|
/// Get the parent of the current scope if it exists
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::any_props::{BoxedAnyProps, VProps};
|
use crate::any_props::{BoxedAnyProps, VProps};
|
||||||
use crate::innerlude::{ElementRef, EventHandler, MountId, ScopeState};
|
use crate::innerlude::{ElementRef, EventHandler, MountId, ScopeState};
|
||||||
|
use crate::properties::HasProps;
|
||||||
use crate::{arena::ElementId, Element, Event};
|
use crate::{arena::ElementId, Element, Event};
|
||||||
use crate::{Properties, VirtualDom};
|
use crate::{Properties, VirtualDom};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@@ -443,7 +444,7 @@ pub struct VComponent {
|
|||||||
/// The function pointer of the component, known at compile time
|
/// 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
|
/// 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,
|
pub(crate) props: BoxedAnyProps,
|
||||||
}
|
}
|
||||||
@@ -463,16 +464,21 @@ impl VComponent {
|
|||||||
/// fn(Scope<Props>) -> Element;
|
/// fn(Scope<Props>) -> Element;
|
||||||
/// async 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
|
where
|
||||||
// The properties must be valid until the next bump frame
|
// 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 {
|
VComponent {
|
||||||
name: fn_name,
|
name: fn_name,
|
||||||
render_fn: component as *const (),
|
render_fn: render_fn_id,
|
||||||
props: BoxedAnyProps::new(vcomp),
|
props: BoxedAnyProps::new(vcomp),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,25 +67,36 @@ impl EmptyBuilder {
|
|||||||
|
|
||||||
/// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern
|
/// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern
|
||||||
/// to initialize a component's props.
|
/// to initialize a component's props.
|
||||||
pub fn fc_to_builder<F: HasProps<P>, P>(
|
pub fn fc_to_builder<F: HasProps<P>, P>(_: F) -> <<F as HasProps<P>>::Props as Properties>::Builder
|
||||||
_: F,
|
where
|
||||||
) -> <<F as HasProps<P>>::Props as Properties>::Builder {
|
F::Props: Properties,
|
||||||
|
{
|
||||||
F::Props::builder()
|
F::Props::builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A function pointer that can be used to create a component.
|
/// A function pointer that can be used to create a component.
|
||||||
pub trait HasProps<P> {
|
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;
|
type Props = T;
|
||||||
|
|
||||||
|
fn call(&self, props: T) -> Element {
|
||||||
|
self(props)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct ZeroElementMarker;
|
pub struct ZeroElementMarker;
|
||||||
impl<F: Fn() -> Element> HasProps<ZeroElementMarker> for F {
|
impl<F: Fn() -> Element> HasProps<ZeroElementMarker> for F {
|
||||||
type Props = ();
|
type Props = ();
|
||||||
|
|
||||||
|
fn call(&self, _: ()) -> Element {
|
||||||
|
self()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use dioxus::prelude::*;
|
|||||||
#[test]
|
#[test]
|
||||||
fn state_shares() {
|
fn state_shares() {
|
||||||
fn app() -> Element {
|
fn app() -> Element {
|
||||||
cx.provide_context(generation() as i32);
|
cx.provide_context(generation().unwrap() as i32);
|
||||||
|
|
||||||
render!(child_1 {})
|
render!(child_1 {})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user