--- title: 'Properties' description: 'Parent to child communication' --- import Tabs from '@theme/Tabs' import TabItem from '@theme/TabItem' :::note Properties are often shortened as "Props". ::: Properties are essentially component arguments that Yew can keep watch on. A type has to implement the `Properties` trait before it can be used as the properties of a component. ## Reactivity Yew checks if props have changed when reconciling the Virtual DOM during re-rendering, to know if nested components need to be re-rendered. This way Yew can be considered a very reactive framework, as changes from the parent will always be propagated downward, and the view will never be out of sync with the data coming from props/state. :::tip If you have not yet completed the [tutorial](../../tutorial), try it out and test this reactivity yourself! ::: ## Derive macro Yew provides a derive macro to easily implement the `Properties` trait on structs. Types for which you derive `Properties` must also implement `PartialEq` so Yew can do data comparison. ```rust use yew::Properties; #[derive(Properties, PartialEq)] pub struct Props { pub is_loading: bool, } ``` ## Use in function components The attribute `#[function_component]` allows to optionally receive Props in the function arguments. To supply them, they are assigned via attributes in the `html!` macro. ```rust use yew::{function_component, html, Html, Properties}; #[derive(Properties, PartialEq)] pub struct Props { pub is_loading: bool, } #[function_component] fn HelloWorld(&Props { is_loading }: &Props) -> Html { html! { <>{"Am I loading? - "}{is_loading} } } // Then supply the prop #[function_component] fn App() -> Html { html! { } } ``` ```rust use yew::{function_component, html, Html}; #[function_component] fn HelloWorld() -> Html { html! { "Hello world" } } // No props to supply #[function_component] fn App() -> Html { html! { } } ``` ## Derive macro field attributes When deriving `Properties` all fields are required by default. The following attributes allow you to give your props default values which will be used when the parent has not set them. :::tip Attributes aren't visible in Rustdoc generated documentation. The doc strings of your properties should mention whether a prop is optional and if it has a special default value. ::: 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}; #[derive(Properties, PartialEq)] pub struct Props { // highlight-start #[prop_or_default] // highlight-end pub is_loading: bool, } #[function_component] fn HelloWorld(&Props { is_loading }: &Props) -> Html { if is_loading { html! { "Loading" } } else { html! { "Hello world" } } } // Then use like this with default #[function_component] fn Case1() -> Html { html! { } } // Or no override the default #[function_component] fn Case2() -> Html { html! { } } ``` Use `value` to initialize the prop value. `value` can be any expression that returns the field's type. For example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`. The expression is evaluated when the properties are constructed and no explicit value has been given. ```rust use yew::prelude::*; #[derive(Properties, PartialEq)] pub struct Props { #[prop_or_default] pub is_loading: bool, // highlight-start #[prop_or(AttrValue::Static("Bob"))] // highlight-end pub name: AttrValue, } #[function_component] fn Hello(&Props { is_loading, ref name }: &Props) -> Html { if is_loading { html! { "Loading" } } else { html! { <>{"Hello "}{name} } } } // Then use like this with default #[function_component] fn Case1() -> Html { html! { } } // Or no override the default #[function_component] fn Case2() -> Html { html! { } } ``` Call `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type. The function is called when no explicit value has been given for that attribute. ```rust use yew::prelude::*; fn create_default_name() -> AttrValue { AttrValue::Static("Bob") } #[derive(Properties, PartialEq)] pub struct Props { #[prop_or_default] pub is_loading: bool, // highlight-start #[prop_or_else(create_default_name)] // highlight-end pub name: AttrValue, } #[function_component] fn Hello(&Props { is_loading, ref name }: &Props) -> Html { if is_loading { html! { "Loading" } } else { html! { <>{"Hello "}{name} } } } // Then use like this with default #[function_component] fn Case1() -> Html { html! { } } // Or no override the default #[function_component] fn Case2() -> Html { html! { } } ``` ## Memory/speed overhead of using Properties Internally properties are reference counted. This means that only a shared pointer is passed down the component tree for props. It saves us from the cost of having to clone the entire props, which might be expensive. :::tip Make use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type. ::: ## Props macro The `yew::props!` macro allows you to build properties the same way the `html!` macro does it. The macro uses the same syntax as a struct expression except that you can't use attributes or a base expression (`Foo { ..base }`). The type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`). ```rust use yew::prelude::*; #[derive(Properties, PartialEq)] pub struct Props { #[prop_or_default] pub is_loading: bool, #[prop_or(AttrValue::Static("Bob"))] pub name: AttrValue, } #[function_component] fn Hello(&Props { is_loading, ref name }: &Props) -> Html { if is_loading { html! { "Loading" } } else { html! { <>{"Hello "}{name} } } } #[function_component] fn App() -> Html { // highlight-start let pre_made_props = yew::props! { Props {} // Notice we did not need to specify name prop }; // highlight-end html! { } } ``` ## Automatically generate properties (yew-autoprops) In order to streamline your development process, you can also use the macro `#[autoprops]` (from the crate `yew-autoprops`) that will automatically generate the `Properties` struct for you. ```rust use yew::prelude::*; use yew_autoprops::autoprops; // the #[autoprops] macro must appear BEFORE #[function_component], the order matters #[autoprops] #[function_component] fn Greetings( #[prop_or_default] is_loading: bool, #[prop_or(AttrValue::Static("Hello"))] message: &AttrValue, #[prop_or(AttrValue::Static("World"))] name: &AttrValue, ) -> Html { if is_loading { html! { "Loading" } } else { html! { <>{message}{" "}{name} } } } // The properties struct "GreetingsProps" will be generated automatically. // // `is_loading` will be passed as value to the components while `message` and // `name` will use references because of the leading `&` in the definition. ``` ## Evaluation Order Props are evaluated in the order they're specified, as shown by the following example: ```rust #[derive(yew::Properties, PartialEq)] struct Props { first: usize, second: usize, last: usize } let mut g = 1..=3; let props = yew::props!(Props { first: g.next().unwrap(), second: g.next().unwrap(), last: g.next().unwrap() }); assert_eq!(props.first, 1); assert_eq!(props.second, 2); assert_eq!(props.last, 3); ``` ## Anti Patterns While almost any Rust type can be passed as properties, there are some anti-patterns that should be avoided. These include, but are not limited to: 1. Using `String` type instead of `AttrValue`.
**Why is this bad?** `String` can be expensive to clone. Cloning is often needed when the prop value is used with hooks and callbacks. `AttrValue` is either a reference-counted string (`Rc`) or a `&'static str`, thus very cheap to clone.
**Note**: `AttrValue` internally is `IString` from [implicit-clone](https://crates.io/crates/implicit-clone) See that crate to learn more. 2. Using interior mutability.
**Why is this bad?** Interior mutability (such as with `RefCell`, `Mutex`, etc.) should _generally_ be avoided. It can cause problems with re-renders (Yew doesn't know when the state has changed) so you may have to manually force a render. Like all things, it has its place. Use it with caution. 3. Using `Vec` type instead of `IArray`.
**Why is this bad?** `Vec`, just like `String`, can also be expensive to clone. `IArray` is either a reference-counted slice (`Rc`) or a `&'static [T]`, thus very cheap to clone.
**Note**: `IArray` can be imported from [implicit-clone](https://crates.io/crates/implicit-clone) See that crate to learn more. 4. You tell us. Did you run into an edge-case you wish you knew about earlier? Feel free to create an issue or PR a fix to this documentation. ## yew-autoprops [yew-autoprops](https://crates.io/crates/yew-autoprops) is an experimental package that allows one to create the Props struct on the fly out of the arguments of your function. Might be useful, if the properties struct is never reused.