---
title: '属性（Properties）'
description: '父组件到子组件的通信'
---

Properties 用于父级到子组件的通信。
每个组件都有一个关联的属性类型，描述了从父级传递下来的内容。
理论上，这可以是任何实现了 `Properties` trait 的类型，但实际上，
没有理由不使用一个结构体，其中每个字段都代表一个属性。

## 派生宏

不要尝试自己去实现 `Properties`，而是通过使用 `#[derive(Properties)]` 来派生它。
派生 `Properties` 的类型还必须实现 `PartialEq`。

### Field attributes

When deriving `Properties`, all fields are required by default.
The following attributes allow you to give your props initial values which will be used unless they are set to another value.

:::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.
:::

#### `#[prop_or_default]`

Initialize the prop value with the default value of the field's type using the `Default` trait.

#### `#[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)]`.

#### `#[prop_or_else(function)]`

Call `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.

## `PartialEq`

`Properties` require `PartialEq` to be implemented. This is so that they can be compared by Yew to call the `changed` method
only when they change.

## Memory/speed overhead of using Properties

Internally properties are reference counted. This means that only a 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.
:::

## Example

```rust
use yew::Properties;
/// Importing the AttrValue from virtual_dom
use yew::virtual_dom::AttrValue;

#[derive(Clone, PartialEq)]
pub enum LinkColor {
    Blue,
    Red,
    Green,
    Black,
    Purple,
}

fn create_default_link_color() -> LinkColor {
    LinkColor::Blue
}

#[derive(Properties, PartialEq)]
pub struct LinkProps {
    /// The link must have a target.
    href: AttrValue,
    /// Also notice that we are using AttrValue instead of String
    text: AttrValue,
    /// Color of the link. Defaults to `Blue`.
    #[prop_or_else(create_default_link_color)]
    color: LinkColor,
    /// The view function will not specify a size if this is None.
    #[prop_or_default]
    size: Option<u32>,
    /// When the view function does not specify active, it defaults to true.
    #[prop_or(true)]
    active: bool,
}
```

## 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 cannot 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::{props, Properties, virtual_dom::AttrValue};

#[derive(Clone, PartialEq)]
pub enum LinkColor {
    Blue,
    Red,
    Green,
    Black,
    Purple,
}

fn create_default_link_color() -> LinkColor {
    LinkColor::Blue
}

#[derive(Properties, PartialEq)]
pub struct LinkProps {
    /// The link must have a target.
    href: AttrValue,
    /// Also notice that we're using AttrValue instead of String
    text: AttrValue,
    /// Color of the link. Defaults to `Blue`.
    #[prop_or_else(create_default_link_color)]
    color: LinkColor,
    /// The view function will not specify a size if this is None.
    #[prop_or_default]
    size: Option<u32>,
    /// When the view function doesn't specify active, it defaults to true.
    #[prop_or(true)]
    active: bool,
}

impl LinkProps {
    /// Notice that this function receives href and text as String
    /// We can use `AttrValue::from` to convert it to a `AttrValue`
    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {
        // highlight-start
        props! {LinkProps {
            href: AttrValue::from(href),
            text: AttrValue::from(text),
            size,
        }}
        // highlight-end
    }
}
```
