diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/children.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/children.mdx new file mode 100644 index 00000000000..4e70024633d --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/children.mdx @@ -0,0 +1,307 @@ +--- +title: '子コンポーネント' +--- + +:::caution + +`Children` をチェックおよび操作すると、アプリケーションで驚くべきかつ説明が難しい動作が発生することがよくあります。これにより、エッジケースが発生し、通常は予期しない結果が生じる可能性があります。`Children` を操作しようとする場合は、他の方法を検討する必要があります。 + +Yew は、子コンポーネントのプロパティの型として `Html` を使用することをサポートしています。`Children` または `ChildrenRenderer` が必要ない場合は、子コンポーネントとして `Html` を使用することをお勧めします。これは `Children` の欠点がなく、パフォーマンスのオーバーヘッドも低くなります。 + +::: + +## 一般的な使用法 + +_ほとんどの場合、_ コンポーネントに子コンポーネントを持たせる場合、子コンポーネントの型を気にする必要はありません。この場合、以下の例で十分です。 + +```rust +use yew::{html, Component, Context, Html, Properties}; + +#[derive(Properties, PartialEq)] +pub struct ListProps { + #[prop_or_default] + pub children: Html, +} + +pub struct List; + +impl Component for List { + type Message = (); + type Properties = ListProps; + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, ctx: &Context) -> Html { + html! { +
+ {ctx.props().children.clone()} +
+ } + } +} + +## 高度な使用法 + +### 型指定された子コンポーネント + +特定のタイプのコンポーネントを子コンポーネントとして渡したい場合は、`yew::html::ChildrenWithProps` を使用できます。 + +```rust +use yew::{html, ChildrenWithProps, Component, Context, Html, Properties}; + +pub struct Item; + +impl Component for Item { + type Message = (); + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, _ctx: &Context) -> Html { + html! { + { "item" } + } + } +} + +#[derive(Properties, PartialEq)] +pub struct ListProps { + #[prop_or_default] + pub children: ChildrenWithProps, +} + +pub struct List; + +impl Component for List { + type Message = (); + type Properties = ListProps; + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, ctx: &Context) -> Html { + html! { +
+ { for ctx.props().children.iter() } +
+ } + } +} +``` + +## プロパティを持つネストされた子コンポーネント + +コンポーネントがその子コンポーネントを型指定している場合、ネストされたコンポーネントのプロパティにアクセスして変更することができます。 + +```rust +use std::rc::Rc; +use yew::prelude::*; + +#[derive(Clone, PartialEq, Properties)] +pub struct ListItemProps { + value: String, +} + +#[function_component] +fn ListItem(props: &ListItemProps) -> Html { + let ListItemProps { value } = props.clone(); + html! { + + {value} + + } +} + +#[derive(PartialEq, Properties)] +pub struct Props { + pub children: ChildrenWithProps, +} + +#[function_component] +fn List(props: &Props) -> Html { + let modified_children = props.children.iter().map(|mut item| { + let mut props = Rc::make_mut(&mut item.props); + props.value = format!("item-{}", props.value); + item + }); + html! { for modified_children } +} + +html! { + + + + + +}; +``` + +### 列挙型の子コンポーネント + +もちろん、時には子コンポーネントをいくつかの異なるコンポーネントに制限する必要がある場合があります。そのような場合には、Yewについてさらに深く理解する必要があります。 + +ここでは、より良いエルゴノミクスを提供するために [`derive_more`](https://github.com/JelteF/derive_more) を使用しています。使用したくない場合は、各バリアントに対して手動で `From` を実装することができます。 + +```rust +use yew::{ + html, html::ChildrenRenderer, virtual_dom::VChild, Component, + Context, Html, Properties, +}; + +pub struct Primary; + +impl Component for Primary { + type Message = (); + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, _ctx: &Context) -> Html { + html! { + { "Primary" } + } + } +} + +pub struct Secondary; + +impl Component for Secondary { + type Message = (); + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, _ctx: &Context) -> Html { + html! { + { "Secondary" } + } + } +} + +#[derive(Clone, derive_more::From, PartialEq)] +pub enum Item { + Primary(VChild), + Secondary(VChild), +} + +// 現在、`Into` を実装して、yew が `Item` をどのようにレンダリングするかを知ることができるようにします。 +#[allow(clippy::from_over_into)] +impl Into for Item { + fn into(self) -> Html { + match self { + Self::Primary(child) => child.into(), + Self::Secondary(child) => child.into(), + } + } +} + +#[derive(Properties, PartialEq)] +pub struct ListProps { + #[prop_or_default] + pub children: ChildrenRenderer, +} + +pub struct List; + +impl Component for List { + type Message = (); + type Properties = ListProps; + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, ctx: &Context) -> Html { + html! { +
+ { for ctx.props().children.iter() } +
+ } + } +} +``` + +### オプションの型の子コンポーネント + +特定の型の単一のオプションの子コンポーネントを持つこともできます: + +```rust +use yew::{ + html, html_nested, virtual_dom::VChild, Component, + Context, Html, Properties +}; + +pub struct PageSideBar; + +impl Component for PageSideBar { + type Message = (); + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, _ctx: &Context) -> Html { + html! { + { "sidebar" } + } + } +} + +#[derive(Properties, PartialEq)] +pub struct PageProps { + #[prop_or_default] + pub sidebar: Option>, +} + +struct Page; + +impl Component for Page { + type Message = (); + type Properties = PageProps; + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, ctx: &Context) -> Html { + html! { +
+ { ctx.props().sidebar.clone().map(Html::from).unwrap_or_default() } + // ... ページ内容 +
+ } + } +} + +// ページコンポーネントはサイドバーを含むかどうかを選択できます: + +pub fn render_page(with_sidebar: bool) -> Html { + if with_sidebar { + // サイドバーを含むページ + html! { + + }} /> + } + } else { + // サイドバーを含まないページ + html! { + + } + } +} +``` + +## さらに読む + +- このパターンの実際の例については、yew-router のソースコードを参照してください。より高度な例については、yew リポジトリの[関連する例のリスト](https://github.com/yewstack/yew/tree/master/examples/nested_list)を参照してください。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/how-it-works.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/how-it-works.mdx new file mode 100644 index 00000000000..fbed4d6ef80 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/how-it-works.mdx @@ -0,0 +1,39 @@ +--- +title: '仕組み' +description: 'フレームワークの低レベルの詳細について' +--- + +# 基本ライブラリの内部詳細 + +## `html!` マクロの内部 + +`html!` マクロは、HTMLに似たカスタム構文で記述されたコードを有効なRustコードに変換します。このマクロを使用することはYewアプリケーションの開発に必須ではありませんが、推奨されています。このマクロが生成するコードはYewのパブリックライブラリAPIを使用しており、希望すれば直接使用することもできます。いくつかのメソッドは意図的に文書化されていないため、誤用を避けるために注意が必要です。`yew-macro`の各更新により、生成されるコードはより効率的になり、`html!`構文をほとんど(または全く)変更することなく破壊的な変更を処理できるようになります。 + +`html!` マクロを使用すると、宣言的なスタイルでコードを記述できるため、UIレイアウトコードはページのHTMLに非常に似たものになります。アプリケーションがよりインタラクティブになり、コードベースが大きくなるにつれて、この方法はますます有用になります。DOM 操作のすべてのコードを手動で記述するのに比べて、マクロがこれらすべてを処理してくれます。 + +`html!` マクロの使用は非常に魔法のように感じるかもしれませんが、隠すべきものは何もありません。その仕組みに興味がある場合は、プログラム内の `html!` マクロ呼び出しを展開してみてください。`cargo expand` という便利なコマンドがあり、Rustマクロの展開を確認できます。`cargo expand` はデフォルトで `cargo` に含まれていないため、まだインストールしていない場合は `cargo install cargo-expand` を使用してインストールする必要があります。[Rust-Analyzer](https://rust-analyzer.github.io/) も[IDEからマクロ出力を取得するメカニズム](https://rust-analyzer.github.io/manual.html#expand-macro-recursively)を提供しています。 + +`html!` マクロの出力は通常非常に簡潔です!これは特徴です:機械生成のコードは時々アプリケーション内の他のコードと衝突することがあります。問題を防ぐために、`proc_macro` は「衛生」ルールに従っています。いくつかの例を以下に示します: + +1. Yewパッケージを正しく参照するために、マクロ生成コードでは `::yew::` を使用し、直接 `yew::` を使用しません。これは `::alloc::vec::Vec::new()` を呼び出すのと同じ理由です。 +2. トレイトメソッド名の衝突を避けるために、`` を使用して正しいトレイトメンバーを使用していることを確認します。 + +## 仮想 DOM とは? + +DOM(「ドキュメントオブジェクトモデル」)は、ブラウザによって管理されるHTMLコンテンツの表現です。「仮想」 DOM は、単にメモリ内の DOM のコピーです。仮想 DOM を管理することで、メモリのオーバーヘッドが増加しますが、ブラウザAPIの使用を回避または遅延させることでバッチ処理と高速な読み取りを実現できます。 + +メモリ内に DOM のコピーを持つことは、宣言的UIを使用するライブラリの使用を促進するのに役立ちます。ユーザーイベントに基づいて DOM を変更するための特定のコードが必要な場合とは異なり、ライブラリは一般的な方法を使用して DOM の「差分」を行うことができます。Yewコンポーネントが更新され、そのレンダリング方法を変更したい場合、Yewライブラリは仮想 DOM の2番目のコピーを構築し、現在画面上に表示されている内容をミラーリングする仮想 DOM と直接比較します。両者の「差分」は増分更新に分解され、ブラウザAPIと共に適用されます。更新が適用されると、古い仮想 DOM のコピーは破棄され、新しいコピーが将来の差分チェックのために保存されます。 + +この「差分」アルゴリズムは、時間の経過とともに最適化され、複雑なアプリケーションのパフォーマンスを向上させることができます。YewアプリケーションはWebAssemblyを介して実行されるため、Yewは将来的により複雑なアルゴリズムを採用する上で競争力を持つと信じています。 + +Yewの仮想 DOM はブラウザの DOM と完全に一対一対応しているわけではありません。DOM 要素を整理するための「リスト」や「コンポーネント」も含まれています。リストは単に要素の順序付きリストである場合もありますが、より強力な場合もあります。各リスト要素に「キー」注釈を追加することで、アプリケーション開発者はリストが変更されたときに差分更新の計算に必要な作業量を最小限に抑えるための追加の最適化をYewに提供できます。同様に、コンポーネントは再レンダリングが必要かどうかを示すカスタムロジックを提供し、パフォーマンスを向上させるのに役立ちます。 + +## Yewスケジューラとコンポーネントスコープのイベントループ + +_貢献ドキュメント - `yew::scheduler` と `yew::html::scope` の仕組みを詳しく説明_ + +## さらなる読み物 + +- [Rustのマクロに関する詳細情報](https://doc.rust-lang.org/stable/book/ch19-06-macros.html) +- [`cargo-expand` に関する詳細情報](https://github.com/dtolnay/cargo-expand) +- [`yew::virtual_dom` のAPIドキュメント](https://docs.rs/yew/*/yew/virtual_dom/index.html) \ No newline at end of file diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/immutable.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/immutable.mdx new file mode 100644 index 00000000000..f05917a1399 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/immutable.mdx @@ -0,0 +1,19 @@ +--- +title: 'イミュータブルタイプ' +description: 'Yew のイミュータブルデータ構造' +--- + +## イミュータブルタイプとは? + +これらのタイプは、インスタンス化はできるが値を変更することはできないタイプです。値を更新するには、新しい値をインスタンス化する必要があります。 + +## なぜイミュータブルタイプを使用するのですか? + +React と同様に、プロパティは祖先から子孫に伝播されます。これは、各コンポーネントが更新されるたびにプロパティが存在する必要があることを意味します。したがって、プロパティは理想的には簡単にクローンできるべきです。これを実現するために、通常は `Rc` にラップします。 + +イミュータブルタイプは、コンポーネント間でプロパティの値を低コストでクローンできるため、プロパティの値を保持するのに最適です。 + +## さらに読む + +- [イミュータブルの例](https://github.com/yewstack/yew/tree/master/examples/immutable) +- [Crate `implicit-clone`](https://docs.rs/implicit-clone/) diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/optimizations.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/optimizations.mdx new file mode 100644 index 00000000000..8c024044a97 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/optimizations.mdx @@ -0,0 +1,111 @@ +--- +title: '最適化とベストプラクティス' +sidebar_label: Optimizations +description: 'アプリケーションのパフォーマンスを最適化する' +--- +## スマートポインタの使用 + +**注意:このセクションで使用されている用語に混乱がある場合は、Rustのマニュアルにある[スマートポインタに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)が役立ちます。** + +再レンダリング時に大量のデータをクローンしてpropsを作成するのを避けるために、スマートポインタを使用してデータ自体ではなくデータへの参照のみをクローンすることができます。propsや子コンポーネントに関連データの参照を渡すことで、データを変更する必要がある子コンポーネントでデータをクローンするのを避けることができます。`Rc::make_mut`を使用してデータをクローンし、変更するための可変参照を取得できます。 + +これにより、`Component::changed`でのpropの変更がコンポーネントの再レンダリングを必要とするかどうかを判断する際にさらに利点があります。これは、データの値ではなくポインタのアドレス(つまり、データがマシンメモリに格納されている場所)を比較できるためです。2つのポインタが同じデータを指している場合、それらが指しているデータの値は同じでなければなりません。逆は必ずしも真ではないことに注意してください!2つのポインタアドレスが異なる場合でも、基になるデータは同じである可能性があります。この場合、基になるデータを比較する必要があります。 + +この比較を行うには、`PartialEq`(データを比較する際に自動的に使用される等価演算子`==`)ではなく、`Rc::ptr_eq`を使用する必要があります。Rustのドキュメントには、`Rc::ptr_eq`に関する[詳細](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)があります。 + +この最適化は、`Copy`を実装していないデータ型に最も有用です。データを安価にコピーできる場合、それをスマートポインタの後ろに置く必要はありません。`Vec`、`HashMap`、`String`などのデータ集約型の構造体に対して、スマートポインタを使用することでパフォーマンスの向上が見込まれます。 + +この最適化は、子コンポーネントが値を更新しない場合に最も効果的であり、親コンポーネントがほとんど更新されない場合にさらに効果的です。これにより、`Rc<_>`は純粋なコンポーネントでpropsの値をラップするのに適した選択肢となります。 + +ただし、子コンポーネントでデータを自分でクローンする必要がない限り、この最適化は無駄であり、不要な参照カウントのコストを追加するだけです。Yewのpropsはすでに参照カウントされており、内部でデータのクローンは行われません。 + +## レンダリング関数 + +コードの可読性のために、`html!`の一部の繰り返しコードを専用の分割関数に移行することは通常意味があります。これにより、コードが読みやすくなり、インデントが減り、良いデザインパターンを奨励します。特に、複数の場所で呼び出すことができるこれらの関数を使用して、コード量を減らすことができます。 + +## 純粋なコンポーネント + +純粋なコンポーネントは、その状態を変更せず、コンテンツを表示し、メッセージを通常の可変コンポーネントに伝播するコンポーネントです。これらは、`html!`マクロ内でコンポーネント構文(``)を使用する点でビュー関数とは異なり、実装に応じてメモ化される可能性があります(これは、一度関数が呼び出されると、その値が「保存」されることを意味し、同じパラメータで複数回呼び出された場合、その値を再計算する必要がなく、最初の関数呼び出しから保存された値を返すだけです)。Yewは内部でpropsを比較するため、propsが変更された場合にのみUIを再レンダリングします。 + +## ワークスペースを使用してコンパイル時間を短縮する + +Yewの最大の欠点は、コンパイルにかかる時間が長いことです。プロジェクトのコンパイルにかかる時間は、`html!`マクロに渡されるコードの量に関連しているようです。小規模なプロジェクトでは問題にならないようですが、大規模なアプリケーションでは、コンパイラがアプリケーションのために行う作業量を最小限に抑えるためにコードを複数のクレートに分割することが理にかなっています。 + +1つの方法として、メインクレートがルーティング/ページ選択を処理し、各ページごとに異なるクレートを作成することが考えられます。各ページは異なるコンポーネントまたは`Html`を生成する大きな関数である可能性があります。アプリケーションの異なる部分を含むクレート間で共有されるコードは、プロジェクトが依存する別のクレートに格納できます。理想的には、すべてのコードを再コンパイルするのではなく、メインクレートと1つのページクレートのみを再コンパイルすることになります。最悪の場合、「共通」クレートで何かを編集した場合、すべての依存コードを再コンパイルする必要があり、元の状態に戻ります。 + +メインクレートが重すぎる場合や、深くネストされたページ(例:別のページ上にレンダリングされるページ)を迅速に反復したい場合は、メインページの簡略化された実装を作成し、作業中のコンポーネントを追加でレンダリングするためにサンプルクレートを使用できます。 + +## バイナリサイズの縮小 + +- Rustコードの最適化 +- `cargo.toml`(リリースプロファイルの定義) +- `wasm-opt` を使用してwasmコードを最適化 + +**注意:バイナリサイズの縮小に関する詳細は、[Rust Wasmマニュアル](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)を参照してください。** + +### Cargo.toml + +リリースビルドをより小さくするために、`Cargo.toml`の`[profile.release]`セクションで利用可能な設定を使用して構成できます。 + +```toml, title=Cargo.toml +[profile.release] +# バイナリサイズを小さくする +panic = 'abort' +# コード全体を最適化する(最適化は良くなるが、ビルド速度は遅くなる) +codegen-units = 1 +# サイズを最適化する(より積極的なアプローチ) +opt-level = 'z' +# サイズを最適化する +# opt-level = 's' +# プログラム全体の解析を使用してリンク時に最適化 +lto = true +``` + +### 開発版 Cargo 設定 + +Rust と cargo の実験的な開発版機能から追加の利点を得ることもできます。`trunk` の開発版ツールチェーンを使用するには、`RUSTUP_TOOLCHAIN="nightly"` 環境変数を設定します。その後、`.cargo/config.toml` で不安定な rustc 機能を構成できます。不安定機能のドキュメント、特に[`build-std`]および[`build-std-features`]に関する部分を参照して、設定方法を確認してください。 + +```toml, title=".cargo/config.toml" +[unstable] +# rust-srcコンポーネントが必要です。`rustup +nightly component add rust-src` +build-std = ["std", "panic_abort"] +build-std-features = ["panic_immediate_abort"] +``` + +[不安定な機能のリスト]: https://doc.rust-lang.org/cargo/reference/unstable.html +[`build-std`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std +[`build-std-features`]: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std-features + +:::caution +開発版のRustコンパイラには、[この例](https://github.com/yewstack/yew/issues/2696)のようなバグが含まれている可能性があるため、定期的に監視し調整する必要があります。これらの実験的なオプションを使用する際は注意が必要です。 +::: + +### wasm-opt + +さらに、`wasm` コードのサイズを最適化することができます。 + +Rust Wasm マニュアルには、Wasm バイナリファイルのサイズを縮小する方法に関するセクションがあります:[.wasm サイズの縮小](https://rustwasm.github.io/book/game-of-life/code-size.html) + +- `wasm-pack` を使用すると、デフォルトでリリースビルドの `wasm` コードが最適化されます +- `wasm` ファイルに直接 `wasm-opt` を使用する + +```text +wasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm +``` + +#### yew/examples/ の 'minimal' サンプルのビルドサイズ + +注意:`wasm-pack` は Rust と Wasm コードの最適化を組み合わせています。この例では、`wasm-bindgen` は Rust のサイズ最適化を行っていません。 + +| ツールチェーン | サイズ | +| :-------------------------- | :---- | +| wasm-bindgen | 158KB | +| wasm-bindgen + wasm-opt -Os | 116KB | +| wasm-pack | 99 KB | + +## さらに読む + +- [Rust マニュアルのスマート ポインターに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html) +- [Rust Wasm マニュアルのコードサイズの縮小に関する章](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size) +- [Rust プロファイルに関するドキュメント](https://doc.rust-lang.org/cargo/reference/profiles.html) +- [binaryen プロジェクト](https://github.com/WebAssembly/binaryen) \ No newline at end of file diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/portals.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/portals.mdx new file mode 100644 index 00000000000..b46a0977e7a --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/portals.mdx @@ -0,0 +1,48 @@ +--- +title: 'ポータル (Portals)' +description: 'コンテンツをDOMツリー外のノードにレンダリングする' +--- + +## ポータルとは? + +ポータル (Portal) は、子要素を親コンポーネントのDOM階層外のDOMノードにレンダリングする方法を提供します。`yew::create_portal(child, host)` は `Html` 値を返し、`child` を `host` 要素の子要素としてレンダリングしますが、親コンポーネントの階層下ではありません。 + +## 使用方法 + +ポータルの典型的な用途には、モーダルダイアログやホバーカード、さらに技術的な用途として、要素の [`shadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/Element/shadowRoot) の内容を制御すること、スタイルシートを周囲のドキュメントの `` に添付すること、`` の中央の `` 要素に参照される要素を収集することなどがあります。 + +`yew::create_portal` は低レベルの構成要素であることに注意してください。ライブラリはこれを使用してより高レベルのAPIを実装し、その後アプリケーションはこれらのAPIを使用できます。例えば、ここでは `children` を `yew` 以外の要素にレンダリングするシンプルなモーダルダイアログを示します。この要素は `id="modal_host"` で識別されます。 + +```rust +use yew::prelude::*; + +#[derive(Properties, PartialEq)] +pub struct ModalProps { + #[prop_or_default] + pub children: Html, +} + +#[function_component] +fn Modal(props: &ModalProps) -> Html { + let modal_host = gloo::utils::document() + .get_element_by_id("modal_host") + .expect("Expected to find a #modal_host element"); + + create_portal( + props.children.clone(), + modal_host.into(), + ) +} +``` + +## イベント処理 + +ポータル内部の要素で発生するイベントは、仮想DOMのバブリングに従います。つまり、ポータルが要素の子要素としてレンダリングされる場合、その要素上のイベントリスナーは、ポータル内部から発生するイベントをキャプチャします。たとえポータルが実際のDOM内の無関係な位置にその内容をレンダリングしていてもです。 + +これにより、開発者は使用しているコンポーネントがポータルを使用して実装されているかどうかを気にする必要がなくなります。いずれにせよ、その子要素上で発生するイベントはバブリングします。 + +既知の問題として、ポータルから **閉じた** シャドウルートへのイベントは2回分配されます。1回はシャドウルート内部の要素に対して、もう1回はホスト要素自体に対してです。**開いた** シャドウルートは正常に動作しますので、これが影響する場合は、いつでもバグレポートを提出してください。 + +## さらなる読み物 + +- [ポータルの例](https://github.com/yewstack/yew/tree/master/examples/portals) diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/server-side-rendering.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/server-side-rendering.mdx new file mode 100644 index 00000000000..5d31a0cdbff --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/server-side-rendering.mdx @@ -0,0 +1,183 @@ +--- +title: 'サーバーサイドレンダリング' +description: 'Yewコンポーネントをサーバーサイドでレンダリングする。' +--- + +# サーバーサイドレンダリング (Server-Side Rendering) + +デフォルトでは、Yewコンポーネントはクライアントサイドでレンダリングされます。ユーザーがウェブサイトにアクセスすると、サーバーは実際のコンテンツを含まない骨組みのHTMLファイルとWebAssemblyパッケージをブラウザに送信します。すべてのコンテンツはクライアントサイドでWebAssemblyパッケージによってレンダリングされます。これをクライアントサイドレンダリングと呼びます。 + +この方法はほとんどのウェブサイトにとって有効ですが、いくつかの注意点があります: + +1. ユーザーはWebAssemblyパッケージがダウンロードされ、初期レンダリングが完了するまで何も表示されません。これにより、ネットワークが遅い場合にユーザーエクスペリエンスが悪化する可能性があります。 +2. 一部の検索エンジンは動的にレンダリングされたウェブページのコンテンツをサポートしておらず、サポートしている検索エンジンでも通常は動的なウェブサイトのランキングが低くなります。 + +これらの問題を解決するために、ウェブサイトをサーバーサイドでレンダリングすることができます。 + +## 動作原理 + +Yewはページをサーバーサイドでレンダリングするための `ServerRenderer` を提供しています。 + +Yewコンポーネントをサーバーサイドでレンダリングするには、`ServerRenderer::::new()` を使用してレンダラーを作成し、`renderer.render().await` を呼び出して `` を `String` としてレンダリングします。 + +```rust +use yew::prelude::*; +use yew::ServerRenderer; + +#[function_component] +fn App() -> Html { + html! {
{"Hello, World!"}
} +} + +// この例が CI の WASM 環境で動作することを保証するために `flavor = "current_thread"` を使用しています。 +// マルチスレッドを使用したい場合は、デフォルトの `#[tokio::main]` マクロを使用できます。 +#[tokio::main(flavor = "current_thread")] +async fn no_main() { + let renderer = ServerRenderer::::new(); + + let rendered = renderer.render().await; + + // プリント:
Hello, World!
+ println!("{}", rendered); +} +``` + +## コンポーネントのライフサイクル + +クライアントサイドレンダリングとは異なり、サーバーサイドレンダリング時のコンポーネントのライフサイクルは異なります。 + +コンポーネントが最初に `Html` として正常にレンダリングされるまで、`use_effect`(および `use_effect_with`)以外のすべてのフックは正常に動作します。 + +:::caution ブラウザインターフェースは利用できません! + +`web_sys` などのブラウザ関連のインターフェースは、サーバーサイドレンダリング時には利用できません。これらを使用しようとすると、アプリケーションがクラッシュします。このロジックは `use_effect` または `use_effect_with` に隔離する必要があります。これらはサーバーサイドレンダリング時には実行されないためです。 + +::: + +:::danger 構造化コンポーネント + +サーバーサイドレンダリング時に構造化コンポーネントを使用することは可能ですが、クライアントサイドの安全なロジック(関数コンポーネントの `use_effect` フックなど)とライフサイクルイベントの間には明確な境界がなく、ライフサイクルイベントの呼び出し順序もクライアントとは異なります。 + +さらに、構造化コンポーネントは、すべての子コンポーネントがレンダリングされ `destroy` メソッドが呼び出されるまでメッセージを受け取り続けます。開発者は、コンポーネントに渡される可能性のあるメッセージがブラウザインターフェースを呼び出すロジックにリンクされないようにする必要があります。 + +サーバーサイドレンダリングをサポートするアプリケーションを設計する際は、特別な理由がない限り、関数コンポーネントを使用することをお勧めします。 + +::: + +## サーバーサイドレンダリング中のデータ取得 + +データ取得はサーバーサイドレンダリングとハイドレーション(hydration)中の難点の一つです。 + +従来の方法では、コンポーネントがレンダリングされるとすぐに利用可能になります(仮想DOMを出力してレンダリングします)。コンポーネントがデータを取得する必要がない場合、この方法は有効です。しかし、コンポーネントがレンダリング時にデータを取得しようとするとどうなるでしょうか? + +以前は、Yewにはコンポーネントがまだデータを取得しているかどうかを検出するメカニズムがありませんでした。データ取得クライアントは、初期レンダリング中に何が要求されたかを検出し、要求が完了した後に再レンダリングをトリガーするソリューションを実装する責任がありました。サーバーはこのプロセスを繰り返し、応答を返す前にレンダリング中に追加の保留中の要求がないことを確認します。 + +これは、コンポーネントを繰り返しレンダリングするため、CPUリソースを浪費するだけでなく、データクライアントは、サーバー側で取得したデータをハイドレーション中に利用可能にする方法を提供する必要があり、初期レンダリングで返される仮想DOMがサーバーサイドレンダリングのDOMツリーと一致することを保証する必要があります。これは実現が難しい場合があります。 + +Yewは、`` を使用してこの問題を解決する異なるアプローチを採用しています。 + +`` は特別なコンポーネントで、クライアント側で使用する場合、コンポーネントがデータを取得(保留)している間にフォールバックUIを表示し、データ取得が完了した後に通常のUIに戻る方法を提供します。 + +アプリケーションがサーバーサイドレンダリングされると、Yewはコンポーネントが保留状態でなくなるまで待機し、それを文字列バッファにシリアル化します。 + +ハイドレーション中、`` コンポーネント内の要素は、すべての子コンポーネントが保留状態でなくなるまでハイドレーションされません。 + +この方法により、開発者はサーバーサイドレンダリングに対応したクライアント非依存のアプリケーションを簡単に構築し、データ取得を行うことができます。 + +## SSR ハイドレーション + +## サーバーサイドレンダリングハイドレーション(SSR Hydration) + +ハイドレーションは、Yewアプリケーションをサーバー側で生成されたHTMLファイルに接続するプロセスです。デフォルトでは、`ServerRender` はハイドレーション可能なHTML文字列を出力し、追加情報を含んでハイドレーションを容易にします。`Renderer::hydrate` メソッドを呼び出すと、Yewは最初からレンダリングするのではなく、アプリケーションが生成した仮想DOMとサーバーレンダラーが生成したHTML文字列を調整します。 + +:::caution + +`ServerRenderer` が作成したHTMLマークアップを正常にハイドレーションするためには、クライアントはSSRに使用されたレイアウトと完全に一致する仮想DOMレイアウトを生成する必要があります。要素を含まないコンポーネントも含めてです。特定の実装でのみ使用されるコンポーネントがある場合は、`PhantomComponent` を使用して追加のコンポーネントの位置を埋めることを検討してください。 +::: + +:::warning + +SSR出力(静的HTML)をブラウザが初期レンダリングした後、実際のDOMが期待されるDOMと一致する場合にのみ、ハイドレーションは成功します。HTMLが規格に準拠していない場合、ハイドレーションは失敗する可能性があります。ブラウザは不正なHTMLのDOM構造を変更する可能性があり、実際のDOMが期待されるDOMと異なることがあります。例えば、[`` のない `` がある場合、ブラウザはDOMに `` を追加する可能性があります](https://github.com/yewstack/yew/issues/2684)。 +::: + +## ハイドレーション中のコンポーネントライフサイクル + +ハイドレーション中、コンポーネントは作成後に2回連続してレンダリングされます。すべてのエフェクトは2回目のレンダリングが完了した後に呼び出されます。コンポーネントのレンダリング関数に副作用がないことを確認することが重要です。状態を変更したり、追加のレンダリングをトリガーしたりしないようにしてください。現在、状態を変更したり追加のレンダリングをトリガーしたりするコンポーネントがある場合は、それらを `use_effect` フックに移動してください。 + +ハイドレーション中、構造化コンポーネントを使用してサーバーサイドレンダリングを行うことができます。ビュー関数はレンダリング関数の前に複数回呼び出されます。レンダリング関数が呼び出されるまで、DOMは未接続と見なされ、`rendered()` メソッドが呼び出される前にレンダリングノードにアクセスすることを防ぐ必要があります。 + +## 例 + +```rust ,ignore +use yew::prelude::*; +use yew::Renderer; + +#[function_component] +fn App() -> Html { + html! {
{"Hello, World!"}
} +} + +fn main() { + let renderer = Renderer::::new(); + + // body 要素の下のすべてのコンテンツをハイドレーションし、末尾の要素を削除します(存在する場合)。 + renderer.hydrate(); +} +``` +例: [simple_ssr](https://github.com/yewstack/yew/tree/master/examples/simple_ssr) +例: [ssr_router](https://github.com/yewstack/yew/tree/master/examples/ssr_router) + +## シングルスレッドモード + +Yewは `yew::LocalServerRenderer` を使用してシングルスレッドでのサーバーサイドレンダリングをサポートしています。このモードはWASIのようなシングルスレッド環境に適しています。 + +```rust +// Rustc 1.78以降では、`wasm32-wasip1` または `wasm32-wasip2` ターゲットを使用してビルドします。 +// 古いバージョンのRustc(1.84以前)を使用している場合は、`wasm32-wasi` ターゲットを使用してビルドすることもできます。 +// 詳細については、https://blog.rust-lang.org/2024/04/09/updates-to-rusts-wasi-targets.html を参照してください。 + +use yew::prelude::*; +use yew::LocalServerRenderer; + +#[function_component] +fn App() -> Html { + use yew_router::prelude::*; + + html! { + <> +

{"Yew WASI SSR demo"}

+ + } +} + +pub async fn render() -> String { + let renderer = LocalServerRenderer::::new(); + let html_raw = renderer.render().await; + + let mut body = String::new(); + body.push_str(""); + body.push_str("
"); + body.push_str(&html_raw); + body.push_str("
"); + body.push_str(""); + + body +} + +#[tokio::main(flavor = "current_thread")] +async fn main() { + println!("{}", render().await); +} +``` + +例: [wasi_ssr_module](https://github.com/yewstack/yew/tree/master/examples/wasi_ssr_module) + +:::note +`wasm32-unknown-unknown` ターゲットを使用してSSRアプリケーションをビルドする場合、`not_browser_env` 機能フラグを使用して、Yew内部のブラウザ固有のAPIへのアクセスを無効にすることができます。これは、Cloudflare Workerのようなサーバーレスプラットフォームで非常に便利です。 +::: + +:::caution + +サーバーサイドレンダリングは現在実験的な機能です。バグを見つけた場合は、[GitHubで報告してください](https://github.com/yewstack/yew/issues/new?assignees=&labels=bug&template=bug_report.md&title=)。 + +::: diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/callbacks.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/callbacks.mdx new file mode 100644 index 00000000000..17dc93b3286 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/callbacks.mdx @@ -0,0 +1,85 @@ +--- +title: 'コールバック関数 (Callbacks)' +--- + +## コールバック関数 (Callbacks) + +コールバック関数は、Yew でサービス、エージェント、および親コンポーネントと通信するために使用されます。内部的には、それらの型は `Rc` に包まれた `Fn` に過ぎず、クローンを許可します。 + +それらには `emit` 関数があり、その `` 型を引数として取り、それをターゲットが期待するメッセージに変換します。親コンポーネントのコールバック関数が子コンポーネントに props として提供される場合、子コンポーネントはその `update` ライフサイクルフックでコールバック関数の `emit` 関数を呼び出して、メッセージを親コンポーネントに送信できます。`html!` マクロで props として提供されるクロージャまたは関数は、自動的にコールバック関数に変換されます。 + +シンプルなコールバック関数の使用例は次のようになります: + +```rust +use yew::{html, Component, Context, Html}; + +enum Msg { + Clicked, +} + +struct Comp; + +impl Component for Comp { + + type Message = Msg; + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, ctx: &Context) -> Html { + // highlight-next-line + let onclick = ctx.link().callback(|_| Msg::Clicked); + html! { + // highlight-next-line + + } + } +} +``` + +この関数を `callback` に渡す場合、常に1つの引数を持つ必要があります。例えば、`onclick` ハンドラは `MouseEvent` 型の引数を受け取る関数である必要があります。その後、ハンドラはコンポーネントにどのタイプのメッセージを送信するかを決定できます。このメッセージは無条件に次の更新サイクルにスケジュールされます。 + +更新を引き起こす必要がないコールバック関数が必要な場合は、`batch_callback` を使用してください。 + +```rust +use yew::{events::KeyboardEvent, html, Component, Context, Html}; + +enum Msg { + Submit, +} + +struct Comp; + +impl Component for Comp { + + type Message = Msg; + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, ctx: &Context) -> Html { + // highlight-start + let onkeypress = ctx.link().batch_callback(|event: KeyboardEvent| { + if event.key() == "Enter" { + Some(Msg::Submit) + } else { + None + } + }); + + html! { + + } + // highlight-end + } +} +``` + +## 関連例 + +- [Counter](https://github.com/yewstack/yew/tree/master/examples/counter) +- [Timer](https://github.com/yewstack/yew/tree/master/examples/timer) diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/hoc.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/hoc.mdx new file mode 100644 index 00000000000..bc8d3043421 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/hoc.mdx @@ -0,0 +1,82 @@ +--- +title: '高階コンポーネント' +--- + +いくつかの状況では、構造コンポーネントは特定の機能(例えば Suspense)を直接サポートしていないか、または特定の機能を使用するために大量のボイラープレートコードが必要です(例えば Context)。 + +このような場合、高階コンポーネントの関数コンポーネントを作成することをお勧めします。 + +## 高階コンポーネントの定義 + +高階コンポーネントは、新しい HTML を追加せず、他のコンポーネントをラップして追加機能を提供するコンポーネントです。 + +### 例 + +Context(コンテキスト)フックを使用し、それを構造コンポーネントに渡す例 + +```rust +use yew::prelude::*; + +#[derive(Clone, Debug, PartialEq)] +struct Theme { + foreground: String, + background: String, +} + +#[function_component] +pub fn App() -> Html { + let ctx = use_state(|| Theme { + foreground: "#000000".to_owned(), + background: "#eeeeee".to_owned(), + }); + + html! { + context={(*ctx).clone()}> + + > + } +} + +// highlight-start +#[function_component] +pub fn ThemedButtonHOC() -> Html { + let theme = use_context::().expect("no ctx found"); + + html! {} +} +// highlight-end + +#[derive(Properties, PartialEq)] +pub struct Props { + pub theme: Theme, +} + +struct ThemedButtonStructComponent; + +impl Component for ThemedButtonStructComponent { + type Message = (); + type Properties = Props; + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, ctx: &Context) -> Html { + let theme = &ctx.props().theme; + html! { + + } + } +} + + + + +``` diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/introduction.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/introduction.mdx new file mode 100644 index 00000000000..fedf3c692e6 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/introduction.mdx @@ -0,0 +1,28 @@ +--- +title: '紹介' +description: 'Yew のコンポーネント' +--- + +## コンポーネントとは? + +コンポーネントは Yew の構成要素です。内部状態を管理し、要素を DOM にレンダリングできます。`Component` トレイトを実装することでコンポーネントを作成します。 + +## コンポーネントマークアップの作成 + +Yew は仮想 DOM を使用して要素を DOM にレンダリングします。仮想 DOM ツリーは `html!` マクロを使用して構築できます。`html!` の構文は HTML に似ていますが、同じではありません。ルールもより厳格です。また、条件付きレンダリングやイテレータを使用したリストのレンダリングなどの強力な機能も提供します。 + +:::info +[`html!` マクロ、その使用方法、および構文についてさらに詳しく知る](concepts/html/introduction.mdx) +::: + +## コンポーネントにデータを渡す + +Yew コンポーネントは _props_ を使用して親コンポーネントと子コンポーネント間で通信します。親コンポーネントは任意のデータを props として子コンポーネントに渡すことができます。Props は HTML 属性に似ていますが、任意の Rust 型を props として渡すことができます。 + +:::info +[props についてさらに詳しく知る](advanced-topics/struct-components/properties.mdx) +::: + +:::info +親/子通信以外の通信には、[コンテキスト](../../concepts/contexts.mdx) を使用してください +::: diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/lifecycle.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/lifecycle.mdx new file mode 100644 index 00000000000..9007bb65379 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/lifecycle.mdx @@ -0,0 +1,273 @@ +--- +title: 'ライフサイクル' +description: 'コンポーネントとそのライフサイクルフック' +--- + +`Component` トレイトには、実装する必要がある多くのメソッドがあります。Yew はコンポーネントのライフサイクルのさまざまな段階でこれらのメソッドを呼び出します。 + +## ライフサイクル + +:::important ドキュメントの改善 +`ドキュメントに貢献する:` [カスタムライフサイクルを持つコンポーネントの例を追加](https://github.com/yewstack/yew/issues/1915) +::: + +## ライフサイクルメソッド + +### Create + +コンポーネントが作成されるとき、それは親コンポーネントからプロパティを受け取り、それらは `create` メソッドに渡される `Context` に保存されます。これらのプロパティはコンポーネントの状態を初期化するために使用でき、"link" はコールバックを登録したり、コンポーネントにメッセージを送信したりするために使用できます。 + +```rust +use yew::{Component, Context, html, Html, Properties}; + +#[derive(PartialEq, Properties)] +pub struct Props; + +pub struct MyComponent; + +impl Component for MyComponent { + type Message = (); + type Properties = Props; + + // highlight-start + fn create(ctx: &Context) -> Self { + MyComponent + } + // highlight-end + + fn view(&self, _ctx: &Context) -> Html { + html! { + // 具体的な実装 + } + } +} +``` + +### View + +`view` メソッドは、コンポーネントがDOMにどのようにレンダリングされるべきかを記述することを可能にします。Rust関数を使用してHTMLに似たコードを書くことは非常に混乱する可能性があるため、Yewは`html!`マクロを提供しています。これにより、HTMLおよびSVGノードを宣言し(およびそれらに属性とイベントリスナーを追加し)、子コンポーネントを便利にレンダリングする方法が提供されます。このマクロは、ReactのJSXに似ています(プログラミング言語の違いを除いて)。一つの違いは、YewがSvelteのようなプロパティの簡略化された構文を提供している点です。ここでは、`{onclick}`とだけ書くことができ、`onclick={onclick}`と書く必要はありません。 + +```rust +use yew::{Component, Context, html, Html, Properties}; + +enum Msg { + Click, +} + +#[derive(PartialEq, Properties)] +struct Props { + button_text: String, +} + +struct MyComponent; + +impl Component for MyComponent { + type Message = Msg; + type Properties = Props; + + fn create(_ctx: &Context) -> Self { + Self + } + + // highlight-start + fn view(&self, ctx: &Context) -> Html { + let onclick = ctx.link().callback(|_| Msg::Click); + html! { + + } + } + // highlight-end +} +``` + +使用方法の詳細については、[html! ガイド](concepts/html/introduction.mdx) を参照してください。 + +### Rendered + +`rendered` コンポーネントライフサイクルメソッドは、`view` が呼び出され、Yew がその結果を DOM にレンダリングした後、ブラウザがページを更新する前に呼び出されます。このメソッドは、コンポーネントが要素をレンダリングした後にのみ完了できる操作を実行したい場合に非常に便利です。また、`first_render` という名前のパラメーターがあり、この関数が最初のレンダリング時に呼び出されたか、後続のレンダリング時に呼び出されたかを判断するために使用できます。 + +```rust +use web_sys::HtmlInputElement; +use yew::{ + Component, Context, html, Html, NodeRef, +}; + +pub struct MyComponent { + node_ref: NodeRef, +} + +impl Component for MyComponent { + type Message = (); + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self { + node_ref: NodeRef::default(), + } + } + + fn view(&self, ctx: &Context) -> Html { + html! { + + } + } + + // highlight-start + fn rendered(&mut self, _ctx: &Context, first_render: bool) { + if first_render { + if let Some(input) = self.node_ref.cast::() { + input.focus(); + } + } + } + // highlight-end +} +``` + +:::tip note +このライフサイクルメソッドは実装する必要はなく、デフォルトでは何も実行しません。 +::: + +### Update + +コンポーネントとの通信は主にメッセージを通じて行われ、これらのメッセージは `update` ライフサイクルメソッドによって処理されます。これにより、コンポーネントはメッセージに基づいて自身を更新し、再レンダリングが必要かどうかを判断できます。メッセージはイベントリスナー、子コンポーネント、エージェント、サービス、またはフューチャーによって送信されることがあります。 + +以下は `update` の実装例です: + +```rust +use yew::{Component, Context, html, Html}; + +// highlight-start +pub enum Msg { + SetInputEnabled(bool) +} +// highlight-end + +struct MyComponent { + input_enabled: bool, +} + +impl Component for MyComponent { + // highlight-next-line + type Message = Msg; + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self { + input_enabled: false, + } + } + + // highlight-start + fn update(&mut self, _ctx: &Context, msg: Self::Message) -> bool { + match msg { + Msg::SetInputEnabled(enabled) => { + if self.input_enabled != enabled { + self.input_enabled = enabled; + true // 再レンダリング + } else { + false + } + } + } + } + // highlight-end + + fn view(&self, _ctx: &Context) -> Html { + html! { + // 具体的な実装 + } + } + +} +``` + +### Changed + +コンポーネントは親コンポーネントによって再レンダリングされることがあります。この場合、新しいプロパティを受け取り、再レンダリングが必要になることがあります。この設計により、プロパティの値を変更するだけで親子コンポーネント間の通信が促進されます。プロパティが変更されると、デフォルトの実装によりコンポーネントが再レンダリングされます。 + +### Destroy + +コンポーネントがDOMからアンマウントされると、Yewは`destroy`ライフサイクルメソッドを呼び出します。コンポーネントが破棄される前にクリーンアップ操作を実行する必要がある場合に便利です。このメソッドはオプションであり、デフォルトでは何も実行しません。 + +### 無限ループ + +Yewのライフサイクルメソッドでは無限ループが発生する可能性がありますが、それは各レンダリング後に同じコンポーネントを更新し、その更新が再レンダリングを要求する場合にのみ発生します。 + +以下は簡単な例です: + +```rust +use yew::{Context, Component, Html}; + +struct Comp; + +impl Component for Comp { + type Message = (); + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self + } + + fn update(&mut self, _ctx: &Context, _msg: Self::Message) -> bool { + // どのメッセージでも常に再レンダリングを要求します + true + } + + fn view(&self, _ctx: &Context) -> Html { + // レンダリングする内容は重要ではありません + Html::default() + } + + fn rendered(&mut self, ctx: &Context, _first_render: bool) { + // この新しいメッセージを使用してコンポーネントを更新するように要求します + ctx.link().send_message(()); + } +} +``` + +ここで何が起こっているのか見てみましょう: + +1. `create` 関数を使用してコンポーネントを作成します。 +2. `view` メソッドを呼び出して、Yew がブラウザの DOM にレンダリングする内容を知ることができます。 +3. `rendered` メソッドを呼び出し、`Context` リンクを使用して更新メッセージをスケジュールします。 +4. Yew がレンダリングフェーズを完了します。 +5. Yew はスケジュールされたイベントをチェックし、更新メッセージキューが空でないことを確認してメッセージを処理します。 +6. `update` メソッドを呼び出し、変更が発生し、コンポーネントが再レンダリングする必要があることを示す `true` を返します。 +7. ステップ2に戻ります。 + +`rendered` メソッドで更新をスケジュールすることは依然として可能であり、これは通常便利ですが、その際にはこのループをどのように終了させるかを考慮してください。 + +## 関連タイプ + +`Component` トレイトには、`Message` と `Properties` の2つの関連タイプがあります。 + +```rust ,ignore +impl Component for MyComponent { + type Message = Msg; + type Properties = Props; + + // ... +} +``` + +`Message` タイプは、イベントが発生した後にコンポーネントにメッセージを送信するために使用されます。例えば、ユーザーがボタンをクリックしたり、ページをスクロールしたりしたときに何かを実行したい場合があります。コンポーネントは通常、複数のイベントに応答する必要があるため、`Message` タイプは通常、処理するイベントごとにバリアントを持つ列挙型です。 + +コードベースを整理する際には、`Message` タイプの定義をコンポーネントを定義する同じモジュールに含めるのが賢明です。メッセージタイプの命名に一貫した命名規則を採用することが役立つ場合があります。一つのオプション(唯一のオプションではありませんが)は、タイプを `ComponentNameMsg` と命名することです。例えば、コンポーネントが `Homepage` と名付けられている場合、タイプを `HomepageMsg` と命名することができます。 + +```rust +enum Msg { + Click, + FormInput(String) +} +``` + +`Properties` は、親コンポーネントからコンポーネントに渡される情報を表します。この型は `Properties` トレイトを実装する必要があり(通常はそれを派生させる)、特定のプロパティが必須かオプションかを指定できます。コンポーネントの作成および更新時にこの型が使用されます。コンポーネントのモジュール内で `Props` という名前の構造体を作成し、それをコンポーネントの `Properties` 型として使用するのが一般的な方法です。通常、"properties" は "props" と略されます。プロパティは親コンポーネントから渡されるため、アプリケーションのルートコンポーネントは通常、`Properties` 型として `()` を持ちます。ルートコンポーネントにプロパティを指定する場合は、`App::mount_with_props` メソッドを使用します。 + +:::info +[プロパティに関する詳細はこちら](./properties) +::: + +## ライフサイクルコンテキスト + +すべてのコンポーネントライフサイクルメソッドは、コンテキストオブジェクトを受け取ります。このオブジェクトは、コンポーネントのスコープへの参照を提供し、コンポーネントにメッセージを送信したり、コンポーネントに渡されたプロパティを取得したりすることができます。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/properties.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/properties.mdx new file mode 100644 index 00000000000..b4518bba3af --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/properties.mdx @@ -0,0 +1,134 @@ +--- +title: 'プロパティ (Props)' +description: '親子コンポーネント間の通信' +--- + +プロパティ (Properties) は、子コンポーネントと親コンポーネントの間で通信を可能にします。各コンポーネントには、親コンポーネントから渡される内容を記述するための関連プロパティ型があります。理論的には、これは `Properties` トレイトを実装した任意の型である可能性がありますが、実際には、各フィールドがプロパティを表す構造体であるべきです。 + +## 派生マクロ + +`Properties` トレイトを自分で実装する必要はありません。`#[derive(Properties)]` を使用して実装を自動生成できます。`Properties` を派生する型は `PartialEq` も実装する必要があります。 + +### フィールド属性 + +`Properties` を派生する際、デフォルトではすべてのフィールドが必須です。以下の属性を使用すると、他の値が設定されていない限り、プロパティに初期値を提供できます。 + +:::tip +プロパティは Rustdoc によって生成されたドキュメントには表示されません。プロパティのドキュメント文字列には、そのプロパティがオプションであるかどうか、または特別なデフォルト値があるかどうかを記載する必要があります。 +::: + +#### `#[prop_or_default]` + +フィールド型のデフォルト値を使用してプロパティ値を初期化します。これは `Default` トレイトを使用します。 + +#### `#[prop_or(value)]` + +`value` を使用してプロパティ値を初期化します。`value` はフィールド型を返す任意の式である可能性があります。例えば、ブールプロパティをデフォルトで `true` にするには、属性 `#[prop_or(true)]` を使用します。 + +#### `#[prop_or_else(function)]` + +`function` を呼び出してプロパティ値を初期化します。`function` は `FnMut() -> T` のシグネチャを持つ必要があります。ここで、`T` はフィールド型です。 + +## `PartialEq` + +`Properties` は `PartialEq` を実装する必要があります。これにより、Yew はそれらを比較し、変更があった場合に `changed` メソッドを呼び出すことができます。 + +## Properties のパフォーマンスオーバーヘッド + +内部プロパティは参照カウントされたポインタに基づいて格納されます。これにより、コンポーネントツリーに渡されるプロパティにはポインタのみが渡され、プロパティ全体をクローンすることによる高価なパフォーマンスオーバーヘッドを回避できます。 + +:::tip +`AttrValue` を使用してください。これは、クローンが必要な String やその他の類似の型を使用せずに済むようにするために提供されているカスタムプロパティ値型です。 +::: + +## 例 + +```rust +use yew::Properties; +/// virtual_dom から AttrValue をインポート +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 { + /// リンクにはターゲットが必要です + href: AttrValue, + /// また、String ではなく AttrValue を使用していることに注意してください + text: AttrValue, + /// リンクの色、デフォルトは `Blue` + #[prop_or_else(create_default_link_color)] + color: LinkColor, + /// 値が None の場合、ビュー関数はサイズを指定しません + #[prop_or_default] + size: Option, + /// ビュー関数がアクティブを指定しない場合、デフォルトは true + #[prop_or(true)] + active: bool, +} +``` + +## Props マクロ + +`yew::props!` マクロを使用すると、`html!` マクロと同じ方法でプロパティを構築できます。 + +このマクロは構造体の式と同じ構文を使用しますが、属性や基本式 (`Foo { ..base }`) を使用することはできません。型パスはプロパティ (`path::to::Props`) に直接指すことも、コンポーネントの関連プロパティ (`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 { + /// リンクにはターゲットが必要です + href: AttrValue, + /// また、String ではなく AttrValue を使用していることに注意してください + text: AttrValue, + /// リンクの色、デフォルトは `Blue` + #[prop_or_else(create_default_link_color)] + color: LinkColor, + /// 値が None の場合、ビュー関数はサイズを指定しません + #[prop_or_default] + size: Option, + /// ビュー関数がアクティブを指定しない場合、デフォルトは true + #[prop_or(true)] + active: bool, +} + +impl LinkProps { + /// この関数は href と text を String として受け取ります + /// `AttrValue::from` を使用してそれらを `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 + } +} +``` diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/refs.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/refs.mdx new file mode 100644 index 00000000000..d1902c4200e --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/refs.mdx @@ -0,0 +1,51 @@ +--- +title: '参照 (Refs)' +description: 'DOM への越境アクセスを実現する' +--- + +`ref` キーワードは、任意の HTML 要素やコンポーネントに使用して、その要素に付随する DOM `Element` を取得できます。これにより、`view` ライフサイクルメソッドの外で DOM を変更することができます。 + +これは、canvas 要素を取得したり、ページの異なる部分にスクロールしたりするのに便利です。例えば、コンポーネントの `rendered` メソッドで `NodeRef` を使用すると、`view` からレンダリングされた後に canvas 要素に描画呼び出しを行うことができます。 + +構文は次のとおりです: + +```rust +use web_sys::Element; +use yew::{html, Component, Context, Html, NodeRef}; + +struct Comp { + node_ref: NodeRef, +} + +impl Component for Comp { + type Message = (); + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self { + // highlight-next-line + node_ref: NodeRef::default(), + } + } + + fn view(&self, _ctx: &Context) -> Html { + html! { + // highlight-next-line +
+ } + } + + fn rendered(&mut self, _ctx: &Context, _first_render: bool) { + // highlight-start + let has_attributes = self.node_ref + .cast::() + .unwrap() + .has_attributes(); + // highlight-end + } +} +``` + +## 関連例 + +- [ノード参照](https://github.com/yewstack/yew/tree/master/examples/node_refs) diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/scope.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/scope.mdx new file mode 100644 index 00000000000..88c107a8f52 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/advanced-topics/struct-components/scope.mdx @@ -0,0 +1,70 @@ +--- +title: 'スコープ' +description: "コンポーネントのスコープ" +--- + +## コンポーネントの `Scope<_>` インターフェース + +`Scope` は、メッセージを介してコールバックを作成し、自身を更新するメカニズムです。コンポーネントに渡されるコンテキストオブジェクトで `link()` を呼び出すことで、その参照を取得します。 + +### `send_message` + +この関数は、コンポーネントにメッセージを送信できます。メッセージは `update` メソッドによって処理され、コンポーネントが再レンダリングするかどうかを決定します。 + +### `send_message_batch` + +この関数は、コンポーネントに複数のメッセージを同時に送信できます。これは `send_message` に似ていますが、任意のメッセージが `update` メソッドで `true` を返す場合、バッチ内のすべてのメッセージの処理が完了した後にコンポーネントが再レンダリングされます。 + +指定された引数ベクターが空の場合、この関数は何も実行しません。 + +### `callback` + +コールバックを作成し、実行時にコンポーネントにメッセージを送信します。内部的には、提供されたクロージャが返すメッセージを使用して `send_message` を呼び出します。 + +```rust +use yew::{html, Component, Context, Html}; + +enum Msg { + Text(String), +} + +struct Comp; + +impl Component for Comp { + + type Message = Msg; + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self + } + + fn view(&self, ctx: &Context) -> Html { + // テキストを受け取り、それを `Msg::Text` メッセージバリアントとしてコンポーネントに送信するコールバックを作成します。 + // highlight-next-line + let cb = ctx.link().callback(|text: String| Msg::Text(text)); + + // 上の行は冗長であり、より明確にするために次のように簡略化できます: + // highlight-next-line + let cb = ctx.link().callback(Msg::Text); + + // `Msg::Text("Hello World!")` をコンポーネントに送信します。 + // highlight-next-line + cb.emit("Hello World!".to_owned()); + + html! { + // ここに HTML を配置 + } + } +} +``` + +### `batch_callback` + +バッチメッセージを送信するコールバックを作成します。このメソッドに渡されるクロージャはメッセージを返す必要はありません。代わりに、クロージャは `Vec` または `Option` を返すことができます。ここで、`Msg` はコンポーネントのメッセージタイプです。 + +`Vec` はバッチメッセージとして扱われ、内部的に `send_message_batch` を使用します。 + +`Option` は値が `Some` の場合に `send_message` を呼び出します。値が `None` の場合は何も実行しません。これは、更新が不要な場合に使用できます。 + +これは、これらの型に対してのみ実装された `SendAsMessage` トレイトを使用して実現されています。独自の型に対して `SendAsMessage` を実装することで、`batch_callback` でそれらを使用できるようになります。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/agents.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/agents.mdx new file mode 100644 index 00000000000..04af271e92f --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/agents.mdx @@ -0,0 +1,56 @@ +--- +title: 'エージェント (Agents)' +description: "Yew のエージェントシステム" +--- + +import useBaseUrl from '@docusaurus/useBaseUrl' +import ThemedImage from '@theme/ThemedImage' + +エージェント (Agents) は、タスクを Web Workers にオフロードする方法です。 + +エージェントが並行して動作できるようにするために、Yew は [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) を使用します。 + +## ライフサイクル + + + + + +## エージェントの種類 + +### 範囲 + +- 公開 - 任意の時点で、公開エージェントのインスタンスは最大で1つだけです。ブリッジはWeb Worker内でエージェントを生成するか、既に生成されたエージェントに接続します。ブリッジがこのエージェントに接続されていない場合、エージェントは消滅します。 + +- 私有 - 新しいブリッジごとにWeb Worker内で新しいエージェントを生成します。これは、ブラウザと通信する共有だが独立した動作をコンポーネントから移動するのに適しています。接続されたブリッジが破棄されると、エージェントは消滅します。 + +- グローバル \(WIP\) + +## エージェントとコンポーネント間の通信 + +### 通信ブリッジ (Bridges) + +通信ブリッジ(ブリッジ)は、コンポーネントとエージェント間の通信チャネルです。これにより、コンポーネントはエージェントにメッセージを送信し、エージェントからのメッセージを受信できます。 + +`use_bridge` フックは、関数コンポーネント内でブリッジを作成する機能も提供します。 + +### ディスパッチャー (Dispatchers) + +ディスパッチャー(ディスパッチャー)は、コンポーネントとエージェント間の一方向通信を可能にし、コンポーネントがこの方法でエージェントにメッセージを送信します。 + +## オーバーヘッド + +エージェントはWeb Workers(つまり、私有および公開)を使用します。メッセージの送受信時にシリアル化オーバーヘッドが発生します。エージェントは [bincode](https://github.com/bincode-org/bincode) を使用して他のスレッドと通信するため、コストは関数を呼び出すだけの場合よりもはるかに高くなります。 + +## さらなる読み物 + +- [web_worker_fib](https://github.com/yewstack/yew/tree/master/examples/web_worker_fib) の例は、コンポーネントがエージェントにメッセージを送信し、エージェントからのメッセージを受信する方法を示しています。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/css.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/css.mdx new file mode 100644 index 00000000000..fbad27e3d94 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/css.mdx @@ -0,0 +1,99 @@ +--- +title: 'classes! マクロを使用して CSS クラスを処理する' +description: '便利なマクロを使用して CSS クラスを処理する' +comment: 'ファイルを短くシンプルに保つようにしてください。これは、読者が Yew のコンポーネントをより理解しやすくするためであり、正確な API ドキュメントを提供するためではありません。' +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +Yew はネイティブの CSS-in-Rust ソリューションを提供していませんが、HTML の `class` 属性とプログラム的に対話する方法を提供することでスタイルを支援します。 + +## `classes!` マクロ + +`classes!` マクロと関連する `Classes` 構造体は、HTML クラスの使用を簡素化します: + + + + +```rust +use yew::{classes, html}; + +html! { +
+}; +``` + +
+ + +```rust +use yew::{classes, html}; + +html! { +
+}; +``` + +
+ + +```rust +use yew::{classes, html}; + +html! { +
+}; +``` + +
+ + +```rust +use yew::{classes, html}; + +html! { +
+}; +``` + + + + +```rust +use yew::{classes, html}; + +html! { +
+}; +``` + +
+ + +```rust +use yew::{classes, html}; + +html! { +
+}; +``` + +
+ + +詳細な CSS に関する内容は[こちらのドキュメント](../../more/css)をご覧ください。 + +## インラインスタイル + +現在、Yew は `style` 属性を使用して指定されたインラインスタイルを処理するための特別な支援ツールを提供していませんが、他の HTML 属性と同様に処理することができます: + +```rust +use yew::{classes, html}; + +html! { +
+}; +``` + +詳細な CSS に関する内容は[こちらのドキュメント](../../more/css)をご覧ください。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/html.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/html.mdx new file mode 100644 index 00000000000..1747d272b0d --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/html.mdx @@ -0,0 +1,75 @@ +--- +title: 'html! マクロを使用してHTMLを処理する' +description: 'これはHTMLですが、完全にそうではありません!' +comment: 'ファイルを短く簡潔に保つようにしてください。これは、読者がYewのコンポーネントをより簡単に理解できるようにするためであり、正確なAPIドキュメントを提供するためではありません。' +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +`html!` マクロを使用して、HTML に似た式を記述できます。Yew はバックグラウンドでそれを DOM を表現する Rust コードに変換します。 + +```rust +use yew::prelude::*; + +let my_header: Html = html! { + Girl in a jacket +}; +``` + +フォーマットされた式と同様に、波括弧を使用して周囲のコンテキストの値を HTML に埋め込むことができます: + +```rust +use yew::prelude::*; + +let header_text = "Hello world".to_string(); +let header_html: Html = html! { +

{header_text}

+}; + +let count: usize = 5; +let counter_html: Html = html! { +

{"My age is: "}{count}

+}; + +let combined_html: Html = html! { +
{header_html}{counter_html}
+}; +``` + +`html!` を使用する際の重要なルールの 1 つは、1 つのラッピングノードしか返せないということです。複数の要素のリストをレンダリングするために、`html!` は空のタグ(フラグメント)の使用を許可しています。空のタグは名前のないタグで、それ自体は HTML 要素を生成しません。 + + + + +```rust , compile_fail +use yew::html; + +// エラー:ルート HTML 要素は1つだけ許可されています +html! { + +
+

+ +}; +``` + +
+ + +```rust +use yew::html; + +// 修正:HTML 空のタグを使用してラップする +html! { + <> +
+

+ +}; +``` + +
+
+ +詳細については、[HTML の詳細](concepts/html/introduction.mdx)を参照してください。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/js.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/js.mdx new file mode 100644 index 00000000000..64d8cf9c819 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/js.mdx @@ -0,0 +1,50 @@ +--- +title: 'JavaScript と Rust' +description: 'Rust で JavaScript を使用する' +comment: 'ファイルを簡潔に保つようにしてください。これは、読者が Yew のコンポーネントをより理解しやすくするためのものであり、正確な API ドキュメントを提供するためのものではありません。' +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +> Yew は、再利用可能な UI 部分に必要なすべてのコンテンツを1か所に集める一方で、必要に応じて基盤技術へのアクセスも維持します。 + +今日現在、WebAssembly は DOM との相互作用を完全にはサポートしていません。これは、Yew でも時々 JavaScript の呼び出しに依存することを意味します。次に、関係するライブラリの概要を示します。 + +## wasm-bindgen + +[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) は、JavaScript と Rust 関数の間に呼び出しの橋を架けるライブラリとツールです。 + +彼らの[ドキュメント](https://rustwasm.github.io/docs/wasm-bindgen/)と私たちの[クイックガイド](./wasm-bindgen.mdx)を強くお勧めします。 + +## web-sys + +[`web-sys` crate](https://crates.io/crates/web-sys) は Web API のバインディングを提供し、Rust で処理され安全な方法で JavaScript コードを書くことを可能にします。 + +例: + + + + +```js +let document = window.document +``` + + + + + +```rust ,no_run +use wasm_bindgen::UnwrapThrowExt; +use web_sys::window; + +let document = window() + .expect_throw("window is undefined") + .document() + .expect_throw("document is undefined"); +``` + + + + +繰り返しになりますが、彼らの[ドキュメント](https://rustwasm.github.io/docs/wasm-bindgen/)と私たちの[クイックガイド](./web-sys.mdx)を強くお勧めします。 diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/wasm-bindgen.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/wasm-bindgen.mdx new file mode 100644 index 00000000000..a0c3b2dd294 --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/wasm-bindgen.mdx @@ -0,0 +1,177 @@ +--- +title: 'wasm-bindgen' +sidebar_label: wasm-bindgen +--- + +[`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) は、JavaScript と Rust 関数の間に呼び出しブリッジを作成するためのライブラリおよびツールです。これは [Rust と WebAssembly ワーキンググループ](https://rustwasm.github.io/) によって Rust で構築されました。 + +Yew は `wasm-bindgen` を使用して、いくつかのクレートを介してブラウザと対話します: + +- [`js-sys`](https://crates.io/crates/js-sys) +- [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen) +- [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures) +- [`web-sys`](https://crates.io/crates/web-sys) + +このセクションでは、これらのクレートをより抽象的なレベルから探求し、Yew での `wasm-bindgen` API の理解と使用を容易にします。`wasm-bindgen` および関連するクレートに関する詳細なガイドについては、[`wasm-bindgen` ガイド](https://rustwasm.github.io/docs/wasm-bindgen/) を参照してください。 + +上記のクレートのドキュメントについては、[`wasm-bindgen docs.rs`](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/index.html) を参照してください。 + +:::tip +`wasm-bindgen` doc.rs 検索を使用して、`wasm-bindgen` を使用してインポートされたブラウザ API および JavaScript タイプを見つけます。 +::: + +## [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen) + +このクレートは、上記の他のクレートに多くの構成要素を提供します。このセクションでは、`wasm-bindgen` クレートの主要な領域の 2 つ、つまりマクロと、何度も目にするタイプ/トレイトのいくつかについてのみ説明します。 + +### `#[wasm_bindgen]` マクロ + +`#[wasm_bindgen]` マクロは Rust と JavaScript の間のインターフェースを提供し、両者の間で変換を行うシステムを提供します。このマクロの使用はより高度であり、外部の JavaScript ライブラリを使用する場合を除いて使用しないでください。`js-sys` および `web-sys` クレートは、組み込みの JavaScript タイプおよびブラウザ API に対して `wasm-bindgen` 定義を提供します。 + +`#[wasm-bindgen]` マクロを使用して、特定のバージョンの [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) 関数をインポートする簡単な例を見てみましょう。 + +```rust ,no_run +use wasm_bindgen::prelude::*; + +// まず、`web_sys` を使用せずに `console.log` を手動でバインドしてみましょう。 +// ここでは、手動で `#[wasm_bindgen]` アノテーションを書きます。プログラムの正確性はこれらのアノテーションの正確性に依存します! +#[wasm_bindgen] +extern "C" { + // ここで `js_namespace` を使用して `console.log(..)` をバインドします。`log(..)` だけではありません。 + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); + + // `console.log` は多態的なので、複数のシグネチャを使用してバインドできます。 + #[wasm_bindgen(js_namespace = console, js_name = log)] + fn log_u32(a: u32); + + // 複数の引数も可能です! + #[wasm_bindgen(js_namespace = console, js_name = log)] + fn log_many(a: &str, b: &str); +} + +// インポートされた関数を使用します! +log("Hello from Rust!"); +log_u32(42); +log_many("Logging", "many values!"); +``` + +_この例は、[1.2 `wasm-bindgen` ガイドの console.log を使用する](https://rustwasm.github.io/docs/wasm-bindgen/examples/console-log.html) に基づいています。_ + +### 継承のシミュレーション + +JavaScript クラス間の継承は、JavaScript 言語のコア機能であり、DOM(ドキュメントオブジェクトモデル)はそれを中心に設計されています。`wasm-bindgen` を使用して型をインポートする際にも、それらの継承関係を記述する属性を追加できます。 + +Rust では、この継承関係は [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) と [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) トレイトを使用して表現されます。ここで例を挙げると役立つかもしれません。例えば、`A`、`B`、`C` という 3 つの型があり、`C` が `B` を拡張し、`B` が `A` を拡張しているとします。 + +これらの型をインポートする際、`#[wasm-bindgen]` マクロは次のように `Deref` と `AsRef` トレイトを実装します: + +- `C` は `B` に `Deref` できます +- `B` は `A` に `Deref` できます +- `C` は `B` に `AsRef` できます +- `C` と `B` はどちらも `A` に `AsRef` できます + +これらの実装により、`C` のインスタンスで `A` のメソッドを呼び出したり、`C` を `&B` または `&A` として使用したりできます。 + +注意すべき点は、`#[wasm-bindgen]` を使用してインポートされたすべての型には同じルート型があり、それを上記の例の `A` と見なすことができるということです。この型は [`JsValue`](#jsvalue) であり、以下にそのセクションがあります。 + +_[`wasm-bindgen` ガイドの extends セクション](https://rustwasm.github.io/docs/wasm-bindgen/reference/attributes/on-js-imports/extends.html)_ + +### [`JsValue`](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html) + +これは JavaScript が所有するオブジェクトの表現であり、`wasm-bindgen` のルートキャプチャ型です。`wasm-bindgen` からの任意の型は `JsValue` です。これは、JavaScript には強い型システムがないため、変数 `x` を受け取る任意の関数がその型を定義しないため、`x` は有効な JavaScript 値である可能性があるためです。したがって `JsValue` です。`JsValue` を受け取るインポート関数や型を使用している場合、技術的には任意のインポート値が有効です。 + +`JsValue` は関数で受け取ることができますが、その関数は特定の型のみを受け取る可能性があり、それがパニックを引き起こす可能性があります。したがって、元の `wasm-bindgen` API を使用する場合は、インポートされた JavaScript のドキュメントを確認して、その値が特定の型でない場合に例外(パニック)を引き起こすかどうかを確認してください。 + +_[`JsValue` ドキュメント](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/struct.JsValue.html)_ + +### [`JsCast`](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html) + +Rust には強い型システムがありますが、JavaScript にはありません😞。Rust がこれらの強い型を維持しながらも便利であるために、WebAssembly ワーキンググループは非常に巧妙な機能 `JsCast` を提案しました。これは、ある JavaScript "型" から別の "型" への変換を支援するものです。これは曖昧に聞こえますが、ある型が別の型であることがわかっている場合、`JsCast` の関数を使用してある型から別の型にジャンプできます。`web-sys`、`wasm_bindgen`、`js-sys` を使用する際にこの機能を理解しておくと便利です。これらのクレートから多くの型が `JsCast` を実装していることに気付くでしょう。 + +`JsCast` はチェック付きとチェックなしの変換メソッドを提供します。したがって、実行時にオブジェクトがどの型であるかわからない場合は、変換を試みることができ、失敗する可能性のある型として [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) や [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html) を返します。 + +一般的な例は [`web-sys`](./web-sys.mdx) で、イベントのターゲットを取得しようとする場合です。ターゲット要素が何であるかを知っているかもしれませんが、[`web_sys::Event`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Event.html) API は常に [`Option`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Event.html#method.target) を返します。 +その要素型に変換する必要があり、そのメソッドを呼び出すことができます。 + +```rust +// このトレイトを最初にインポートする必要があります +use wasm_bindgen::JsCast; +use web_sys::{Event, EventTarget, HtmlInputElement, HtmlSelectElement}; + +fn handle_event(event: Event) { + let target: EventTarget = event + .target() + .expect("I'm sure this event has a target!"); + + // もしかしたらターゲットは選択要素かもしれませんか? + if let Some(select_element) = target.dyn_ref::() { + // 別のことをする + return; + } + + // それが選択要素でないことが確実であれば、入力要素であることが確実です! + let input_element: HtmlInputElement = target.unchecked_into(); +} +``` + +[`dyn_ref`](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_ref) メソッドはチェック付きの変換であり、`Option<&T>` を返します。これは、変換が失敗した場合に元の型を再度使用できることを意味し、`None` を返します。 [`dyn_into`](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html#method.dyn_into) メソッドは `self` を消費し、Rust の `into` メソッドの規約に従い、`Result` 型を返します。変換が失敗した場合、元の `Self` 値は `Err` に返されます。再試行するか、元の型で他の操作を行うことができます。 + +_[`JsCast` ドキュメント](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/trait.JsCast.html)._ + +### [`Closure`](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html) + +`Closure` 型は、Rust のクロージャを JavaScript に渡す方法を提供します。健全性の理由から、JavaScript に渡されるクロージャは `'static` ライフタイムを持つ必要があります。 + +この型は「ハンドル」であり、破棄されると、それが参照する JS クロージャを無効にします。`Closure` が破棄された後、JS 内のクロージャの使用はすべて例外を引き起こします。 + +`Closure` は、[`&js_sys::Function`](https://rustwasm.github.io/wasm-bindgen/api/js_sys/struct.Function.html) 型を受け取る `js-sys` または `web-sys` API を使用する際に一般的に使用されます。Yew で `Closure` を使用する例は、[Events](../html/events.mdx) ページの[Using `Closure` セクション](../html/events.mdx#using-closure-verbose) にあります。 + +_[`Closure` ドキュメント](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html)._ + +## [`js-sys`](https://crates.io/crates/js-sys) + +`js-sys` クレートは、JavaScript の標準組み込みオブジェクトのバインディング/インポートを提供します。これには、それらのメソッドやプロパティが含まれます。 + +これは Web API を含みません。Web API は [`web-sys`](./web-sys.mdx) の役割です! + +_[`js-sys` ドキュメント](https://rustwasm.github.io/wasm-bindgen/api/js_sys/index.html)._ + +## [`wasm-bindgen-futures`](https://crates.io/crates/wasm-bindgen-futures) + +`wasm-bindgen-futures` クレートは、JavaScript の Promise 型を Rust の [`Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html) として扱うためのブリッジを提供し、Rust の Future を JavaScript の Promise に変換するユーティリティを含みます。Rust(wasm)で非同期または他のブロッキング作業を処理する際に役立ち、JavaScript のイベントや JavaScript I/O プリミティブと対話する能力を提供します。 + +現在、このクレートには3つの主要なインターフェースがあります: + +1. [`JsFuture`](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen_futures/struct.JsFuture.html) - + [`Promise`](https://rustwasm.github.io/wasm-bindgen/api/js_sys/struct.Promise.html) を使用して構築された型で、`Future>` として使用できます。`Promise` が解決されると、この `Future` は `Ok` に解決され、`Promise` が拒否されると `Err` に解決され、それぞれ `Promise` の解決または拒否の値を含みます。 + +2. [`future_to_promise`](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.future_to_promise.html) - + Rust の `Future>` を JavaScript の `Promise` に変換します。Future の結果は、JavaScript 内の解決または拒否された `Promise` に変換されます。 + +3. [`spawn_local`](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) - + 現在のスレッドで `Future` を生成します。これは、Rust 内で Future を実行する最良の方法であり、JavaScript に送信するのではなく、Rust 内で実行します。 + +_[`wasm-bindgen-futures` ドキュメント](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen_futures/index.html)._ + +### [`spawn_local`](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html) + +`spawn_local` は、非同期 API を使用するライブラリを使用する際に、Yew で `wasm-bindgen-futures` クレートの最も一般的に使用される部分です。 + +```rust ,no_run +use web_sys::console; +use wasm_bindgen_futures::spawn_local; + +async fn my_async_fn() -> String { String::from("Hello") } + +spawn_local(async { + let mut string = my_async_fn().await; + string.push_str(", world!"); + // "Hello, world!" を出力します + console::log_1(&string.into()); +}); +``` + +Yew はいくつかの API に futures のサポートを追加しており、特に `async` ブロックを受け入れる `callback_future` を作成できることが注目されます。これは内部的に `spawn_local` を使用しています。 + +_[`spawn_local` ドキュメント](https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen_futures/fn.spawn_local.html)._ diff --git a/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/web-sys.mdx b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/web-sys.mdx new file mode 100644 index 00000000000..b1c9117ed5d --- /dev/null +++ b/website/i18n/ja/docusaurus-plugin-content-docs/version-0.22/concepts/basic-web-technologies/web-sys.mdx @@ -0,0 +1,210 @@ +--- +title: 'web-sys' +description: 'web-sys クレートは Web API のバインディングを提供します。' +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +[`web-sys` クレート](https://crates.io/crates/web-sys) は Web API のバインディングを提供します。これはブラウザの WebIDL から生成されるため、名前が長くなったり、型が曖昧になったりすることがあります。 + +## `web-sys` の特性 (features) + +`web-sys` クレートで全ての特性を有効にすると、Wasm アプリケーションに多くの冗長性が追加される可能性があります。この問題を解決するために、ほとんどの型は特性を有効にすることで制御され、アプリケーションに必要な型だけを含めることができます。Yew は `web-sys` のいくつかの特性を有効にし、その公開 API でいくつかの型を公開しています。通常、`web-sys` を依存関係として追加する必要があります。 + +## `web-sys` の継承 + +[継承のシミュレーション](./wasm-bindgen.mdx#simulating-inheritance)のセクションでは、Rust が通常 JavaScript の継承をシミュレートする方法を提供していることがわかります。これは `web-sys` で非常に重要です。ある型にどのようなメソッドがあるかを理解するためには、その継承を理解する必要があります。 + +このセクションでは、特定の要素を見て、Rust で [`Deref::deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref) を呼び出して、その値が [`JsValue`](./wasm-bindgen.mdx#jsvalue) になるまでの継承をリストします。 + +```rust +use std::ops::Deref; +use web_sys::{ + Element, + EventTarget, + HtmlElement, + HtmlTextAreaElement, + Node, +}; + +fn inheritance_of_text_area(text_area: HtmlTextAreaElement) { + // HtmlTextAreaElement は HTML の