WorldSEnder cd5b8a520c
Improve grammar and paragraph structure in documentation (#2620)
* Read through the docs and correct spelling and grammar

* Run prettier

* Apply review suggestions

Co-authored-by: Muhammad Hamza <muhammadhamza1311@gmail.com>

* adjust translation messages

Co-authored-by: Muhammad Hamza <muhammadhamza1311@gmail.com>
2022-04-20 16:41:42 +05:00

261 lines
6.3 KiB
Plaintext

---
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 vdom during rerendering, to know if nested components needs to be rerendered.
This way Yew can be considered a very reactive framework as changes from the parent will always be propagated downwards
and the view will never be out of sync from 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.
<Tabs>
<TabItem value="with-props" label="With Props">
```rust
use yew::{function_component, html, Html, Properties};
#[derive(Properties, PartialEq)]
pub struct Props {
pub is_loading: bool,
}
#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! { <>{"Am I loading? - "}{props.is_loading.clone()}</> }
}
// Then supply the prop
#[function_component]
fn App() -> Html {
html! {<HelloWorld is_loading={true} />}
}
```
</TabItem>
<TabItem value="no-props" label="No Props">
```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! {<HelloWorld />}
}
```
</TabItem>
</Tabs>
## 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 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.
:::
<Tabs>
<TabItem value="prop_or_default" label="#[prop_or_default]">
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: &Props) -> Html {
if props.is_loading.clone() {
html! { "Loading" }
} else {
html! { "Hello world" }
}
}
// Then use like this with default
#[function_component]
fn Case1() -> Html {
html! {<HelloWorld />}
}
// Or no override the default
#[function_component]
fn Case2() -> Html {
html! {<HelloWorld is_loading={true} />}
}
```
</TabItem>
<TabItem value="prop_or_value" label="#[prop_or(value)]">
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::{function_component, html, Html, Properties};
#[derive(Properties, PartialEq)]
pub struct Props {
// highlight-start
#[prop_or("Bob".to_string())]
// highlight-end
pub name: String,
}
#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! {<>{"Hello world"}{props.name.clone()}</>}
}
// Then use like this with default
#[function_component]
fn Case1() -> Html {
html! {<HelloWorld />}
}
// Or no override the default
#[function_component]
fn Case2() -> Html {
html! {<HelloWorld name={"Sam".to_string()} />}
}
```
</TabItem>
<TabItem value="prop_or_else_function" label="#[prop_or_else(function)]">
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::{function_component, html, Html, Properties};
fn create_default_name() -> String {
"Bob".to_string()
}
#[derive(Properties, PartialEq)]
pub struct Props {
// highlight-start
#[prop_or_else(create_default_name)]
// highlight-end
pub name: String,
}
#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! {<>{"Hello world"}{props.name.clone()}</>}
}
// Then use like this with default
#[function_component]
fn Case1() -> Html {
html! {<HelloWorld />}
}
// Or no override the default
#[function_component]
fn Case2() -> Html {
html! {<HelloWorld name={"Sam".to_string()} />}
}
```
</TabItem>
</Tabs>
## 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.
## 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::{function_component, html, Html, Properties, props};
#[derive(Properties, PartialEq)]
pub struct Props {
#[prop_or("Bob".to_string())]
pub name: String,
}
#[function_component]
fn HelloWorld(props: &Props) -> Html {
html! {<>{"Hello world"}{props.name.clone()}</>}
}
#[function_component]
fn App() -> Html {
// highlight-start
let pre_made_props = props! {
Props {} // Notice we did not need to specify name prop
};
// highlight-end
html! {<HelloWorld ..pre_made_props />}
}
```