yew: function_component -> component (#3885)

This commit is contained in:
Tim Kurdov 2025-07-21 01:06:41 +00:00 committed by GitHub
parent 16fd8b085a
commit f0b182d391
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
102 changed files with 353 additions and 350 deletions

View File

@ -85,7 +85,7 @@ where
/// The Oneshot Agent Provider.
///
/// This component provides its children access to an oneshot agent.
#[function_component]
#[component]
pub fn OneshotProvider<T, C = Bincode>(props: &WorkerProviderProps) -> Html
where
T: Oneshot + 'static,

View File

@ -85,7 +85,7 @@ where
/// The Reactor Agent Provider.
///
/// This component provides its children access to a reactor agent.
#[function_component]
#[component]
pub fn ReactorProvider<R, C = Bincode>(props: &WorkerProviderProps) -> Html
where
R: 'static + Reactor,

View File

@ -39,7 +39,7 @@
//! # }
//! # }
//! use my_worker_mod::MyWorker; // note that <MyWorker as yew_agent::Worker>::Output == WorkerResponseType
//! #[function_component(UseWorkerBridge)]
//! #[component(UseWorkerBridge)]
//! fn bridge() -> Html {
//! let counter = use_state(|| 0);
//!

View File

@ -104,7 +104,7 @@ where
/// The Worker Agent Provider.
///
/// This component provides its children access to a worker agent.
#[function_component]
#[component]
pub fn WorkerProvider<W, C = Bincode>(props: &WorkerProviderProps) -> Html
where
W: Worker + 'static,

View File

@ -35,7 +35,7 @@ impl Parse for FunctionComponent {
item => {
return Err(syn::Error::new_spanned(
item,
"`function_component` attribute can only be applied to functions",
"`component` attribute can only be applied to functions",
))
}
};

View File

@ -258,12 +258,12 @@ mod value_into_some_value_in_props {
optional: ::std::option::Option<usize>
}
#[::yew::function_component]
#[::yew::component]
fn Inner(_props: &Props) -> ::yew::html::Html {
::yew::html!{}
}
#[::yew::function_component]
#[::yew::component]
fn Main() -> ::yew::html::Html {
::yew::html! {<>
<Inner required=3 optional=5/>

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(Comp)]
#[component(Comp)]
struct Test;
fn main() {}

View File

@ -1,4 +1,4 @@
error: `function_component` attribute can only be applied to functions
error: `component` attribute can only be applied to functions
--> $DIR/applied-to-non-fn-fail.rs:9:1
|
9 | struct Test;

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(Comp)]
#[component(Comp)]
async fn comp(props: &Props) -> Html {
html! {
<p>

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(let)]
#[component(let)]
fn comp(props: &Props) -> Html {
html! {
<p>
@ -14,7 +14,7 @@ fn comp(props: &Props) -> Html {
}
}
#[function_component(x, y, z)]
#[component(x, y, z)]
fn comp_2(props: &Props) -> Html {
html! {
<p>
@ -23,7 +23,7 @@ fn comp_2(props: &Props) -> Html {
}
}
#[function_component(124)]
#[component(124)]
fn comp_3(props: &Props) -> Html {
html! {
<p>
@ -32,7 +32,7 @@ fn comp_3(props: &Props) -> Html {
}
}
#[function_component(component)]
#[component(component)]
fn component(props: &Props) -> Html {
html! {
<p>

View File

@ -1,23 +1,23 @@
error: expected identifier, found keyword `let`
--> tests/function_component_attr/bad-name-fail.rs:8:22
--> tests/function_component_attr/bad-name-fail.rs:8:13
|
8 | #[function_component(let)]
| ^^^
8 | #[component(let)]
| ^^^
error: unexpected token
--> tests/function_component_attr/bad-name-fail.rs:17:23
--> tests/function_component_attr/bad-name-fail.rs:17:14
|
17 | #[function_component(x, y, z)]
| ^
17 | #[component(x, y, z)]
| ^
error: expected identifier
--> tests/function_component_attr/bad-name-fail.rs:26:22
--> tests/function_component_attr/bad-name-fail.rs:26:13
|
26 | #[function_component(124)]
| ^^^
26 | #[component(124)]
| ^^^
error: the component must not have the same name as the function
--> tests/function_component_attr/bad-name-fail.rs:35:22
--> tests/function_component_attr/bad-name-fail.rs:35:13
|
35 | #[function_component(component)]
| ^^^^^^^^^
35 | #[component(component)]
| ^^^^^^^^^

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(Comp)]
#[component(Comp)]
fn comp(props: Props) -> Html {
html! {
<p>

View File

@ -5,10 +5,10 @@ struct Props {
a: usize,
}
#[function_component(Comp1)]
#[component(Comp1)]
fn comp_1(_props: &Props) {}
#[function_component(Comp)]
#[component(Comp)]
fn comp(_props: &Props) -> u32 {
1
}

View File

@ -7,10 +7,10 @@ error: function components must return `yew::Html` or `yew::HtmlResult`
error[E0277]: the trait bound `u32: IntoHtmlResult` is not satisfied
--> tests/function_component_attr/bad-return-type-fail.rs:11:1
|
11 | #[function_component(Comp)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoHtmlResult` is not implemented for `u32`
11 | #[component(Comp)]
| ^^^^^^^^^^^^^^^^^^ the trait `IntoHtmlResult` is not implemented for `u32`
|
= help: the following other types implement trait `IntoHtmlResult`:
VNode
Result<VNode, RenderError>
= note: this error originates in the attribute macro `function_component` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the attribute macro `component` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(Comp)]
#[component(Comp)]
const fn comp(props: &Props) -> Html {
html! {
<p>

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(Comp)]
#[component(Comp)]
extern "C" fn comp(props: &Props) -> Html {
html! {
<p>

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(Comp)]
#[component(Comp)]
fn comp<'a>(props: &'a Props) -> Html {
html! {
<p>

View File

@ -40,7 +40,7 @@ struct Props {
a: ::std::primitive::usize,
}
#[::yew::function_component(Comp)]
#[::yew::component(Comp)]
fn comp<P>(_props: &P) -> ::yew::Html
where
P: ::yew::Properties + ::std::cmp::PartialEq,
@ -50,14 +50,14 @@ where
}
}
#[::yew::function_component(Comp1)]
#[::yew::component(Comp1)]
fn comp1<T1, T2>(_props: &()) -> ::yew::Html {
::yew::html! {
<p></p>
}
}
#[::yew::function_component(ConstGenerics)]
#[::yew::component(ConstGenerics)]
fn const_generics<const N: ::std::primitive::i32>() -> ::yew::Html {
::yew::html! {
<div>

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(Comp)]
#[component(Comp)]
fn comp<P>(_props: &P) -> Html
where
P: Properties + PartialEq,

View File

@ -55,8 +55,8 @@ error[E0277]: the trait bound `MissingTypeBounds: yew::Properties` is not satisf
note: required by a bound in `Comp`
--> tests/function_component_attr/generic-props-fail.rs:11:8
|
8 | #[function_component(Comp)]
| ---- required by a bound in this struct
8 | #[component(Comp)]
| ---- required by a bound in this struct
...
11 | P: Properties + PartialEq,
| ^^^^^^^^^^ required by this bound in `Comp`
@ -65,8 +65,8 @@ note: required by a bound in `Comp`
error[E0599]: the function or associated item `new` exists for struct `VChild<Comp<MissingTypeBounds>>`, but its trait bounds were not satisfied
--> tests/function_component_attr/generic-props-fail.rs:27:14
|
8 | #[function_component(Comp)]
| ------------------------- doesn't satisfy `Comp<MissingTypeBounds>: yew::BaseComponent`
8 | #[component(Comp)]
| ---------------- doesn't satisfy `Comp<MissingTypeBounds>: yew::BaseComponent`
...
27 | html! { <Comp<MissingTypeBounds> /> };
| ^^^^ function or associated item cannot be called on `VChild<Comp<MissingTypeBounds>>` due to unsatisfied trait bounds
@ -106,10 +106,10 @@ error[E0107]: missing generics for struct `Comp`
| ^^^^ expected 1 generic argument
|
note: struct defined here, with 1 generic parameter: `P`
--> tests/function_component_attr/generic-props-fail.rs:8:22
--> tests/function_component_attr/generic-props-fail.rs:8:13
|
8 | #[function_component(Comp)]
| ^^^^
8 | #[component(Comp)]
| ^^^^
9 | fn comp<P>(_props: &P) -> Html
| -
help: add missing generic argument

View File

@ -3,7 +3,7 @@ use yew::prelude::*;
#[derive(Debug, PartialEq, Clone)]
struct Ctx;
#[function_component]
#[component]
fn Comp() -> Html {
if let Some(_m) = use_context::<Ctx>() {
use_context::<Ctx>().unwrap();

View File

@ -6,7 +6,7 @@
)]
struct Ctx;
#[::yew::prelude::function_component]
#[::yew::prelude::component]
fn Comp() -> ::yew::prelude::Html {
::yew::prelude::use_context::<Ctx>().unwrap();

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(Comp)]
#[component(Comp)]
fn comp(props: &'static Props) -> Html {
html! {
<p>

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(Comp)]
#[component(Comp)]
fn comp(props: &Props, invalid: String) -> Html {
html! {
<p>
@ -15,7 +15,7 @@ fn comp(props: &Props, invalid: String) -> Html {
}
}
#[function_component(Comp)]
#[component(Comp)]
fn comp3(props: &Props, invalid: String, another_invalid: u32) -> Html {
html! {
<p>

View File

@ -5,7 +5,7 @@ struct Props {
a: usize,
}
#[function_component(Comp)]
#[component(Comp)]
fn comp(props: &mut Props) -> Html {
html! {
<p>

View File

@ -4,7 +4,7 @@ struct Props {
a: usize,
}
#[::yew::prelude::function_component]
#[::yew::prelude::component]
fn Comp(props: &Props) -> ::yew::prelude::Html {
::yew::prelude::html! {
<p>

View File

@ -11,12 +11,12 @@ impl<A> ::std::cmp::PartialEq for CompProps<A> {
}
}
#[::yew::prelude::function_component(Comp)]
#[::yew::prelude::component(Comp)]
pub fn comp<A = ()>(_props: &CompProps<A>) -> ::yew::prelude::Html {
::std::todo!()
}
#[::yew::prelude::function_component(App)]
#[::yew::prelude::component(App)]
pub fn app() -> ::yew::prelude::Html {
::yew::prelude::html! { <Comp /> } // No generics here.
}

View File

@ -39,7 +39,7 @@ struct Props {
a: ::std::primitive::usize,
}
#[::yew::function_component(Comp)]
#[::yew::component(Comp)]
fn comp(props: &Props) -> ::yew::Html {
::yew::html! {
<p>

View File

@ -8,7 +8,7 @@ struct Props {
struct Test;
impl Test {
#[function_component(Comp)]
#[component(Comp)]
fn comp(self, props: &Props) -> Html {
html! {
<p>

View File

@ -36,7 +36,7 @@ pub struct u8;
#[allow(non_camel_case_types)]
pub struct usize;
#[::yew::function_component(Comp)]
#[::yew::component(Comp)]
fn comp() -> ::yew::Html {
::yew::html! {
<p>

View File

@ -14,7 +14,7 @@ macro_rules! use_some_macro {
};
}
#[function_component]
#[component]
fn Comp() -> Html {
let content = if true {
use_some_macro!()

View File

@ -15,7 +15,7 @@ macro_rules! use_some_macro {
};
}
#[::yew::functional::function_component]
#[::yew::functional::component]
fn Comp() -> ::yew::Html {
let a = use_some_macro!();
let b = use_some_macro!("b");

View File

@ -1,7 +1,7 @@
use yew::prelude::*;
use yew_macro::{use_prepared_state_with_closure, use_prepared_state_without_closure};
#[function_component]
#[component]
fn Comp() -> HtmlResult {
use_prepared_state_with_closure!(123)?;
@ -18,7 +18,7 @@ fn Comp() -> HtmlResult {
Ok(Html::default())
}
#[function_component]
#[component]
fn Comp2() -> HtmlResult {
use_prepared_state_without_closure!(123)?;

View File

@ -1,7 +1,7 @@
use yew::prelude::*;
use yew_macro::{use_transitive_state_with_closure, use_transitive_state_without_closure};
#[function_component]
#[component]
fn Comp() -> HtmlResult {
use_transitive_state_with_closure!(123)?;
@ -16,7 +16,7 @@ fn Comp() -> HtmlResult {
Ok(Html::default())
}
#[function_component]
#[component]
fn Comp2() -> HtmlResult {
use_transitive_state_without_closure!(123)?;

View File

@ -151,7 +151,7 @@ pub struct RenderPropProps {
pub children: ::yew::Callback<()>,
}
#[::yew::function_component]
#[::yew::component]
pub fn RenderPropComp(_props: &RenderPropProps) -> ::yew::Html {
::yew::html! {}
}

View File

@ -140,7 +140,7 @@ fn compile_fail() {
pub struct HtmlInPropsProperties {
pub header: ::yew::Html,
}
#[function_component]
#[component]
fn HtmlInProps(props: &HtmlInPropsProperties) -> Html { let _ = (); unimplemented!() }
fn not_expressions() {

View File

@ -1,20 +1,20 @@
use yew::prelude::*;
#[function_component]
#[component]
pub fn App() -> Html {
html! {
<Foo />
}
}
#[function_component]
#[component]
pub fn App1() -> Html {
html! {
<Foo bar={"bar".to_string()} />
}
}
#[function_component]
#[component]
pub fn App2() -> Html {
html! {
<Foo bar={"bar".to_string()} baz={42} />
@ -27,7 +27,7 @@ pub struct FooProps {
pub baz: u32,
}
#[function_component]
#[component]
pub fn Foo(_props: &FooProps) -> Html {
html! {}
}

View File

@ -36,7 +36,7 @@ where
}
/// A wrapper around `<a>` tag to be used with [`Router`](crate::Router)
#[function_component]
#[component]
pub fn Link<R, Q = (), S = ()>(props: &LinkProps<R, Q, S>) -> Html
where
R: Routable + 'static,

View File

@ -12,7 +12,7 @@ pub struct RedirectProps<R: Routable> {
}
/// A component that will redirect to specified route when rendered.
#[function_component(Redirect)]
#[component(Redirect)]
pub fn redirect<R>(props: &RedirectProps<R>) -> Html
where
R: Routable + 'static,

View File

@ -19,7 +19,7 @@
//! NotFound,
//! }
//!
//! #[function_component(Secure)]
//! #[component(Secure)]
//! fn secure() -> Html {
//! let navigator = use_navigator().unwrap();
//!
@ -32,7 +32,7 @@
//! }
//! }
//!
//! #[function_component(Main)]
//! #[component(Main)]
//! fn app() -> Html {
//! html! {
//! <BrowserRouter>

View File

@ -66,7 +66,7 @@ impl NavigatorContext {
///
/// The implementation is separated to make sure <Router /> has the same virtual dom layout as
/// the <BrowserRouter /> and <HashRouter />.
#[function_component(BaseRouter)]
#[component(BaseRouter)]
fn base_router(props: &RouterProps) -> Html {
let RouterProps {
history,
@ -149,7 +149,7 @@ fn base_router(props: &RouterProps) -> Html {
/// If you are building a web application, you may want to consider using [`BrowserRouter`] instead.
///
/// You only need one `<Router />` for each application.
#[function_component(Router)]
#[component(Router)]
pub fn router(props: &RouterProps) -> Html {
html! {
<BaseRouter ..{props.clone()} />
@ -173,7 +173,7 @@ pub struct ConcreteRouterProps {
///
/// The router will by default use the value declared in `<base href="..." />` as its basename.
/// You may also specify a different basename with props.
#[function_component(BrowserRouter)]
#[component(BrowserRouter)]
pub fn browser_router(props: &ConcreteRouterProps) -> Html {
let ConcreteRouterProps { children, basename } = props.clone();
let history = use_state(|| AnyHistory::from(BrowserHistory::new()));
@ -196,7 +196,7 @@ pub fn browser_router(props: &ConcreteRouterProps) -> Html {
/// # Warning
///
/// Prefer [`BrowserRouter`] whenever possible and use this as a last resort.
#[function_component(HashRouter)]
#[component(HashRouter)]
pub fn hash_router(props: &ConcreteRouterProps) -> Html {
let ConcreteRouterProps { children, basename } = props.clone();
let history = use_state(|| AnyHistory::from(HashHistory::new()));

View File

@ -24,7 +24,7 @@ where
/// Otherwise `html! {}` is rendered and a message is logged to console
/// stating that no route can be matched.
/// See the [crate level document][crate] for more information.
#[function_component]
#[component]
pub fn Switch<R>(props: &SwitchProps<R>) -> Html
where
R: Routable + 'static,

View File

@ -5,7 +5,7 @@ use std::time::Duration;
use serde::{Deserialize, Serialize};
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
use yew::functional::function_component;
use yew::functional::component;
use yew::platform::time::sleep;
use yew::prelude::*;
use yew_router::prelude::*;
@ -35,7 +35,7 @@ struct NoProps {
id: u32,
}
#[function_component(No)]
#[component(No)]
fn no(props: &NoProps) -> Html {
let route = props.id.to_string();
@ -49,7 +49,7 @@ fn no(props: &NoProps) -> Html {
}
}
#[function_component(Comp)]
#[component(Comp)]
fn component() -> Html {
let navigator = use_navigator().unwrap();
@ -100,7 +100,7 @@ fn component() -> Html {
}
}
#[function_component(Root)]
#[component(Root)]
fn root() -> Html {
html! {
<BrowserRouter basename="/base/">

View File

@ -5,7 +5,7 @@ use std::time::Duration;
use serde::{Deserialize, Serialize};
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
use yew::functional::function_component;
use yew::functional::component;
use yew::platform::time::sleep;
use yew::prelude::*;
use yew_router::prelude::*;
@ -35,7 +35,7 @@ struct NoProps {
id: u32,
}
#[function_component(No)]
#[component(No)]
fn no(props: &NoProps) -> Html {
let route = props.id.to_string();
@ -49,7 +49,7 @@ fn no(props: &NoProps) -> Html {
}
}
#[function_component(Comp)]
#[component(Comp)]
fn component() -> Html {
let navigator = use_navigator().unwrap();
@ -100,7 +100,7 @@ fn component() -> Html {
}
}
#[function_component(Root)]
#[component(Root)]
fn root() -> Html {
html! {
<BrowserRouter>

View File

@ -5,7 +5,7 @@ use std::time::Duration;
use serde::{Deserialize, Serialize};
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
use yew::functional::function_component;
use yew::functional::component;
use yew::platform::time::sleep;
use yew::prelude::*;
use yew_router::prelude::*;
@ -35,7 +35,7 @@ struct NoProps {
id: u32,
}
#[function_component(No)]
#[component(No)]
fn no(props: &NoProps) -> Html {
let route = props.id.to_string();
@ -49,7 +49,7 @@ fn no(props: &NoProps) -> Html {
}
}
#[function_component(Comp)]
#[component(Comp)]
fn component() -> Html {
let navigator = use_navigator().unwrap();
@ -100,7 +100,7 @@ fn component() -> Html {
}
}
#[function_component(Root)]
#[component(Root)]
fn root() -> Html {
html! {
<HashRouter>

View File

@ -8,7 +8,7 @@ use gloo::utils::window;
use js_sys::{JsString, Object, Reflect};
use serde::{Deserialize, Serialize};
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
use yew::functional::function_component;
use yew::functional::component;
use yew::platform::time::sleep;
use yew::prelude::*;
use yew_router::prelude::*;
@ -59,7 +59,7 @@ struct NavigationMenuProps {
assertion: Option<fn(&Navigator, &Location)>,
}
#[function_component(NavigationMenu)]
#[component(NavigationMenu)]
fn navigation_menu(props: &NavigationMenuProps) -> Html {
let navigator = use_navigator().unwrap();
let location = use_location().unwrap();
@ -98,7 +98,7 @@ fn navigation_menu(props: &NavigationMenuProps) -> Html {
}
}
#[function_component(RootForBrowserRouter)]
#[component(RootForBrowserRouter)]
fn root_for_browser_router() -> Html {
html! {
<BrowserRouter>
@ -140,7 +140,7 @@ struct BasenameProps {
assertion: fn(&Navigator, &Location),
}
#[function_component(RootForBasename)]
#[component(RootForBasename)]
fn root_for_basename(props: &BasenameProps) -> Html {
html! {
<BrowserRouter basename={props.basename.clone()}>
@ -283,7 +283,7 @@ async fn link_with_basename(correct_initial_path: bool) {
assert_eq!(RENDERS.load(Ordering::Relaxed), 5);
}
#[function_component(RootForHashRouter)]
#[component(RootForHashRouter)]
fn root_for_hash_router() -> Html {
html! {
<HashRouter>

View File

@ -20,7 +20,7 @@ enum AppRoute {
Search { query: String },
}
#[function_component]
#[component]
fn Comp() -> Html {
let switch = move |routes: AppRoute| match routes {
AppRoute::Root => html! {
@ -40,7 +40,7 @@ fn Comp() -> Html {
}
}
#[function_component(Root)]
#[component(Root)]
fn root() -> Html {
html! {
<BrowserRouter>

View File

@ -299,7 +299,7 @@ mod tests {
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
use super::*;
use crate::{function_component, html, Html};
use crate::{component, html, Html};
wasm_bindgen_test_configure!(run_in_browser);
@ -373,7 +373,7 @@ mod tests {
#[test]
async fn macro_syntax_works() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { <a href="https://example.com/" ~alt={"abc"} ~data-bool={JsValue::from_bool(true)} /> }
}

View File

@ -20,7 +20,7 @@ use crate::functional::{hook, use_memo};
/// pub callback: Callback<String, String>,
/// }
///
/// #[function_component(MyComponent)]
/// #[component(MyComponent)]
/// fn my_component(props: &Props) -> Html {
/// let greeting = props.callback.emit("Yew".to_string());
///
@ -29,7 +29,7 @@ use crate::functional::{hook, use_memo};
/// }
/// }
///
/// #[function_component(UseCallback)]
/// #[component(UseCallback)]
/// fn callback() -> Html {
/// let counter = use_state(|| 0);
/// let onclick = {

View File

@ -16,7 +16,7 @@ use crate::functional::{Hook, HookContext};
/// # Example
///
/// ```rust
/// use yew::{ContextProvider, function_component, html, use_context, use_state, Html};
/// use yew::{ContextProvider, component, html, use_context, use_state, Html};
///
///
/// /// App theme
@ -27,7 +27,7 @@ use crate::functional::{Hook, HookContext};
/// }
///
/// /// Main component
/// #[function_component]
/// #[component]
/// pub fn App() -> Html {
/// let ctx = use_state(|| Theme {
/// foreground: "#000000".to_owned(),
@ -47,7 +47,7 @@ use crate::functional::{Hook, HookContext};
///
/// /// The toolbar.
/// /// This component has access to the context
/// #[function_component]
/// #[component]
/// pub fn Toolbar() -> Html {
/// html! {
/// <div>
@ -58,7 +58,7 @@ use crate::functional::{Hook, HookContext};
///
/// /// Button placed in `Toolbar`.
/// /// As this component is a child of `ThemeContextProvider` in the component tree, it also has access to the context.
/// #[function_component]
/// #[component]
/// pub fn ThemedButton() -> Html {
/// let theme = use_context::<Theme>().expect("no ctx found");
///

View File

@ -134,7 +134,7 @@ where
/// use yew::prelude::*;
/// # use std::rc::Rc;
///
/// #[function_component(UseEffect)]
/// #[component(UseEffect)]
/// fn effect() -> Html {
/// let counter = use_state(|| 0);
///
@ -186,7 +186,7 @@ where
/// # Example
///
/// ```rust
/// use yew::{function_component, html, use_effect_with, Html, Properties};
/// use yew::{component, html, use_effect_with, Html, Properties};
/// # use gloo::console::log;
///
/// #[derive(Properties, PartialEq)]
@ -194,7 +194,7 @@ where
/// pub is_loading: bool,
/// }
///
/// #[function_component]
/// #[component]
/// fn HelloWorld(props: &Props) -> Html {
/// let is_loading = props.is_loading.clone();
///
@ -216,10 +216,10 @@ where
/// render of a component.
///
/// ```rust
/// use yew::{function_component, html, use_effect_with, Html};
/// use yew::{component, html, use_effect_with, Html};
/// # use gloo::console::log;
///
/// #[function_component]
/// #[component]
/// fn HelloWorld() -> Html {
/// use_effect_with((), move |_| {
/// log!("I got rendered, yay!");
@ -235,10 +235,10 @@ where
/// It will only get called when the component is removed from view / gets destroyed.
///
/// ```rust
/// use yew::{function_component, html, use_effect_with, Html};
/// use yew::{component, html, use_effect_with, Html};
/// # use gloo::console::log;
///
/// #[function_component]
/// #[component]
/// fn HelloWorld() -> Html {
/// use_effect_with((), move |_| {
/// || {

View File

@ -80,7 +80,7 @@ mod feat_nightly {
/// ```rust
/// use yew::prelude::*;
///
/// #[function_component]
/// #[component]
/// fn ManuallyUpdatedDate() -> Html {
/// let trigger = use_force_update();
/// let onclick = use_state(move || Callback::from(move |_| trigger.force_update()));
@ -116,7 +116,7 @@ pub fn use_force_update() -> impl Hook<Output = UseForceUpdateHandle> {
mod nightly_test {
use yew::prelude::*;
#[function_component]
#[component]
fn ManuallyUpdatedDate() -> Html {
let trigger = use_force_update();
let _ = move || trigger();

View File

@ -56,7 +56,7 @@ where
/// pub step: usize,
/// }
///
/// #[function_component(UseMemo)]
/// #[component(UseMemo)]
/// fn memo(props: &Props) -> Html {
/// // Will only get recalculated if `props.step` value changes
/// let message = use_memo(props.step, |step| {

View File

@ -299,7 +299,7 @@ where
/// }
/// }
///
/// #[function_component(UseReducer)]
/// #[component(UseReducer)]
/// fn reducer() -> Html {
/// // The use_reducer hook takes an initialization function which will be called only once.
/// let counter = use_reducer(CounterState::default);

View File

@ -34,7 +34,7 @@ impl<T: 'static, F: FnOnce() -> T> Hook for UseRef<F> {
/// use web_sys::HtmlInputElement;
/// use yew::prelude::*;
///
/// #[function_component(UseRef)]
/// #[component(UseRef)]
/// fn ref_hook() -> Html {
/// let message = use_state(|| "".to_string());
/// let message_count = use_ref(|| Cell::new(0));
@ -88,7 +88,7 @@ where
/// use web_sys::HtmlInputElement;
/// use yew::prelude::*;
///
/// #[function_component(UseRef)]
/// #[component(UseRef)]
/// fn ref_hook() -> Html {
/// let message = use_state(|| "".to_string());
/// let message_count = use_mut_ref(|| 0);
@ -141,9 +141,9 @@ where
/// use wasm_bindgen::prelude::Closure;
/// use wasm_bindgen::JsCast;
/// use web_sys::{Event, HtmlElement};
/// use yew::{function_component, html, use_effect_with, use_node_ref, Html};
/// use yew::{component, html, use_effect_with, use_node_ref, Html};
///
/// #[function_component(UseNodeRef)]
/// #[component(UseNodeRef)]
/// pub fn node_ref_hook() -> Html {
/// let div_ref = use_node_ref();
///

View File

@ -40,7 +40,7 @@ where
/// use yew::prelude::*;
/// # use std::rc::Rc;
///
/// #[function_component(UseState)]
/// #[component(UseState)]
/// fn state() -> Html {
/// let counter = use_state(|| 0);
/// let onclick = {

View File

@ -1,5 +1,5 @@
//! Function components are a simplified version of normal components.
//! They consist of a single function annotated with the attribute `#[function_component]`
//! They consist of a single function annotated with the attribute `#[component]`
//! that receives props and determines what should be rendered by returning [`Html`](crate::Html).
//!
//! Functions with the attribute have to return `Html` and may take a single parameter for the type
@ -12,7 +12,7 @@
//! ```rust
//! # use yew::prelude::*;
//! #
//! #[function_component]
//! #[component]
//! fn HelloWorld() -> Html {
//! html! { "Hello world" }
//! }
@ -40,7 +40,7 @@ pub use hooks::*;
/// for props. Note that the function only receives a reference to the props.
///
/// When using this attribute you need to provide a name for the component:
/// `#[function_component(ComponentName)]`.
/// `#component(ComponentName)]`.
/// The attribute will then automatically create a [`FunctionComponent`] with the given
/// identifier which you can use like a normal component.
///
@ -53,13 +53,16 @@ pub use hooks::*;
/// # text: String
/// # }
/// #
/// #[function_component(NameOfComponent)]
/// #[component(NameOfComponent)]
/// pub fn component(props: &Props) -> Html {
/// html! {
/// <p>{ &props.text }</p>
/// }
/// }
/// ```
pub use yew_macro::function_component as component;
/// A re-export of [`component`](yew_macro::function_component) with the older name.
#[deprecated(since = "0.22.0", note = "renamed to `#[component]")]
pub use yew_macro::function_component;
/// This attribute creates a user-defined hook from a normal Rust function.
pub use yew_macro::hook;
@ -310,7 +313,7 @@ pub trait FunctionProvider {
///
/// Function Components should not be implemented with this type directly.
///
/// Use the `#[function_component]` macro instead.
/// Use the `#[component]` macro instead.
#[doc(hidden)]
pub struct FunctionComponent<T>
where

View File

@ -1,6 +1,6 @@
//! Primitive Components & Properties Types
use crate::function_component;
use crate::component;
use crate::html::{BaseComponent, ChildrenProps, Html};
/// A Component to represent a component that does not exist in current implementation.
@ -28,12 +28,12 @@ use crate::html::{BaseComponent, ChildrenProps, Html};
/// use yew::prelude::*;
/// # use yew::html::ChildrenProps;
/// #
/// # #[function_component]
/// # #[component]
/// # fn Comp(props: &ChildrenProps) -> Html {
/// # Html::default()
/// # }
/// #
/// # #[function_component]
/// # #[component]
/// # fn Provider(props: &ChildrenProps) -> Html {
/// # let children = props.children.clone();
/// #
@ -44,7 +44,7 @@ use crate::html::{BaseComponent, ChildrenProps, Html};
/// # type Provider3 = Provider;
/// # type Provider4 = Provider;
///
/// #[function_component]
/// #[component]
/// fn ServerApp() -> Html {
/// // The Server Side Rendering Application has 3 Providers.
/// html! {
@ -58,7 +58,7 @@ use crate::html::{BaseComponent, ChildrenProps, Html};
/// }
/// }
///
/// #[function_component]
/// #[component]
/// fn App() -> Html {
/// // The Client Side Rendering Application has 4 Providers.
/// html! {
@ -85,12 +85,12 @@ use crate::html::{BaseComponent, ChildrenProps, Html};
/// use yew::prelude::*;
/// # use yew::html::{PhantomComponent, ChildrenProps};
/// #
/// # #[function_component]
/// # #[component]
/// # fn Comp(props: &ChildrenProps) -> Html {
/// # Html::default()
/// # }
/// #
/// # #[function_component]
/// # #[component]
/// # fn Provider(props: &ChildrenProps) -> Html {
/// # let children = props.children.clone();
/// #
@ -101,7 +101,7 @@ use crate::html::{BaseComponent, ChildrenProps, Html};
/// # type Provider3 = Provider;
/// # type Provider4 = Provider;
///
/// #[function_component]
/// #[component]
/// fn ServerApp() -> Html {
/// html! {
/// <Provider1>
@ -118,7 +118,7 @@ use crate::html::{BaseComponent, ChildrenProps, Html};
/// }
/// }
///
/// #[function_component]
/// #[component]
/// fn App() -> Html {
/// html! {
/// <Provider1>
@ -137,7 +137,7 @@ use crate::html::{BaseComponent, ChildrenProps, Html};
/// }
/// }
/// ```
#[function_component]
#[component]
pub fn PhantomComponent<T>(props: &ChildrenProps) -> Html
where
T: BaseComponent,

View File

@ -73,7 +73,7 @@ impl<COMP: BaseComponent> Context<COMP> {
/// The common base of both function components and struct components.
///
/// If you are taken here by doc links, you might be looking for [`Component`] or
/// [`#[function_component]`](crate::functional::function_component).
/// [`#[component]`](crate::functional::component).
///
/// We provide a blanket implementation of this trait for every member that implements
/// [`Component`].
@ -84,7 +84,7 @@ impl<COMP: BaseComponent> Context<COMP> {
/// implementation.
///
/// You should used the [`Component`] trait or the
/// [`#[function_component]`](crate::functional::function_component) macro to define your
/// [`#[component]`](crate::functional::component) macro to define your
/// components.
pub trait BaseComponent: Sized + 'static {
/// The Component's Message.

View File

@ -367,7 +367,7 @@ mod test {
pub footer: Children,
}
#[function_component]
#[component]
pub fn App(props: &Props) -> Html {
let Props {
header,
@ -405,7 +405,7 @@ mod test {
fn test_vchild_to_children_with_props_compiles() {
use crate::prelude::*;
#[function_component]
#[component]
pub fn Comp() -> Html {
Html::default()
}
@ -420,7 +420,7 @@ mod test {
pub footer: ChildrenWithProps<Comp>,
}
#[function_component]
#[component]
pub fn App(props: &Props) -> Html {
let Props {
header,
@ -459,7 +459,7 @@ mod test {
use crate::prelude::*;
use crate::virtual_dom::VList;
#[function_component]
#[component]
fn Foo() -> Html {
todo!()
}
@ -470,7 +470,7 @@ mod test {
pub children: Html,
}
#[function_component]
#[component]
fn Child(_props: &ChildProps) -> Html {
html!()
}
@ -480,7 +480,7 @@ mod test {
pub children: VList,
}
#[function_component]
#[component]
fn Parent(_props: &ParentProps) -> Html {
todo!()
}
@ -517,7 +517,7 @@ mod test {
pub children: AttrValue,
}
#[function_component]
#[component]
fn Child(_props: &ChildProps) -> Html {
html!()
}

View File

@ -20,7 +20,7 @@ mod feat_csr_ssr {
#[cfg(feature = "hydration")]
use crate::suspense::SuspensionHandle;
use crate::virtual_dom::{VNode, VSuspense};
use crate::{function_component, html};
use crate::{component, html};
#[derive(Properties, PartialEq, Debug, Clone)]
pub(crate) struct BaseSuspenseProps {
@ -147,7 +147,7 @@ mod feat_csr_ssr {
}
/// Suspend rendering and show a fallback UI until the underlying task completes.
#[function_component]
#[component]
pub fn Suspense(props: &SuspenseProps) -> Html {
let SuspenseProps { children, fallback } = props.clone();
@ -171,10 +171,10 @@ pub use feat_csr_ssr::*;
#[cfg(not(any(feature = "ssr", feature = "csr")))]
mod feat_no_csr_ssr {
use super::*;
use crate::function_component;
use crate::component;
/// Suspend rendering and show a fallback UI until the underlying task completes.
#[function_component]
#[component]
pub fn Suspense(_props: &SuspenseProps) -> Html {
Html::default()
}

View File

@ -58,7 +58,7 @@ impl<T: fmt::Debug> fmt::Debug for UseFutureHandle<T> {
/// action=query&origin=*&format=json&generator=search&\
/// gsrnamespace=0&gsrlimit=5&gsrsearch='New_England_Patriots'";
///
/// #[function_component]
/// #[component]
/// fn WikipediaSearch() -> HtmlResult {
/// let res = use_future(|| async { Request::get(URL).send().await?.text().await })?;
/// let result_html = match *res {

View File

@ -290,12 +290,12 @@ mod ssr_tests {
name: String,
}
#[function_component]
#[component]
fn Child(props: &ChildProps) -> Html {
html! { <div>{"Hello, "}{&props.name}{"!"}</div> }
}
#[function_component]
#[component]
fn Comp() -> Html {
html! {
<div>

View File

@ -301,7 +301,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_text_back_to_back() {
#[function_component]
#[component]
fn Comp() -> Html {
let s = "world";
@ -324,12 +324,12 @@ mod ssr_tests {
name: String,
}
#[function_component]
#[component]
fn Child(props: &ChildProps) -> Html {
html! { <div>{"Hello, "}{&props.name}{"!"}</div> }
}
#[function_component]
#[component]
fn Comp() -> Html {
html! {
<>

View File

@ -124,13 +124,13 @@ mod ssr_tests {
name: String,
}
#[function_component]
#[component]
fn Child(props: &ChildProps) -> HtmlResult {
use_sleep()?;
Ok(html! { <div>{"Hello, "}{&props.name}{"!"}</div> })
}
#[function_component]
#[component]
fn Comp() -> Html {
let fallback = html! {"loading..."};

View File

@ -573,7 +573,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_simple_tag() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { <div></div> }
}
@ -589,7 +589,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_simple_tag_with_attr() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { <div class="abc"></div> }
}
@ -605,7 +605,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_simple_tag_with_content() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { <div>{"Hello!"}</div> }
}
@ -621,7 +621,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_simple_tag_with_nested_tag_and_input() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { <div>{"Hello!"}<input value="abc" type="text" /></div> }
}
@ -637,7 +637,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_textarea() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { <textarea value="teststring" /> }
}
@ -653,7 +653,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_textarea_w_defaultvalue() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { <textarea defaultvalue="teststring" /> }
}
@ -669,7 +669,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_value_precedence_over_defaultvalue() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { <textarea defaultvalue="defaultvalue" value="value" /> }
}
@ -685,7 +685,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_escaping_in_style_tag() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { <style>{"body > a {color: #cc0;}"}</style> }
}
@ -701,7 +701,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_escaping_in_script_tag() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { <script>{"foo.bar = x < y;"}</script> }
}
@ -717,7 +717,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_multiple_vtext_in_style_tag() {
#[function_component]
#[component]
fn Comp() -> Html {
let one = "html { background: black } ";
let two = "body > a { color: white } ";

View File

@ -80,7 +80,7 @@ mod ssr_tests {
#[cfg_attr(not(target_os = "wasi"), test)]
#[cfg_attr(target_os = "wasi", test(flavor = "current_thread"))]
async fn test_simple_str() {
#[function_component]
#[component]
fn Comp() -> Html {
html! { "abc" }
}

View File

@ -16,7 +16,7 @@ use yew::platform::time::sleep;
use yew::prelude::*;
use yew::suspense::{use_future, Suspension, SuspensionResult};
use yew::virtual_dom::VNode;
use yew::{function_component, Renderer, ServerRenderer};
use yew::{component, Renderer, ServerRenderer};
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
@ -25,7 +25,7 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
async fn hydration_works() {
#[function_component]
#[component]
fn Comp() -> Html {
let ctr = use_state_eq(|| 0);
@ -45,7 +45,7 @@ async fn hydration_works() {
}
}
#[function_component]
#[component]
fn App() -> Html {
html! {
<div>
@ -97,7 +97,7 @@ async fn hydration_works() {
#[wasm_bindgen_test]
async fn hydration_with_raw() {
#[function_component(Content)]
#[component(Content)]
fn content() -> Html {
let vnode = VNode::from_html_unchecked("<div><p>Hello World</p></div>".into());
@ -108,7 +108,7 @@ async fn hydration_with_raw() {
}
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
html! {
<div id="result">
@ -189,7 +189,7 @@ async fn hydration_with_suspense() {
}
}
#[function_component(Content)]
#[component(Content)]
fn content() -> HtmlResult {
let resleep = use_sleep()?;
@ -216,7 +216,7 @@ async fn hydration_with_suspense() {
})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"wait..."}</div>};
@ -344,7 +344,7 @@ async fn hydration_with_suspense_not_suspended_at_start() {
}
}
#[function_component(Content)]
#[component(Content)]
fn content() -> HtmlResult {
let resleep = use_sleep()?;
@ -372,7 +372,7 @@ async fn hydration_with_suspense_not_suspended_at_start() {
})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"wait..."}</div>};
@ -468,7 +468,7 @@ async fn hydration_nested_suspense_works() {
}
}
#[function_component(InnerContent)]
#[component(InnerContent)]
fn inner_content() -> HtmlResult {
let resleep = use_sleep()?;
@ -483,7 +483,7 @@ async fn hydration_nested_suspense_works() {
})
}
#[function_component(Content)]
#[component(Content)]
fn content() -> HtmlResult {
let resleep = use_sleep()?;
@ -503,7 +503,7 @@ async fn hydration_nested_suspense_works() {
})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"wait...(outer)"}</div>};
@ -602,7 +602,7 @@ async fn hydration_nested_suspense_works() {
#[wasm_bindgen_test]
async fn hydration_node_ref_works() {
#[function_component(App)]
#[component(App)]
pub fn app() -> Html {
let size = use_state(|| 4);
@ -625,20 +625,20 @@ async fn hydration_node_ref_works() {
size: u32,
}
#[function_component(Test1)]
#[component(Test1)]
fn test1() -> Html {
html! {
<span>{"test"}</span>
}
}
#[function_component(Test2)]
#[component(Test2)]
fn test2() -> Html {
html! {
<Test1/>
}
}
#[function_component(List)]
#[component(List)]
fn list(props: &ListProps) -> Html {
let elems = 0..props.size;
@ -693,7 +693,7 @@ async fn hydration_node_ref_works() {
#[wasm_bindgen_test]
async fn hydration_list_order_works() {
#[function_component(App)]
#[component(App)]
pub fn app() -> Html {
let elems = 0..10;
@ -713,20 +713,20 @@ async fn hydration_list_order_works() {
number: u32,
}
#[function_component(Number)]
#[component(Number)]
fn number(props: &NumberProps) -> Html {
html! {
<div>{props.number.to_string()}</div>
}
}
#[function_component(SuspendedNumber)]
#[component(SuspendedNumber)]
fn suspended_number(props: &NumberProps) -> HtmlResult {
use_suspend()?;
Ok(html! {
<div>{props.number.to_string()}</div>
})
}
#[function_component(ToSuspendOrNot)]
#[component(ToSuspendOrNot)]
fn suspend_or_not(props: &NumberProps) -> Html {
let number = props.number;
html! {
@ -776,7 +776,7 @@ async fn hydration_list_order_works() {
#[wasm_bindgen_test]
async fn hydration_suspense_no_flickering() {
#[function_component(App)]
#[component(App)]
pub fn app() -> Html {
let fallback = html! { <h1>{"Loading..."}</h1> };
html! {
@ -791,7 +791,7 @@ async fn hydration_suspense_no_flickering() {
number: u32,
}
#[function_component(SuspendedNumber)]
#[component(SuspendedNumber)]
fn suspended_number(props: &NumberProps) -> HtmlResult {
use_suspend()?;
@ -799,7 +799,7 @@ async fn hydration_suspense_no_flickering() {
<Number ..{props.clone()}/>
})
}
#[function_component(Number)]
#[component(Number)]
fn number(props: &NumberProps) -> Html {
html! {
<div>
@ -808,7 +808,7 @@ async fn hydration_suspense_no_flickering() {
}
}
#[function_component(Suspended)]
#[component(Suspended)]
fn suspended() -> HtmlResult {
use_suspend()?;
@ -886,7 +886,7 @@ async fn hydration_suspense_no_flickering() {
#[wasm_bindgen_test]
async fn hydration_order_issue_nested_suspense() {
#[function_component(App)]
#[component(App)]
pub fn app() -> Html {
let elems = (0..10).map(|number: u32| {
html! {
@ -906,14 +906,14 @@ async fn hydration_order_issue_nested_suspense() {
number: u32,
}
#[function_component(Number)]
#[component(Number)]
fn number(props: &NumberProps) -> Html {
html! {
<div>{props.number.to_string()}</div>
}
}
#[function_component(SuspendedNumber)]
#[component(SuspendedNumber)]
fn suspended_number(props: &NumberProps) -> HtmlResult {
use_suspend()?;
Ok(html! {
@ -921,7 +921,7 @@ async fn hydration_order_issue_nested_suspense() {
})
}
#[function_component(ToSuspendOrNot)]
#[component(ToSuspendOrNot)]
fn suspend_or_not(props: &NumberProps) -> HtmlResult {
let number = props.number;
Ok(html! {
@ -972,7 +972,7 @@ async fn hydration_order_issue_nested_suspense() {
#[wasm_bindgen_test]
async fn hydration_props_blocked_until_hydrated() {
#[function_component(App)]
#[component(App)]
pub fn app() -> Html {
let range = use_state(|| 0u32..2);
{
@ -995,7 +995,7 @@ async fn hydration_props_blocked_until_hydrated() {
range: Range<u32>,
}
#[function_component(ToSuspend)]
#[component(ToSuspend)]
fn to_suspend(ToSuspendProps { range }: &ToSuspendProps) -> HtmlResult {
use_suspend(Duration::from_millis(100))?;
Ok(html! {
@ -1032,7 +1032,7 @@ async fn hydration_props_blocked_until_hydrated() {
#[wasm_bindgen_test]
async fn hydrate_empty() {
#[function_component]
#[component]
fn Updating() -> Html {
let trigger = use_state(|| false);
{
@ -1048,11 +1048,11 @@ async fn hydrate_empty() {
html! { <div>{"before"}</div> }
}
}
#[function_component]
#[component]
fn Empty() -> Html {
html! { <></> }
}
#[function_component]
#[component]
fn App() -> Html {
html! {
<>

View File

@ -14,7 +14,7 @@ use yew::prelude::*;
#[wasm_bindgen_test]
async fn change_nested_after_append() {
#[function_component]
#[component]
fn Nested() -> Html {
let delayed_trigger = use_state(|| true);
@ -36,12 +36,12 @@ async fn change_nested_after_append() {
}
}
#[function_component]
#[component]
fn Top() -> Html {
html! { <Nested /> }
}
#[function_component]
#[component]
fn App() -> Html {
let show_bottom = use_state_eq(|| false);

View File

@ -18,7 +18,7 @@ async fn props_are_passed() {
value: String,
}
#[function_component]
#[component]
fn PropsComponent(props: &PropsPassedFunctionProps) -> Html {
assert_eq!(&props.value, "props");
html! {

View File

@ -17,7 +17,7 @@ macro_rules! create_test {
($name:ident, $raw:expr, $expected:expr) => {
#[test]
async fn $name() {
#[function_component]
#[component]
fn App() -> Html {
let raw = Html::from_html_unchecked(AttrValue::from($raw));
html! {
@ -78,7 +78,7 @@ macro_rules! create_update_html_test {
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
#[test]
async fn $name() {
#[function_component]
#[component]
fn App() -> Html {
let raw_html = use_state(|| ($initial));
let onclick = {
@ -159,7 +159,7 @@ create_update_html_test!(
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
#[test]
async fn change_vnode_types_from_other_to_vraw() {
#[function_component]
#[component]
fn App() -> Html {
let node = use_state(|| html!("text"));
let onclick = {
@ -211,7 +211,7 @@ async fn change_vnode_types_from_other_to_vraw() {
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
#[test]
async fn change_vnode_types_from_vraw_to_other() {
#[function_component]
#[component]
fn App() -> Html {
let node = use_state(|| Html::from_html_unchecked(AttrValue::from("<span>second</span>")));
let onclick = {

View File

@ -58,7 +58,7 @@ async fn suspense_works() {
}
}
#[function_component(Content)]
#[component(Content)]
fn content() -> HtmlResult {
let resleep = use_sleep()?;
@ -85,7 +85,7 @@ async fn suspense_works() {
})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"wait..."}</div>};
@ -207,7 +207,7 @@ async fn suspense_not_suspended_at_start() {
}
}
#[function_component(Content)]
#[component(Content)]
fn content() -> HtmlResult {
let resleep = use_sleep()?;
@ -235,7 +235,7 @@ async fn suspense_not_suspended_at_start() {
})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"wait..."}</div>};
@ -319,7 +319,7 @@ async fn suspense_nested_suspense_works() {
}
}
#[function_component(InnerContent)]
#[component(InnerContent)]
fn inner_content() -> HtmlResult {
let resleep = use_sleep()?;
@ -334,7 +334,7 @@ async fn suspense_nested_suspense_works() {
})
}
#[function_component(Content)]
#[component(Content)]
fn content() -> HtmlResult {
let resleep = use_sleep()?;
@ -354,7 +354,7 @@ async fn suspense_nested_suspense_works() {
})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"wait...(outer)"}</div>};
@ -465,7 +465,7 @@ async fn effects_not_run_when_suspended() {
}
}
#[function_component(Content)]
#[component(Content)]
fn content(props: &Props) -> HtmlResult {
{
let counter = props.counter.clone();
@ -504,7 +504,7 @@ async fn effects_not_run_when_suspended() {
})
}
#[function_component(App)]
#[component(App)]
fn app(props: &Props) -> Html {
let fallback = html! {<div>{"wait..."}</div>};
@ -597,7 +597,7 @@ async fn effects_not_run_when_suspended() {
#[wasm_bindgen_test]
async fn use_suspending_future_works() {
#[function_component(Content)]
#[component(Content)]
fn content() -> HtmlResult {
let _sleep_handle = use_future(|| async move {
sleep(Duration::from_millis(50)).await;
@ -610,7 +610,7 @@ async fn use_suspending_future_works() {
})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"wait..."}</div>};
@ -643,7 +643,7 @@ async fn use_suspending_future_with_deps_works() {
delay_millis: u64,
}
#[function_component(Content)]
#[component(Content)]
fn content(ContentProps { delay_millis }: &ContentProps) -> HtmlResult {
let delayed_result = use_future_with(*delay_millis, |delay_millis| async move {
sleep(Duration::from_millis(*delay_millis)).await;
@ -657,7 +657,7 @@ async fn use_suspending_future_with_deps_works() {
})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"wait..."}</div>};
@ -687,14 +687,14 @@ async fn use_suspending_future_with_deps_works() {
async fn test_suspend_forever() {
/// A component that its suspension never resumes.
/// We test that this can be used with to trigger a suspension and unsuspend upon unmount.
#[function_component]
#[component]
fn SuspendForever() -> HtmlResult {
let (s, handle) = Suspension::new();
use_state(move || handle);
Err(s.into())
}
#[function_component]
#[component]
fn App() -> Html {
let page = use_state(|| 1);
@ -737,7 +737,7 @@ async fn resume_after_unmount() {
state: UseStateHandle<bool>,
}
#[function_component(Content)]
#[component(Content)]
fn content(ContentProps { state }: &ContentProps) -> HtmlResult {
let state = state.clone();
let _sleep_handle = use_future(|| async move {
@ -751,7 +751,7 @@ async fn resume_after_unmount() {
})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"wait..."}</div>};
let state = use_state(|| true);
@ -785,7 +785,7 @@ async fn resume_after_unmount() {
async fn test_duplicate_suspension() {
use yew::html::ChildrenProps;
#[function_component]
#[component]
fn FetchingProvider(props: &ChildrenProps) -> HtmlResult {
use_future(|| async {
sleep(Duration::ZERO).await;
@ -793,12 +793,12 @@ async fn test_duplicate_suspension() {
Ok(html! { <>{props.children.clone()}</> })
}
#[function_component]
#[component]
fn Child() -> Html {
html! {<div id="result">{"hello!"}</div>}
}
#[function_component]
#[component]
fn App() -> Html {
let fallback = Html::default();
html! {

View File

@ -20,7 +20,7 @@ async fn use_callback_works() {
callback: Callback<String, String>,
}
#[function_component(MyComponent)]
#[component(MyComponent)]
fn my_component(props: &Props) -> Html {
let greeting = props.callback.emit("Yew".to_string());
@ -39,7 +39,7 @@ async fn use_callback_works() {
}
}
#[function_component(UseCallbackComponent)]
#[component(UseCallbackComponent)]
fn use_callback_comp() -> Html {
let state = use_state(|| 0);

View File

@ -17,7 +17,7 @@ async fn use_context_scoping_works() {
#[derive(Clone, Debug, PartialEq)]
struct ExampleContext(String);
#[function_component]
#[component]
fn ExpectNoContextComponent() -> Html {
let example_context = use_context::<ExampleContext>();
@ -32,7 +32,7 @@ async fn use_context_scoping_works() {
}
}
#[function_component]
#[component]
fn UseContextComponent() -> Html {
type ExampleContextProvider = ContextProvider<ExampleContext>;
html! {
@ -56,7 +56,7 @@ async fn use_context_scoping_works() {
}
}
#[function_component]
#[component]
fn UseContextComponentInner() -> Html {
let context = use_context::<ExampleContext>();
html! {
@ -82,7 +82,7 @@ async fn use_context_works_with_multiple_types() {
#[derive(Clone, Debug, PartialEq)]
struct ContextB(u32);
#[function_component]
#[component]
fn Test1() -> Html {
let ctx_a = use_context::<ContextA>();
let ctx_b = use_context::<ContextB>();
@ -93,7 +93,7 @@ async fn use_context_works_with_multiple_types() {
html! {}
}
#[function_component]
#[component]
fn Test2() -> Html {
let ctx_a = use_context::<ContextA>();
let ctx_b = use_context::<ContextB>();
@ -104,7 +104,7 @@ async fn use_context_works_with_multiple_types() {
html! {}
}
#[function_component]
#[component]
fn Test3() -> Html {
let ctx_a = use_context::<ContextA>();
let ctx_b = use_context::<ContextB>();
@ -115,7 +115,7 @@ async fn use_context_works_with_multiple_types() {
html! {}
}
#[function_component]
#[component]
fn Test4() -> Html {
let ctx_a = use_context::<ContextA>();
let ctx_b = use_context::<ContextB>();
@ -126,7 +126,7 @@ async fn use_context_works_with_multiple_types() {
html! {}
}
#[function_component]
#[component]
fn TestComponent() -> Html {
type ContextAProvider = ContextProvider<ContextA>;
type ContextBProvider = ContextProvider<ContextB>;
@ -166,7 +166,7 @@ async fn use_context_update_works() {
children: Children,
}
#[function_component]
#[component]
fn RenderCounter(props: &RenderCounterProps) -> Html {
let counter = use_mut_ref(|| 0);
*counter.borrow_mut() += 1;
@ -187,7 +187,7 @@ async fn use_context_update_works() {
magic: usize,
}
#[function_component]
#[component]
fn ContextOutlet(props: &ContextOutletProps) -> Html {
let counter = use_mut_ref(|| 0);
*counter.borrow_mut() += 1;
@ -204,7 +204,7 @@ async fn use_context_update_works() {
}
}
#[function_component]
#[component]
fn TestComponent() -> Html {
type MyContextProvider = ContextProvider<Rc<MyContext>>;

View File

@ -35,7 +35,7 @@ async fn use_effect_destroys_on_component_drop() {
}
}
#[function_component(UseEffectComponent)]
#[component(UseEffectComponent)]
fn use_effect_comp(props: &FunctionProps) -> Html {
let effect_called = props.effect_called.clone();
let destroy_called = props.destroy_called.clone();
@ -47,7 +47,7 @@ async fn use_effect_destroys_on_component_drop() {
html! {}
}
#[function_component(UseEffectWrapperComponent)]
#[component(UseEffectWrapperComponent)]
fn use_effect_wrapper_comp(props: &WrapperProps) -> Html {
let show = use_state(|| true);
if *show {
@ -79,7 +79,7 @@ async fn use_effect_destroys_on_component_drop() {
#[wasm_bindgen_test]
async fn use_effect_works_many_times() {
#[function_component(UseEffectComponent)]
#[component(UseEffectComponent)]
fn use_effect_comp() -> Html {
let counter = use_state(|| 0);
let counter_clone = counter.clone();
@ -112,7 +112,7 @@ async fn use_effect_works_many_times() {
#[wasm_bindgen_test]
async fn use_effect_works_once() {
#[function_component(UseEffectComponent)]
#[component(UseEffectComponent)]
fn use_effect_comp() -> Html {
let counter = use_state(|| 0);
let counter_clone = counter.clone();
@ -144,7 +144,7 @@ async fn use_effect_works_once() {
#[wasm_bindgen_test]
async fn use_effect_refires_on_dependency_change() {
#[function_component(UseEffectComponent)]
#[component(UseEffectComponent)]
fn use_effect_comp() -> Html {
let number_ref = use_mut_ref(|| 0);
let number_ref_c = number_ref.clone();

View File

@ -15,7 +15,7 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
async fn use_memo_works() {
#[function_component(UseMemoComponent)]
#[component(UseMemoComponent)]
fn use_memo_comp() -> Html {
let state = use_state(|| 0);

View File

@ -16,7 +16,7 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
async fn use_prepared_state_works() {
#[function_component]
#[component]
fn Comp() -> HtmlResult {
let ctr = use_prepared_state!((), |_| -> u32 { 12345 })?.unwrap_or_default();
@ -27,7 +27,7 @@ async fn use_prepared_state_works() {
})
}
#[function_component]
#[component]
fn App() -> Html {
html! {
<Suspense fallback={Html::default()}>
@ -66,7 +66,7 @@ async fn use_prepared_state_works() {
#[wasm_bindgen_test]
async fn use_prepared_state_with_suspension_works() {
#[function_component]
#[component]
fn Comp() -> HtmlResult {
let ctr = use_prepared_state!((), async move |_| -> u32 { 12345 })?.unwrap_or_default();
@ -77,7 +77,7 @@ async fn use_prepared_state_with_suspension_works() {
})
}
#[function_component]
#[component]
fn App() -> Html {
html! {
<Suspense fallback={Html::default()}>

View File

@ -35,7 +35,7 @@ impl Reducible for CounterState {
#[wasm_bindgen_test]
async fn use_reducer_works() {
#[function_component(UseReducerComponent)]
#[component(UseReducerComponent)]
fn use_reducer_comp() -> Html {
let counter = use_reducer(|| CounterState { counter: 10 });
@ -80,7 +80,7 @@ impl Reducible for ContentState {
#[wasm_bindgen_test]
async fn use_reducer_eq_works() {
#[function_component(UseReducerComponent)]
#[component(UseReducerComponent)]
fn use_reducer_comp() -> Html {
let content = use_reducer_eq(|| ContentState {
content: HashSet::default(),

View File

@ -14,7 +14,7 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
async fn use_ref_works() {
#[function_component(UseRefComponent)]
#[component(UseRefComponent)]
fn use_ref_comp() -> Html {
let ref_example = use_mut_ref(|| 0);
*ref_example.borrow_mut().deref_mut() += 1;

View File

@ -13,7 +13,7 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
async fn use_state_works() {
#[function_component(UseComponent)]
#[component(UseComponent)]
fn use_state_comp() -> Html {
let counter = use_state(|| 0);
if *counter < 5 {
@ -39,7 +39,7 @@ async fn use_state_works() {
#[wasm_bindgen_test]
async fn multiple_use_state_setters() {
#[function_component(UseComponent)]
#[component(UseComponent)]
fn use_state_comp() -> Html {
let counter = use_state(|| 0);
let counter_clone = counter.clone();
@ -82,7 +82,7 @@ async fn use_state_eq_works() {
use std::sync::atomic::{AtomicUsize, Ordering};
static RENDER_COUNT: AtomicUsize = AtomicUsize::new(0);
#[function_component(UseComponent)]
#[component(UseComponent)]
fn use_state_comp() -> Html {
RENDER_COUNT.fetch_add(1, Ordering::Relaxed);
let counter = use_state_eq(|| 0);

View File

@ -15,7 +15,7 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
async fn use_transitive_state_works() {
#[function_component]
#[component]
fn Comp() -> HtmlResult {
let ctr = use_transitive_state!((), |_| -> u32 { 12345 })?.unwrap_or_default();
@ -26,7 +26,7 @@ async fn use_transitive_state_works() {
})
}
#[function_component]
#[component]
fn App() -> Html {
html! {
<Suspense fallback={Html::default()}>

View File

@ -115,7 +115,7 @@ pub struct ListItemProps {
value: String,
}
#[function_component]
#[component]
fn ListItem(props: &ListItemProps) -> Html {
let ListItemProps { value } = props.clone();
html! {
@ -130,7 +130,7 @@ pub struct Props {
pub children: ChildrenWithProps<ListItem>,
}
#[function_component]
#[component]
fn List(props: &Props) -> Html {
let modified_children = props.children.iter().map(|mut item| {
let mut props = Rc::make_mut(&mut item.props);

View File

@ -31,7 +31,7 @@ pub struct ModalProps {
pub children: Html,
}
#[function_component]
#[component]
fn Modal(props: &ModalProps) -> Html {
let modal_host = gloo::utils::document()
.get_element_by_id("modal_host")

View File

@ -34,7 +34,7 @@ to render `<App />` into a `String`.
use yew::prelude::*;
use yew::ServerRenderer;
#[function_component]
#[component]
fn App() -> Html {
html! {<div>{"Hello, World!"}</div>}
}
@ -178,7 +178,7 @@ until `rendered()` method is called.
use yew::prelude::*;
use yew::Renderer;
#[function_component]
#[component]
fn App() -> Html {
html! {<div>{"Hello, World!"}</div>}
}
@ -206,7 +206,7 @@ Yew supports single thread mode for server-side rendering by `yew::LocalServerRe
use yew::prelude::*;
use yew::LocalServerRenderer;
#[function_component]
#[component]
fn App() -> Html {
use yew_router::prelude::*;

View File

@ -23,7 +23,7 @@ struct Theme {
background: String,
}
#[function_component]
#[component]
pub fn App() -> Html {
let ctx = use_state(|| Theme {
foreground: "#000000".to_owned(),
@ -38,7 +38,7 @@ pub fn App() -> Html {
}
// highlight-start
#[function_component]
#[component]
pub fn ThemedButtonHOC() -> Html {
let theme = use_context::<Theme>().expect("no ctx found");

View File

@ -21,7 +21,7 @@ This situation is called "Prop Drilling".
Consider the following example which passes down the theme using props:
```rust
use yew::{html, Component, Context, Html, Properties, function_component};
use yew::{html, Component, Context, Html, Properties, component};
#[derive(Clone, PartialEq)]
pub struct Theme {
@ -34,7 +34,7 @@ pub struct NavbarProps {
theme: Theme,
}
#[function_component]
#[component]
fn Navbar(props: &NavbarProps) -> Html {
html! {
<div>
@ -54,14 +54,14 @@ pub struct ThemeProps {
children: Html,
}
#[function_component]
#[component]
fn Title(_props: &ThemeProps) -> Html {
html! {
// impl
}
}
#[function_component]
#[component]
fn NavButton(_props: &ThemeProps) -> Html {
html! {
// impl
@ -69,7 +69,7 @@ fn NavButton(_props: &ThemeProps) -> Html {
}
/// App root
#[function_component]
#[component]
fn App() -> Html {
let theme = Theme {
foreground: "yellow".to_owned(),
@ -107,7 +107,7 @@ struct Theme {
}
/// Main component
#[function_component]
#[component]
pub fn App() -> Html {
let ctx = use_state(|| Theme {
foreground: "#000000".to_owned(),
@ -127,7 +127,7 @@ pub fn App() -> Html {
/// The toolbar.
/// This component has access to the context
#[function_component]
#[component]
pub fn Toolbar() -> Html {
html! {
<div>
@ -139,7 +139,7 @@ pub fn Toolbar() -> Html {
/// Button placed in `Toolbar`.
/// As this component is a child of `ThemeContextProvider` in the component tree, it also has access
/// to the context.
#[function_component]
#[component]
pub fn ThemedButton() -> Html {
let theme = use_context::<Theme>().expect("no ctx found");

View File

@ -23,14 +23,14 @@ let result = cb.emit(String::from("Bob")); // call the callback
A common pattern in yew is to create a callback and pass it down as a prop.
```rust
use yew::{function_component, html, Html, Properties, Callback};
use yew::{component, html, Html, Properties, Callback};
#[derive(Properties, PartialEq)]
pub struct Props {
pub on_name_entry: Callback<String>,
}
#[function_component]
#[component]
fn HelloWorld(props: &Props) -> Html {
props.on_name_entry.emit(String::from("Bob"));
@ -39,7 +39,7 @@ fn HelloWorld(props: &Props) -> Html {
}
// Then supply the prop
#[function_component]
#[component]
fn App() -> Html {
let on_name_entry: Callback<String> = Callback::from(move |name: String| {
let greeting = format!("Hey, {}!", name);
@ -58,9 +58,9 @@ Callbacks are also used to hook into DOM events.
For example, here we define a callback that will be called when the user clicks the button:
```rust
use yew::{function_component, html, Html, Properties, Callback};
use yew::{component, html, Html, Properties, Callback};
#[function_component]
#[component]
fn App() -> Html {
let onclick = Callback::from(move |_| {
let greeting = String::from("Hi there");

View File

@ -5,9 +5,9 @@ title: 'Children'
`Children` is a special prop type that allows you to receive nested `Html` that is provided like html child elements.
```rust
use yew::{function_component, html, Html, Properties};
use yew::{component, html, Html, Properties};
#[function_component]
#[component]
fn App() -> Html {
html! {
// highlight-start
@ -25,7 +25,7 @@ pub struct Props {
pub children: Html, // the field name `children` is important!
}
#[function_component]
#[component]
fn HelloWorld(props: &Props) -> Html {
html! {
<div class="very-stylized-container">

View File

@ -1,16 +1,16 @@
---
title: 'Generic Components'
description: 'The #[function_component] attribute'
description: 'The #[component] attribute'
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
The `#[function_component]` attribute also works with generic functions for creating generic components.
The `#[component]` attribute also works with generic functions for creating generic components.
```rust
use std::fmt::Display;
use yew::{function_component, html, Properties, Html};
use yew::{component, html, Properties, Html};
#[derive(Properties, PartialEq)]
pub struct Props<T>
@ -20,7 +20,7 @@ where
data: T,
}
#[function_component]
#[component]
pub fn MyGenericComponent<T>(props: &Props<T>) -> Html
where
T: PartialEq + Clone + Into<Html>,

View File

@ -16,7 +16,7 @@ use gloo::utils::window;
use std::mem::drop;
#[function_component(ShowStorageChanged)]
#[component(ShowStorageChanged)]
pub fn show_storage_changed() -> Html {
let state_storage_changed = use_state(|| false);

View File

@ -31,20 +31,20 @@ They allow very detailed control, though you will not need that level of detail
## Creating function components
To create a function component add the `#[function_component]` attribute to a function.
To create a function component add the `#[component]` attribute to a function.
By convention, the function is named in PascalCase, like all components, to contrast its
use to normal html elements inside the `html!` macro.
```rust
use yew::{function_component, html, Html};
use yew::{component, html, Html};
#[function_component]
#[component]
fn HelloWorld() -> Html {
html! { "Hello world" }
}
// Then somewhere else you can use the component inside `html!`
#[function_component]
#[component]
fn App() -> Html {
html! { <HelloWorld /> }
}

View File

@ -45,27 +45,27 @@ pub struct Props {
## Use in function components
The attribute `#[function_component]` allows to optionally receive Props in the function arguments. To supply them,
The attribute `#[component]` allows to optionally receive Props in the function arguments. To supply them,
they are assigned via attributes in the `html!` macro.
<Tabs>
<TabItem value="with-props" label="With Props">
```rust
use yew::{function_component, html, Html, Properties};
use yew::{component, html, Html, Properties};
#[derive(Properties, PartialEq)]
pub struct Props {
pub is_loading: bool,
}
#[function_component]
#[component]
fn HelloWorld(&Props { is_loading }: &Props) -> Html {
html! { <>{"Am I loading? - "}{is_loading}</> }
}
// Then supply the prop
#[function_component]
#[component]
fn App() -> Html {
html! { <HelloWorld is_loading=true /> }
}
@ -76,15 +76,15 @@ fn App() -> Html {
<TabItem value="no-props" label="No Props">
```rust
use yew::{function_component, html, Html};
use yew::{component, html, Html};
#[function_component]
#[component]
fn HelloWorld() -> Html {
html! { "Hello world" }
}
// No props to supply
#[function_component]
#[component]
fn App() -> Html {
html! { <HelloWorld /> }
}
@ -110,7 +110,7 @@ The doc strings of your properties should mention whether a prop is optional and
Initialize the prop value with the default value of the field's type using the `Default` trait.
```rust
use yew::{function_component, html, Html, Properties};
use yew::{component, html, Html, Properties};
#[derive(Properties, PartialEq)]
pub struct Props {
@ -120,7 +120,7 @@ pub struct Props {
pub is_loading: bool,
}
#[function_component]
#[component]
fn HelloWorld(&Props { is_loading }: &Props) -> Html {
if is_loading {
html! { "Loading" }
@ -130,12 +130,12 @@ fn HelloWorld(&Props { is_loading }: &Props) -> Html {
}
// Then use like this with default
#[function_component]
#[component]
fn Case1() -> Html {
html! { <HelloWorld /> }
}
// Or no override the default
#[function_component]
#[component]
fn Case2() -> Html {
html! { <HelloWorld is_loading=true /> }
}
@ -161,7 +161,7 @@ pub struct Props {
pub name: AttrValue,
}
#[function_component]
#[component]
fn Hello(&Props { is_loading, ref name }: &Props) -> Html {
if is_loading {
html! { "Loading" }
@ -171,12 +171,12 @@ fn Hello(&Props { is_loading, ref name }: &Props) -> Html {
}
// Then use like this with default
#[function_component]
#[component]
fn Case1() -> Html {
html! { <Hello /> }
}
// Or no override the default
#[function_component]
#[component]
fn Case2() -> Html {
html! { <Hello name="Sam" /> }
}
@ -205,7 +205,7 @@ pub struct Props {
pub name: AttrValue,
}
#[function_component]
#[component]
fn Hello(&Props { is_loading, ref name }: &Props) -> Html {
if is_loading {
html! { "Loading" }
@ -215,12 +215,12 @@ fn Hello(&Props { is_loading, ref name }: &Props) -> Html {
}
// Then use like this with default
#[function_component]
#[component]
fn Case1() -> Html {
html! { <Hello /> }
}
// Or no override the default
#[function_component]
#[component]
fn Case2() -> Html {
html! { <Hello name="Sam" /> }
}
@ -256,7 +256,7 @@ pub struct Props {
pub name: AttrValue,
}
#[function_component]
#[component]
fn Hello(&Props { is_loading, ref name }: &Props) -> Html {
if is_loading {
html! { "Loading" }
@ -265,7 +265,7 @@ fn Hello(&Props { is_loading, ref name }: &Props) -> Html {
}
}
#[function_component]
#[component]
fn App() -> Html {
// highlight-start
let pre_made_props = yew::props! {
@ -286,9 +286,9 @@ generate the `Properties` struct for you.
use yew::prelude::*;
use yew_autoprops::autoprops;
// the #[autoprops] macro must appear BEFORE #[function_component], the order matters
// the #[autoprops] macro must appear BEFORE #[component], the order matters
#[autoprops]
#[function_component]
#[component]
fn Greetings(
#[prop_or_default]
is_loading: bool,

View File

@ -10,14 +10,14 @@ from its props when its view function does not mutate its state or has other sid
The example below is a pure component. For a given prop `is_loading` it will always result in the same `Html` without any side effects.
```rust
use yew::{Properties, function_component, Html, html};
use yew::{Properties, component, Html, html};
#[derive(Properties, PartialEq)]
pub struct Props {
pub is_loading: bool,
}
#[function_component]
#[component]
fn HelloWorld(props: &Props) -> Html {
if props.is_loading {
html! { "Loading" }

View File

@ -105,7 +105,7 @@ struct Props {
children: Html,
}
#[function_component]
#[component]
fn MyComponent(props: &Props) -> Html {
let Props {
class,

View File

@ -10,7 +10,7 @@ Components can be used in the `html!` macro:
```rust
use yew::prelude::*;
#[function_component]
#[component]
fn MyComponent() -> Html {
html! {
{ "This component has no properties!" }
@ -23,7 +23,7 @@ struct Props {
user_last_name: String,
}
#[function_component]
#[component]
fn MyComponentWithProps(props: &Props) -> Html {
let Props { user_first_name, user_last_name } = props;
html! {
@ -66,7 +66,7 @@ struct Props {
children: Html,
}
#[function_component]
#[component]
fn Container(props: &Props) -> Html {
html! {
<div id={props.id.clone()}>
@ -97,7 +97,7 @@ struct Props {
children: Html,
}
#[function_component]
#[component]
fn Container(props: &Props) -> Html {
html! {
<div id={props.id.clone()}>

View File

@ -19,7 +19,7 @@ use web_sys::{Element, Node};
use yew::prelude::*;
use gloo::utils::document;
#[function_component]
#[component]
fn MyComponent() -> Html {
// memoize as this only needs to be executed once
let node = use_memo(

View File

@ -126,7 +126,7 @@ use wasm_bindgen::JsCast;
use web_sys::{EventTarget, HtmlInputElement};
use yew::prelude::*;
#[function_component]
#[component]
fn MyComponent() -> Html {
let input_value_handle = use_state(String::default);
let input_value = (*input_value_handle).clone();
@ -220,7 +220,7 @@ but it works in a very similar way to `JsCast`.
use web_sys::HtmlInputElement;
use yew::prelude::*;
#[function_component]
#[component]
fn MyComponent() -> Html {
let input_value_handle = use_state(String::default);
let input_value = (*input_value_handle).clone();
@ -280,7 +280,7 @@ does the cast on the target of the event. `TargetCast::target_unchecked_into` is
use web_sys::HtmlInputElement;
use yew::prelude::*;
#[function_component]
#[component]
fn MyComponent() -> Html {
//highlight-next-line
let input_node_ref = use_node_ref();
@ -328,7 +328,7 @@ You might also see by using `NodeRef` we don't have to send the `String` back in
use web_sys::HtmlInputElement;
use yew::prelude::*;
#[function_component]
#[component]
fn MyComponent() -> Html {
let input_node_ref = use_node_ref();
@ -390,7 +390,7 @@ use wasm_bindgen::{prelude::Closure, JsCast};
use web_sys::HtmlElement;
use yew::prelude::*;
#[function_component]
#[component]
fn MyComponent() -> Html {
let div_node_ref = use_node_ref();
@ -457,7 +457,7 @@ use yew::prelude::*;
use gloo::events::EventListener;
#[function_component]
#[component]
fn MyComponent() -> Html {
let div_node_ref = use_node_ref();

View File

@ -66,7 +66,7 @@ enum Route {
NotFound,
}
#[function_component(Secure)]
#[component(Secure)]
fn secure() -> Html {
let navigator = use_navigator().unwrap();
@ -89,7 +89,7 @@ fn switch(routes: Route) -> Html {
}
}
#[function_component(Main)]
#[component(Main)]
fn app() -> Html {
html! {
<BrowserRouter>
@ -202,7 +202,7 @@ For function components, the `use_navigator` hook re-renders the component when
Here is how to implement a button that navigates to the `Home` route when clicked.
```rust ,ignore
#[function_component(MyComponent)]
#[component(MyComponent)]
pub fn my_component() -> Html {
let navigator = use_navigator().unwrap();
let onclick = Callback::from(move |_| navigator.push(&Route::Home));
@ -232,7 +232,7 @@ implements `Clone`, here is for example how to have multiple buttons for differe
use yew::prelude::*;
use yew_router::prelude::*;
#[function_component(NavItems)]
#[component(NavItems)]
pub fn nav_items() -> Html {
let navigator = use_navigator().unwrap();
@ -292,7 +292,7 @@ navigator API. The component accepts a
Here is an example:
```rust ,ignore
#[function_component(SomePage)]
#[component(SomePage)]
fn some_page() -> Html {
// made-up hook `use_user`
let user = match use_user() {
@ -471,7 +471,7 @@ fn switch_settings(route: SettingsRoute) -> Html {
}
}
#[function_component(App)]
#[component(App)]
pub fn app() -> Html {
html! {
<BrowserRouter>

View File

@ -24,14 +24,14 @@ The recommended way to use suspense is with hooks.
```rust ,ignore
use yew::prelude::*;
#[function_component(Content)]
#[component(Content)]
fn content() -> HtmlResult {
let user = use_user()?;
Ok(html! {<div>{"Hello, "}{&user.name}</div>})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"Loading..."}</div>};
@ -131,14 +131,14 @@ fn use_user() -> SuspensionResult<User> {
}
}
#[function_component(Content)]
#[component(Content)]
fn content() -> HtmlResult {
let user = use_user()?;
Ok(html! {<div>{"Hello, "}{&user.name}</div>})
}
#[function_component(App)]
#[component(App)]
fn app() -> Html {
let fallback = html! {<div>{"Loading..."}</div>};

View File

@ -100,7 +100,7 @@ properties, you can instead use `yew::Renderer::<App>::with_props(..).render()`.
```rust ,no_run, title=main.rs
use yew::prelude::*;
#[function_component]
#[component]
fn App() -> Html {
let counter = use_state(|| 0);
let onclick = {

Some files were not shown because too many files have changed in this diff Show More