Detect components called as functions (#2461)
* detect components called as functions * use the existing component name information instead of a thread local
This commit is contained in:
1 parent
7efe4d0e49
commit
5024139e01
3 files changed
+38
No files matched your search
@@ -84,6 +84,7 @@ impl ComponentBody {
|
|||||||
} = sig;
|
} = sig;
|
||||||
let Generics { where_clause, .. } = generics;
|
let Generics { where_clause, .. } = generics;
|
||||||
let (_, ty_generics, _) = generics.split_for_impl();
|
let (_, ty_generics, _) = generics.split_for_impl();
|
||||||
|
let generics_turbofish = ty_generics.as_turbofish();
|
||||||
|
|
||||||
// We generate a struct with the same name as the component but called `Props`
|
// We generate a struct with the same name as the component but called `Props`
|
||||||
let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span());
|
let struct_ident = Ident::new(&format!("{fn_ident}Props"), fn_ident.span());
|
||||||
@@ -108,6 +109,9 @@ impl ComponentBody {
|
|||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#(#props_docs)*
|
#(#props_docs)*
|
||||||
#asyncness #vis fn #fn_ident #generics (#props_ident) #fn_output #where_clause {
|
#asyncness #vis fn #fn_ident #generics (#props_ident) #fn_output #where_clause {
|
||||||
|
// In debug mode we can detect if the user is calling the component like a function
|
||||||
|
dioxus_core::internal::verify_component_called_as_component(#fn_ident #generics_turbofish);
|
||||||
|
|
||||||
#expanded_struct
|
#expanded_struct
|
||||||
#block
|
#block
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ mod scopes;
|
|||||||
mod tasks;
|
mod tasks;
|
||||||
mod virtual_dom;
|
mod virtual_dom;
|
||||||
|
|
||||||
|
/// Items exported from this module are used in macros and should not be used directly.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod internal {
|
||||||
|
pub use crate::properties::verify_component_called_as_component;
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) mod innerlude {
|
pub(crate) mod innerlude {
|
||||||
pub(crate) use crate::any_props::*;
|
pub(crate) use crate::any_props::*;
|
||||||
pub use crate::arena::*;
|
pub use crate::arena::*;
|
||||||
|
|||||||
@@ -117,6 +117,34 @@ where
|
|||||||
P::builder()
|
P::builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Make sure that this component is currently running as a component, not a function call
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn verify_component_called_as_component<C: ComponentFunction<P, M>, P, M>(component: C) {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
// We trim WithOwner from the end of the type name for component with a builder that include a special owner which may not match the function name directly
|
||||||
|
let mut type_name = std::any::type_name::<C>();
|
||||||
|
if let Some((_, after_colons)) = type_name.rsplit_once("::") {
|
||||||
|
type_name = after_colons;
|
||||||
|
}
|
||||||
|
let component_name = Runtime::with(|rt| {
|
||||||
|
current_scope_id()
|
||||||
|
.and_then(|id| rt.get_state(id))
|
||||||
|
.map(|scope| scope.name)
|
||||||
|
})
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
// If we are in a component, and the type name is the same as the active component name, then we can just return
|
||||||
|
if component_name == Some(type_name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise the component was called like a function, so we should log an error
|
||||||
|
tracing::error!("It looks like you called the component {type_name} like a function instead of a component. Components should be called with braces like `{type_name} {{ prop: value }}` instead of as a function");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Any component that implements the `ComponentFn` trait can be used as a component.
|
/// Any component that implements the `ComponentFn` trait can be used as a component.
|
||||||
///
|
///
|
||||||
/// This trait is automatically implemented for functions that are in one of the following forms:
|
/// This trait is automatically implemented for functions that are in one of the following forms:
|
||||||
|
|||||||
Reference in new issue
Block a user