---
description: 加速你的專案
---

# 優化與最佳實例

## neq_assign

當元件從父元件接收到屬性時， `change` 的方法就會被呼叫。除了讓你更新元件的狀態，也讓你回傳，決定元件是否要在屬性改變時，重新渲染自己的布林值 `ShouldRender` 。

重新渲染是很浪費效能的，儘可能避免這麼做。一般來說，只有在屬性真的改變時，才重新渲染。下面的程式碼是體現這個原則的例子，當屬性改變時，才回傳 `true`：

```rust
use yew::ShouldRender;

#[derive(PartialEq)]
struct ExampleProps;

struct Example {
    props: ExampleProps,
};

impl Example {
    fn change(&mut self, props: ExampleProps) -> ShouldRender {
        if self.props != props {
            self.props = props;
            true
        } else {
            false
        }
    }
}
```

但我們可以走的更遠！這六行的模板，使用一個 trait 和一個 實作了 `PartialEq` 的 blanket implementation ，可以被縮短至一行。請參考[這裡](https://docs.rs/yewtil/*/yewtil/trait.NeqAssign.html)， `yewtil` 的 crate 裡的 `NeqAssign` trait。

## RC

為了避免重新渲染時，複製大量的資料來建立屬性，我們可以使用智慧指針來讓程式只複製指針。如果你使用 `Rc<_>` 來封裝你的屬性，而不是未封裝的值，你可以使用 `Rc::make_mut`，去複製與存取你想要改變的資料的可變參考，這做到了延遲複製，直到你需要更動子元件的資料。透過避免複製直到有值改變，子元件可以在 `Component::change` 拒絕與他狀態中的屬性相同值的屬性，而且這樣不會有任何效能成本。另外，這個方式，資料必須在與子元件比較與被拒絕之前，被複製進父元件的屬性中。

這個優化最那些無法 `Copy` 的資料型別最有用。如果你可以輕易複製你的資料，那把資料放進智慧指針裡面似乎就沒有這麼值得。對於那些包含很多像是 `Vec` 、 `HashMap` 與 `String` 的結構，這個優化對他們會更值得。

如果子元件幾乎不會更新值，那這個優化效果會很好，甚至如果父元件也很少更新，那效果會更好。上面的情況，使在純元件中使用 `Rc<_>s` 是一個封裝屬性值很好的選擇。

## View 方法

出於程式碼的可讀性，通常會寫方法包裝複雜的 `html!`，這樣你可以避免巢狀的 HTML 造成過多的向右縮排。

## 純元件/函數式元件

純元件 是一種不會改變自己狀態的元件，他們只單純顯示內容或是向普通可變的元件傳送訊息。他們和 view 方法不同的地方在於們可以在 `html!` 巨集中使用，語法會像（`<SomePureComponent />`），而不是表達式語法（`{some_view_function()}`），而且根據他們的實作方式，他們可以被 memoized，這樣可以套用前面所述的 `neq_assign` 的邏輯避免重新渲染。

Yew 本身不支援純元件或是函數式元件，但是你可以透過 external crates 使用。

函數式元件還不存在，但是理論上純元件可以透過巨集與宣告方法產生。

## Keyed DOM nodes when they arrive

## 使用 Cargo Workspaces 加速編譯

Yew 最大的缺點就是花太多時間在編譯上了。編譯時間似乎和 `html!` 巨集中的程式碼質量相同。 對於小專案來說，這應該不是什麼大問題，但是對於有很多頁面的大型網頁應用程式來說，就必須要將程式碼封裝成很多 crates 以減少編譯所花的時間。

你應該將路由與頁面區塊封裝成一個 main crate，然後將共用的程式碼與元件封裝成另一個 crate，將每個頁面會用到的不同的元件，各自封裝到不同的 crate 中，或是只產生 `Html` 的大方法中。最好的狀況，你只需要重新編譯你 main crate 與修改的頁面的 crate 的程式碼；而最壞的情況，你編輯了共用的 crate，你就必須重新編譯所有依賴這個共用 crate 的程式碼。

如果你的 main crate 太過龐大，或是你希望快速迭代深層巢狀的頁面（一個頁面渲染另一個頁面的頂層），你可以使用範例的 crate ，在一個簡單的主頁面上編輯你未完成的元件。

## 編譯大小的優化 <a id="build-size-optimization"></a>

- 優化 Rust 的程式碼
- `cargo.toml` （定義釋出的設定檔）
- 使用 `wasm-opt` 優化 wasm 程式碼

更多關於程式碼大小的資訊，請參考： [rustwasm book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)

### Cargo.toml <a id="cargo-toml"></a>

你可以設定你的發行版本更小的檔案大小，透過設定 `Cargo.toml` 的 `[profile.release]` 。

[Rust profiles documentation](https://doc.rust-lang.org/cargo/reference/profiles.html)

```rust
[profile.release]
# less code to include into binary
panic = 'abort'
# optimization over all codebase ( better optimization, slower build )
codegen-units = 1
# optimization for size ( more aggressive )
opt-level = 'z'
# optimization for size
# opt-level = 's'
# link time optimization using using whole-program analysis
lto = true
```

### wasm-opt <a id="wasm-opt"></a>

更多優化 `wasm` 程式碼大小的方法。

wasm-opt 資訊： [binaryen project](https://github.com/WebAssembly/binaryen)

Rust Wasm 中有一個關於減少 Wasm 二進位檔大小的章節：[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)

- 使用`wasm-pack` 預設在發行版本編譯時優化 `wasm` 程式碼
- 直接在 wasm 檔案上使用 `wasm-opt` 。

```rust
wasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm
```

#### 編譯 yew/examples/ 中 最小的例子 <a id="build-size-of-minimal-example-in-yew-examples"></a>

注意： `wasm-pack` 包含對 Rust 與 wasm 程式碼的優化。而`wasm-bindgen` 只是一個單純的例子，沒有對 `Rust` 做任何優化。

| used tool                   | size  |
| :-------------------------- | :---- |
| wasm-bindgen                | 158KB |
| wasm-binggen + wasm-opt -Os | 116KB |
| wasm-pack                   | 99KB  |
