diff --git a/examples/function_todomvc/src/components/filter.rs b/examples/function_todomvc/src/components/filter.rs index 469572ed9b0..4380d063cdf 100644 --- a/examples/function_todomvc/src/components/filter.rs +++ b/examples/function_todomvc/src/components/filter.rs @@ -8,8 +8,8 @@ pub struct FilterProps { pub onset_filter: Callback, } -#[function_component(Filter)] -pub fn filter(props: &FilterProps) -> Html { +#[function_component] +pub fn Filter(props: &FilterProps) -> Html { let filter = props.filter; let cls = if props.selected { diff --git a/packages/yew-macro/src/function_component.rs b/packages/yew-macro/src/function_component.rs index 9b9a1c20c94..f05ed2b2428 100644 --- a/packages/yew-macro/src/function_component.rs +++ b/packages/yew-macro/src/function_component.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream; -use quote::{quote, quote_spanned, ToTokens}; +use quote::{format_ident, quote, quote_spanned, ToTokens}; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; @@ -140,18 +140,22 @@ impl Parse for FunctionComponent { } pub struct FunctionComponentName { - component_name: Ident, + component_name: Option, } impl Parse for FunctionComponentName { fn parse(input: ParseStream) -> syn::Result { if input.is_empty() { - return Err(input.error("expected identifier for the component")); + return Ok(Self { + component_name: None, + }); } let component_name = input.parse()?; - Ok(Self { component_name }) + Ok(Self { + component_name: Some(component_name), + }) } } @@ -171,7 +175,12 @@ pub fn function_component_impl( name: function_name, return_type, } = component; - + let component_name = component_name.unwrap_or_else(|| function_name.clone()); + let function_name = format_ident!( + "{}FunctionProvider", + function_name, + span = function_name.span() + ); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); if function_name == component_name { diff --git a/packages/yew-macro/tests/function_component_attr/bad-name-fail.stderr b/packages/yew-macro/tests/function_component_attr/bad-name-fail.stderr index f96cc1919ec..6c97843a4f2 100644 --- a/packages/yew-macro/tests/function_component_attr/bad-name-fail.stderr +++ b/packages/yew-macro/tests/function_component_attr/bad-name-fail.stderr @@ -1,23 +1,25 @@ error: expected identifier - --> $DIR/bad-name-fail.rs:8:22 + --> tests/function_component_attr/bad-name-fail.rs:8:22 | 8 | #[function_component(let)] | ^^^ error: unexpected token - --> $DIR/bad-name-fail.rs:17:23 + --> tests/function_component_attr/bad-name-fail.rs:17:23 | 17 | #[function_component(x, y, z)] | ^ error: expected identifier - --> $DIR/bad-name-fail.rs:26:22 + --> tests/function_component_attr/bad-name-fail.rs:26:22 | 26 | #[function_component(124)] | ^^^ -error: the component must not have the same name as the function - --> $DIR/bad-name-fail.rs:35:22 +warning: type `component` should have an upper camel case name + --> tests/function_component_attr/bad-name-fail.rs:35:22 | 35 | #[function_component(component)] - | ^^^^^^^^^ + | ^^^^^^^^^ help: convert the identifier to upper camel case (notice the capitalization): `Component` + | + = note: `#[warn(non_camel_case_types)]` on by default diff --git a/packages/yew-macro/tests/function_component_attr/generic-props-fail.stderr b/packages/yew-macro/tests/function_component_attr/generic-props-fail.stderr index eccd889da64..5d0a9b68e0d 100644 --- a/packages/yew-macro/tests/function_component_attr/generic-props-fail.stderr +++ b/packages/yew-macro/tests/function_component_attr/generic-props-fail.stderr @@ -22,13 +22,13 @@ error[E0277]: the trait bound `MissingTypeBounds: yew::Properties` is not satisf 27 | html! { /> }; | ^^^^ the trait `yew::Properties` is not implemented for `MissingTypeBounds` | - = note: required because of the requirements on the impl of `FunctionProvider` for `comp` + = note: required because of the requirements on the impl of `FunctionProvider` for `compFunctionProvider` -error[E0599]: the function or associated item `new` exists for struct `VChild>>`, but its trait bounds were not satisfied +error[E0599]: the function or associated item `new` exists for struct `VChild>>`, but its trait bounds were not satisfied --> tests/function_component_attr/generic-props-fail.rs:27:14 | 27 | html! { /> }; - | ^^^^ function or associated item cannot be called on `VChild>>` due to unsatisfied trait bounds + | ^^^^ function or associated item cannot be called on `VChild>>` due to unsatisfied trait bounds | ::: $WORKSPACE/packages/yew/src/functional/mod.rs | @@ -36,7 +36,7 @@ error[E0599]: the function or associated item `new` exists for struct `VChild>: yew::Component` + `FunctionComponent>: yew::Component` error[E0107]: missing generics for type alias `Comp` --> tests/function_component_attr/generic-props-fail.rs:30:14 diff --git a/packages/yew-macro/tests/function_component_attr/no-name-fail.rs b/packages/yew-macro/tests/function_component_attr/no-name-default-pass.rs similarity index 57% rename from packages/yew-macro/tests/function_component_attr/no-name-fail.rs rename to packages/yew-macro/tests/function_component_attr/no-name-default-pass.rs index e648f029851..f7ad0b68ecd 100644 --- a/packages/yew-macro/tests/function_component_attr/no-name-fail.rs +++ b/packages/yew-macro/tests/function_component_attr/no-name-default-pass.rs @@ -5,8 +5,8 @@ struct Props { a: usize, } -#[function_component()] -fn comp(props: &Props) -> Html { +#[function_component] +fn Comp(props: &Props) -> Html { html! {

{ props.a } @@ -14,4 +14,8 @@ fn comp(props: &Props) -> Html { } } -fn main() {} +fn main() { + let _ = html! { + + }; +} diff --git a/packages/yew-macro/tests/function_component_attr/no-name-fail.stderr b/packages/yew-macro/tests/function_component_attr/no-name-fail.stderr deleted file mode 100644 index fa9615bcbf9..00000000000 --- a/packages/yew-macro/tests/function_component_attr/no-name-fail.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: unexpected end of input, expected identifier for the component - --> $DIR/no-name-fail.rs:8:1 - | -8 | #[function_component()] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/website/docs/concepts/function-components/attribute.mdx b/website/docs/concepts/function-components/attribute.mdx index 96e87c313ee..ae0da06fe1d 100644 --- a/website/docs/concepts/function-components/attribute.mdx +++ b/website/docs/concepts/function-components/attribute.mdx @@ -11,7 +11,26 @@ Functions with the attribute have to return `Html` and may take a single paramet The parameter type needs to be a reference to a `Properties` type (ex. `props: &MyProps`). If the function doesn't have any parameters the resulting component doesn't accept any props. -The attribute doesn't replace your original function with a component. You need to provide a name as an input to the attribute which will be the identifier of the component. +Just mark the component with the attribute. The component will be named after the function. + +```rust +use yew::{function_component, html, Html}; + +#[function_component] +pub fn ChatContainer() -> Html { + html! { + // chat container impl + } +} + +html! { + +}; +``` + +## Specifying a custom component name + +You need to provide a name as an input to the attribute which will be the identifier of the component. Assuming you have a function called `chat_container` and you add the attribute `#[function_component(ChatContainer)]` you can use the component like this: ```rust @@ -42,8 +61,8 @@ pub struct RenderedAtProps { pub time: String, } -#[function_component(RenderedAt)] -pub fn rendered_at(props: &RenderedAtProps) -> Html { +#[function_component] +pub fn RenderedAt(props: &RenderedAtProps) -> Html { html! {

{ "Rendered at: " } @@ -59,8 +78,8 @@ pub fn rendered_at(props: &RenderedAtProps) -> Html { ```rust use yew::{function_component, html, use_state, Callback}; -#[function_component(App)] -fn app() -> Html { +#[function_component] +fn App() -> Html { let counter = use_state(|| 0); let onclick = { @@ -99,8 +118,8 @@ where data: T, } -#[function_component(MyGenericComponent)] -pub fn my_generic_component(props: &Props) -> Html +#[function_component] +pub fn MyGenericComponent(props: &Props) -> Html where T: PartialEq + Display, { diff --git a/website/docs/concepts/function-components/introduction.mdx b/website/docs/concepts/function-components/introduction.mdx index 05d14fcd5af..29acf8326a3 100644 --- a/website/docs/concepts/function-components/introduction.mdx +++ b/website/docs/concepts/function-components/introduction.mdx @@ -18,8 +18,8 @@ The easiest way to create a function component is to add the [`#[function_compon ```rust use yew::{function_component, html}; -#[function_component(HelloWorld)] -fn hello_world() -> Html { +#[function_component] +fn HelloWorld() -> Html { html! { "Hello world" } } ```