From b25703a035c698f2b88b2b5e087922b3af529ac7 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Fri, 22 Dec 2023 08:06:27 +0100 Subject: [PATCH 1/7] Add yew-autoprops to website documentation (#3505) --- Cargo.lock | 27 +++- .../tests/classes_macro/classes-fail.stderr | 12 +- .../tests/html_macro/element-fail.stderr | 83 +++++++------ packages/yew/Cargo.toml | 2 +- tools/website-test/Cargo.toml | 1 + .../function-components/properties.mdx | 117 +++++++++++++----- 6 files changed, 162 insertions(+), 80 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b560bd7eaef..b015bc8386a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1675,13 +1675,24 @@ dependencies = [ [[package]] name = "implicit-clone" -version = "0.4.1" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3d77000817fd9e7db159e8d52ed9b5941a2cdbfbdc8ca646e59887ae2b2dd1" +checksum = "fc06a255cbf402a52ae399c05a518c68c569c916ea11423620111df576b9b9bb" dependencies = [ + "implicit-clone-derive", "indexmap 2.0.2", ] +[[package]] +name = "implicit-clone-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b" +dependencies = [ + "quote", + "syn 2.0.38", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -3615,6 +3626,7 @@ dependencies = [ "weblog", "yew", "yew-agent", + "yew-autoprops", "yew-router", ] @@ -3876,6 +3888,17 @@ dependencies = [ "yew-agent", ] +[[package]] +name = "yew-autoprops" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58865a8f2470a6ad839274e05c9627170d32930f39a2348f8c425880a6131792" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "yew-macro" version = "0.21.0" diff --git a/packages/yew-macro/tests/classes_macro/classes-fail.stderr b/packages/yew-macro/tests/classes_macro/classes-fail.stderr index 57cf0f21fb7..9d30a817b18 100644 --- a/packages/yew-macro/tests/classes_macro/classes-fail.stderr +++ b/packages/yew-macro/tests/classes_macro/classes-fail.stderr @@ -21,7 +21,7 @@ error[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied >> > > - > + > >> >> > @@ -44,7 +44,7 @@ error[E0277]: the trait bound `Classes: From<{float}>` is not satisfied >> > > - > + > >> >> > @@ -67,7 +67,7 @@ error[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied >> > > - > + > >> >> > @@ -93,7 +93,7 @@ error[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied >> > > - > + > >> >> > @@ -119,7 +119,7 @@ error[E0277]: the trait bound `Classes: From` is not satisfied >> > > - > + > >> >> > @@ -145,7 +145,7 @@ error[E0277]: the trait bound `Classes: From<{integer}>` is not satisfied >> > > - > + > >> >> > diff --git a/packages/yew-macro/tests/html_macro/element-fail.stderr b/packages/yew-macro/tests/html_macro/element-fail.stderr index 11f9e7d631a..bcc320a8975 100644 --- a/packages/yew-macro/tests/html_macro/element-fail.stderr +++ b/packages/yew-macro/tests/html_macro/element-fail.stderr @@ -396,76 +396,76 @@ note: function defined here | pub fn __ensure_type(_: T) {} | ^^^^^^^^^^^^^ -error[E0277]: the trait bound `(): IntoPropValue>` is not satisfied +error[E0277]: the trait bound `(): IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:43:26 | 43 | html! { }; - | ^^ the trait `IntoPropValue>` is not implemented for `()` + | ^^ the trait `IntoPropValue>` is not implemented for `()` | = help: the trait `IntoPropValue` is implemented for `()` -error[E0277]: the trait bound `(): IntoPropValue>` is not satisfied +error[E0277]: the trait bound `(): IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:44:27 | 44 | html! { }; - | ^^ the trait `IntoPropValue>` is not implemented for `()` + | ^^ the trait `IntoPropValue>` is not implemented for `()` | = help: the trait `IntoPropValue` is implemented for `()` -error[E0277]: the trait bound `(): IntoPropValue>` is not satisfied +error[E0277]: the trait bound `(): IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:45:22 | 45 | html! { }; - | ^^ the trait `IntoPropValue>` is not implemented for `()` + | ^^ the trait `IntoPropValue>` is not implemented for `()` | = help: the trait `IntoPropValue` is implemented for `()` -error[E0277]: the trait bound `NotToString: IntoPropValue>` is not satisfied +error[E0277]: the trait bound `NotToString: IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:46:28 | 46 | html! { }; - | ^^^^^^^^^^^ the trait `IntoPropValue>` is not implemented for `NotToString` + | ^^^^^^^^^^^ the trait `IntoPropValue>` is not implemented for `NotToString` | = help: the following other types implement trait `IntoPropValue`: - <&'static [(K, V)] as IntoPropValue>> - <&'static [T] as IntoPropValue>> + <&'static [(K, V)] as IntoPropValue>> + <&'static [T] as IntoPropValue>> <&'static str as IntoPropValue> <&'static str as IntoPropValue>> - <&'static str as IntoPropValue>> + <&'static str as IntoPropValue>> <&'static str as IntoPropValue> - <&'static str as IntoPropValue> + <&'static str as IntoPropValue> <&String as IntoPropValue> and $N others -error[E0277]: the trait bound `Option: IntoPropValue>` is not satisfied +error[E0277]: the trait bound `Option: IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:47:23 | 47 | html! { }; - | ^^^^ the trait `IntoPropValue>` is not implemented for `Option` + | ^^^^ the trait `IntoPropValue>` is not implemented for `Option` | = help: the following other types implement trait `IntoPropValue`: as IntoPropValue>> - as IntoPropValue>> - > as IntoPropValue>> + as IntoPropValue>> + > as IntoPropValue>> as IntoPropValue>>> - > as IntoPropValue>> - as IntoPropValue>> + > as IntoPropValue>> + as IntoPropValue>> > as IntoPropValue>>> as IntoPropValue> -error[E0277]: the trait bound `Option<{integer}>: IntoPropValue>` is not satisfied +error[E0277]: the trait bound `Option<{integer}>: IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:48:22 | 48 | html! { }; - | ^^^^ the trait `IntoPropValue>` is not implemented for `Option<{integer}>` + | ^^^^ the trait `IntoPropValue>` is not implemented for `Option<{integer}>` | = help: the following other types implement trait `IntoPropValue`: as IntoPropValue>> - as IntoPropValue>> - > as IntoPropValue>> + as IntoPropValue>> + > as IntoPropValue>> as IntoPropValue>>> - > as IntoPropValue>> - as IntoPropValue>> + > as IntoPropValue>> + as IntoPropValue>> > as IntoPropValue>>> as IntoPropValue> @@ -567,11 +567,11 @@ error[E0277]: the trait bound `Option: IntoPropValue | = help: the following other types implement trait `IntoPropValue`: as IntoPropValue>> - as IntoPropValue>> - > as IntoPropValue>> + as IntoPropValue>> + > as IntoPropValue>> as IntoPropValue>>> - > as IntoPropValue>> - as IntoPropValue>> + > as IntoPropValue>> + as IntoPropValue>> > as IntoPropValue>>> as IntoPropValue> = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -603,20 +603,20 @@ note: required by a bound in `yew::html::onclick::Wrapper::__macro_new` | |_^ required by this bound in `yew::html::onclick::Wrapper::__macro_new` = note: this error originates in the macro `impl_action` which comes from the expansion of the macro `impl_short` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `NotToString: IntoPropValue>` is not satisfied +error[E0277]: the trait bound `NotToString: IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:60:28 | 60 | html! { }; - | ^^^^^^^^^^^ the trait `IntoPropValue>` is not implemented for `NotToString` + | ^^^^^^^^^^^ the trait `IntoPropValue>` is not implemented for `NotToString` | = help: the following other types implement trait `IntoPropValue`: - <&'static [(K, V)] as IntoPropValue>> - <&'static [T] as IntoPropValue>> + <&'static [(K, V)] as IntoPropValue>> + <&'static [T] as IntoPropValue>> <&'static str as IntoPropValue> <&'static str as IntoPropValue>> - <&'static str as IntoPropValue>> + <&'static str as IntoPropValue>> <&'static str as IntoPropValue> - <&'static str as IntoPropValue> + <&'static str as IntoPropValue> <&String as IntoPropValue> and $N others @@ -629,15 +629,16 @@ error[E0277]: the trait bound `(): IntoPropValue` is not satisfied = help: the trait `IntoPropValue` is implemented for `()` = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `implicit_clone::unsync::IString: From<{integer}>` is not satisfied +error[E0277]: the trait bound `implicit_clone::unsync::string::IString: From<{integer}>` is not satisfied --> tests/html_macro/element-fail.rs:77:16 | 77 | html! { <@{55}> }; - | ^^ the trait `From<{integer}>` is not implemented for `implicit_clone::unsync::IString` + | ^^ the trait `From<{integer}>` is not implemented for `implicit_clone::unsync::string::IString` | = help: the following other types implement trait `From`: - > - >> - >> - > - = note: required because of the requirements on the impl of `Into` for `{integer}` + > + > + >> + >> + > + = note: required because of the requirements on the impl of `Into` for `{integer}` diff --git a/packages/yew/Cargo.toml b/packages/yew/Cargo.toml index 89cd95b4c6c..27c6c545ef8 100644 --- a/packages/yew/Cargo.toml +++ b/packages/yew/Cargo.toml @@ -27,7 +27,7 @@ yew-macro = { version = "^0.21.0", path = "../yew-macro" } thiserror = "1.0" futures = { version = "0.3", default-features = false, features = ["std"] } html-escape = { version = "0.2.13", optional = true } -implicit-clone = { version = "0.4.1", features = ["map"] } +implicit-clone = { version = "0.4.8", features = ["map"] } base64ct = { version = "1.6.0", features = ["std"], optional = true } bincode = { version = "1.3.3", optional = true } serde = { version = "1", features = ["derive"] } diff --git a/tools/website-test/Cargo.toml b/tools/website-test/Cargo.toml index e24d135286e..a930210e718 100644 --- a/tools/website-test/Cargo.toml +++ b/tools/website-test/Cargo.toml @@ -17,6 +17,7 @@ wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" weblog = "0.3.0" yew = { path = "../../packages/yew/", features = ["ssr", "csr"] } +yew-autoprops = "0.4.1" yew-router = { path = "../../packages/yew-router/" } tokio = { version = "1.33.0", features = ["rt", "macros"] } diff --git a/website/docs/concepts/function-components/properties.mdx b/website/docs/concepts/function-components/properties.mdx index d331425ec92..2927004e87f 100644 --- a/website/docs/concepts/function-components/properties.mdx +++ b/website/docs/concepts/function-components/properties.mdx @@ -60,14 +60,14 @@ pub struct Props { } #[function_component] -fn HelloWorld(props: &Props) -> Html { - html! { <>{"Am I loading? - "}{props.is_loading.clone()} } +fn HelloWorld(&Props { is_loading }: &Props) -> Html { + html! { <>{"Am I loading? - "}{is_loading} } } // Then supply the prop #[function_component] fn App() -> Html { - html! {} + html! { } } ``` @@ -91,7 +91,7 @@ fn HelloWorld() -> Html { // No props to supply #[function_component] fn App() -> Html { - html! {} + html! { } } ``` @@ -126,8 +126,8 @@ pub struct Props { } #[function_component] -fn HelloWorld(props: &Props) -> Html { - if props.is_loading.clone() { +fn HelloWorld(&Props { is_loading }: &Props) -> Html { + if is_loading { html! { "Loading" } } else { html! { "Hello world" } @@ -137,12 +137,12 @@ fn HelloWorld(props: &Props) -> Html { // Then use like this with default #[function_component] fn Case1() -> Html { - html! {} + html! { } } // Or no override the default #[function_component] fn Case2() -> Html { - html! {} + html! { } } ``` @@ -154,30 +154,36 @@ For example, to default a boolean prop to `true`, use the attribute `#[prop_or(t is evaluated when the properties are constructed and no explicit value has been given. ```rust -use yew::{function_component, html, Html, Properties}; +use yew::prelude::*; #[derive(Properties, PartialEq)] pub struct Props { + #[prop_or_default] + pub is_loading: bool, // highlight-start - #[prop_or("Bob".to_string())] + #[prop_or(AttrValue::Static("Bob"))] // highlight-end - pub name: String, + pub name: AttrValue, } #[function_component] -fn HelloWorld(props: &Props) -> Html { - html! {<>{"Hello world"}{props.name.clone()}} +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! {} + html! { } } // Or no override the default #[function_component] fn Case2() -> Html { - html! {} + html! { } } ``` @@ -188,34 +194,40 @@ Call `function` to initialize the prop value. `function` should have the signatu The function is called when no explicit value has been given for that attribute. ```rust -use yew::{function_component, html, Html, Properties}; +use yew::prelude::*; -fn create_default_name() -> String { - "Bob".to_string() +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: String, + pub name: AttrValue, } #[function_component] -fn HelloWorld(props: &Props) -> Html { - html! {<>{"Hello world"}{props.name.clone()}} +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! {} + html! { } } // Or no override the default #[function_component] fn Case2() -> Html { - html! {} + html! { } } ``` @@ -239,28 +251,68 @@ The macro uses the same syntax as a struct expression except that you can't use 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, virtual_dom::AttrValue}; +use yew::prelude::*; #[derive(Properties, PartialEq)] pub struct Props { - #[prop_or(AttrValue::from("Bob"))] + #[prop_or_default] + pub is_loading: bool, + #[prop_or(AttrValue::Static("Bob"))] pub name: AttrValue, } #[function_component] -fn HelloWorld(props: &Props) -> Html { - html! {<>{"Hello world"}{props.name.clone()}} +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 = props! { + let pre_made_props = yew::props! { Props {} // Notice we did not need to specify name prop }; // highlight-end - html! {} + 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 @@ -296,7 +348,12 @@ These include, but are not limited to: **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. You tell us. Did you run into an edge-case you wish you knew about earlier? Feel free to create an issue +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 From 16f26d82e75d17dc24e909140828366a1d6aac6b Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Sat, 23 Dec 2023 11:07:29 +0100 Subject: [PATCH 2/7] use_state: fix/clarify docstring (#3570) Signed-off-by: Yann Dirson --- packages/yew/src/functional/hooks/use_state.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yew/src/functional/hooks/use_state.rs b/packages/yew/src/functional/hooks/use_state.rs index 055285a0582..441f3a5d96f 100644 --- a/packages/yew/src/functional/hooks/use_state.rs +++ b/packages/yew/src/functional/hooks/use_state.rs @@ -63,8 +63,8 @@ where /// # Caution /// /// The value held in the handle will reflect the value of at the time the -/// handle is returned by the `use_reducer`. It is possible that the handle does -/// not dereference to an up to date value if you are moving it into a +/// handle is returned by the `use_state()` call. It is possible that the handle does +/// not dereference to an up to date value, for example if you are moving it into a /// `use_effect_with` hook. You can register the /// state to the dependents so the hook can be updated when the value changes. /// From f6b23f08284dec949efaf860fbe8e9198e3d0bed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 23:32:06 +0900 Subject: [PATCH 3/7] Bump openssl from 0.10.55 to 0.10.60 (#3545) Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.55 to 0.10.60. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.55...openssl-v0.10.60) --- updated-dependencies: - dependency-name: openssl dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b015bc8386a..262361ca551 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2155,11 +2155,11 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cfg-if", "foreign-types", "libc", @@ -2187,9 +2187,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ "cc", "libc", From d0419a278dc126af4556c9afae2ef6b00b5fef36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 12:52:20 +0100 Subject: [PATCH 4/7] Bump libgit2-sys from 0.16.1+1.7.1 to 0.16.2+1.7.2 (#3602) Bumps [libgit2-sys](https://github.com/rust-lang/git2-rs) from 0.16.1+1.7.1 to 0.16.2+1.7.2. - [Changelog](https://github.com/rust-lang/git2-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/git2-rs/commits) --- updated-dependencies: - dependency-name: libgit2-sys dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 262361ca551..40f85bf1fa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1890,9 +1890,9 @@ checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libgit2-sys" -version = "0.16.1+1.7.1" +version = "0.16.2+1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a2bb3680b094add03bb3732ec520ece34da31a8cd2d633d1389d0f0fb60d0c" +checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" dependencies = [ "cc", "libc", From 46ebdc8d4bf4ce12befbe6e19776d3adbd95a14e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 08:44:05 +0100 Subject: [PATCH 5/7] Bump mio from 0.8.8 to 0.8.11 (#3624) Bumps [mio](https://github.com/tokio-rs/mio) from 0.8.8 to 0.8.11. - [Release notes](https://github.com/tokio-rs/mio/releases) - [Changelog](https://github.com/tokio-rs/mio/blob/master/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/mio/compare/v0.8.8...v0.8.11) --- updated-dependencies: - dependency-name: mio dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40f85bf1fa5..1da9a34717e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1884,9 +1884,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libgit2-sys" @@ -2031,9 +2031,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", From 95c29cc6848f5397d4f8cb95267bead446e1047c Mon Sep 17 00:00:00 2001 From: WorldSEnder Date: Tue, 12 Mar 2024 13:25:11 +0000 Subject: [PATCH 6/7] Fix: Hydratation of empty lists next to components. (#3630) * fix: hydration of empty VLists an additional (empty) VText was inserted in the second reconciliation pass, which tried to insert itself in an invalid position. This internal error was masked by a "fix" of the internal slot of components, which should have still been trapped to signal that the second fixup render was not yet run. * fixup: new lints from clippy --- Cargo.lock | 87 ++++++++++++++++++- packages/yew/src/callback.rs | 4 +- packages/yew/src/dom_bundle/blist.rs | 12 +-- packages/yew/src/dom_bundle/utils.rs | 9 +- .../yew/src/functional/hooks/use_reducer.rs | 5 +- packages/yew/src/html/component/lifecycle.rs | 4 +- packages/yew/src/html/component/scope.rs | 8 +- packages/yew/src/suspense/suspension.rs | 2 +- packages/yew/src/virtual_dom/listeners.rs | 8 +- 9 files changed, 107 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1da9a34717e..e2075b835f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2112,6 +2112,16 @@ dependencies = [ "yew", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -2197,6 +2207,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "papergrid" version = "0.10.0" @@ -2771,6 +2787,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -2787,14 +2812,14 @@ dependencies = [ "bytes", "clap", "futures 0.3.29", - "log", "reqwest", "serde", + "time", "tokio", + "tracing-subscriber", + "tracing-web", "uuid", "warp", - "wasm-bindgen-futures", - "wasm-logger", "yew", ] @@ -3033,6 +3058,16 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.3.30" @@ -3040,6 +3075,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", + "js-sys", "powerfmt", "serde", "time-core", @@ -3274,6 +3310,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tracing-web" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e6a141feebd51f8d91ebfd785af50fca223c570b86852166caa3b141defe7c" +dependencies = [ + "js-sys", + "tracing-core", + "tracing-subscriber", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -3410,6 +3485,12 @@ dependencies = [ "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/packages/yew/src/callback.rs b/packages/yew/src/callback.rs index 1ba61d9de74..6860e5cd50f 100644 --- a/packages/yew/src/callback.rs +++ b/packages/yew/src/callback.rs @@ -25,7 +25,9 @@ macro_rules! generate_callback_impls { } } - #[allow(clippy::vtable_address_comparisons)] + // We are okay with comparisons from different compilation units to result in false + // not-equal results. This should only lead in the worst-case to some unneeded re-renders. + #[allow(ambiguous_wide_pointer_comparisons)] impl PartialEq for $callback { fn eq(&self, other: &$callback) -> bool { let ($callback { cb }, $callback { cb: rhs_cb }) = (self, other); diff --git a/packages/yew/src/dom_bundle/blist.rs b/packages/yew/src/dom_bundle/blist.rs index ddd909027ea..ab763fa11c2 100644 --- a/packages/yew/src/dom_bundle/blist.rs +++ b/packages/yew/src/dom_bundle/blist.rs @@ -11,7 +11,7 @@ use super::{test_log, BNode, BSubtree, DomSlot}; use crate::dom_bundle::{Reconcilable, ReconcileTarget}; use crate::html::AnyScope; use crate::utils::RcExt; -use crate::virtual_dom::{Key, VList, VNode, VText}; +use crate::virtual_dom::{Key, VList, VNode}; /// This struct represents a mounted [VList] #[derive(Debug)] @@ -427,15 +427,7 @@ impl Reconcilable for VList { // The left items are known since we want to insert them // (self.children). For the right ones, we will look at the bundle, // i.e. the current DOM list element that we want to replace with self. - let (key, mut fully_keyed, mut lefts) = self.split_for_blist(); - - if lefts.is_empty() { - // Without a placeholder the next element becomes first - // and corrupts the order of rendering - // We use empty text element to stake out a place - lefts.push(VText::new("").into()); - fully_keyed = false; - } + let (key, fully_keyed, lefts) = self.split_for_blist(); let rights = &mut blist.rev_children; test_log!("lefts: {:?}", lefts); diff --git a/packages/yew/src/dom_bundle/utils.rs b/packages/yew/src/dom_bundle/utils.rs index b877da9002d..f4227fd13a7 100644 --- a/packages/yew/src/dom_bundle/utils.rs +++ b/packages/yew/src/dom_bundle/utils.rs @@ -50,6 +50,10 @@ mod feat_hydration { #[cfg(feature = "hydration")] pub(super) use feat_hydration::*; +#[cfg(test)] +// this is needed because clippy doesn't like the import not being used +#[allow(unused_imports)] +pub(super) use tests::*; #[cfg(test)] mod tests { @@ -87,8 +91,3 @@ mod tests { (root, scope, parent, sibling) } } - -#[cfg(test)] -// this is needed because clippy doesn't like the import not being used -#[allow(unused_imports)] -pub(super) use tests::*; diff --git a/packages/yew/src/functional/hooks/use_reducer.rs b/packages/yew/src/functional/hooks/use_reducer.rs index 63c69e1a5d6..03280f98268 100644 --- a/packages/yew/src/functional/hooks/use_reducer.rs +++ b/packages/yew/src/functional/hooks/use_reducer.rs @@ -130,7 +130,10 @@ where T: Reducible, { fn eq(&self, rhs: &Self) -> bool { - #[allow(clippy::vtable_address_comparisons)] + // We are okay with comparisons from different compilation units to result in false + // not-equal results. This should only lead in the worst-case to some unneeded + // re-renders. + #[allow(ambiguous_wide_pointer_comparisons)] Rc::ptr_eq(&self.dispatch, &rhs.dispatch) } } diff --git a/packages/yew/src/html/component/lifecycle.rs b/packages/yew/src/html/component/lifecycle.rs index ad5ee160965..c86e4349e22 100644 --- a/packages/yew/src/html/component/lifecycle.rs +++ b/packages/yew/src/html/component/lifecycle.rs @@ -430,7 +430,9 @@ impl ComponentState { fields(component.id = self.comp_id) )] fn render(&mut self, shared_state: &Shared>) { - match self.inner.view() { + let view = self.inner.view(); + tracing::trace!(?view, "render result"); + match view { Ok(vnode) => self.commit_render(shared_state, vnode), Err(RenderError::Suspended(susp)) => self.suspend(shared_state, susp), }; diff --git a/packages/yew/src/html/component/scope.rs b/packages/yew/src/html/component/scope.rs index 2ad0c47950e..9253228fa2e 100644 --- a/packages/yew/src/html/component/scope.rs +++ b/packages/yew/src/html/component/scope.rs @@ -642,7 +642,7 @@ mod feat_hydration { use web_sys::{Element, HtmlScriptElement}; use super::*; - use crate::dom_bundle::{BSubtree, DomSlot, DynamicDomSlot, Fragment}; + use crate::dom_bundle::{BSubtree, DynamicDomSlot, Fragment}; use crate::html::component::lifecycle::{ComponentRenderState, CreateRunner, RenderRunner}; use crate::scheduler; use crate::virtual_dom::Collectable; @@ -679,12 +679,6 @@ mod feat_hydration { let collectable = Collectable::for_component::(); let mut fragment = Fragment::collect_between(fragment, &collectable, &parent); - let next_sibling = if let Some(n) = fragment.front() { - Some(n.clone()) - } else { - fragment.sibling_at_end().cloned() - }; - internal_ref.reassign(DomSlot::create(next_sibling)); let prepared_state = match fragment .back() diff --git a/packages/yew/src/suspense/suspension.rs b/packages/yew/src/suspense/suspension.rs index 23663f974ff..ac50f7885e0 100644 --- a/packages/yew/src/suspense/suspension.rs +++ b/packages/yew/src/suspense/suspension.rs @@ -105,7 +105,7 @@ impl Future for Suspension { let waker = cx.waker().clone(); self.listen(Callback::from(move |_| { - waker.clone().wake(); + waker.wake_by_ref(); })); Poll::Pending diff --git a/packages/yew/src/virtual_dom/listeners.rs b/packages/yew/src/virtual_dom/listeners.rs index f96dead2f39..87774ad3ebb 100644 --- a/packages/yew/src/virtual_dom/listeners.rs +++ b/packages/yew/src/virtual_dom/listeners.rs @@ -187,9 +187,11 @@ impl PartialEq for Listeners { lhs.iter() .zip(rhs.iter()) .all(|(lhs, rhs)| match (lhs, rhs) { - (Some(lhs), Some(rhs)) => - { - #[allow(clippy::vtable_address_comparisons)] + (Some(lhs), Some(rhs)) => { + // We are okay with comparisons from different compilation units to + // result in false not-equal results. This should only lead in the + // worst-case to some unneeded re-renders. + #[allow(ambiguous_wide_pointer_comparisons)] Rc::ptr_eq(lhs, rhs) } (None, None) => true, From e9739fc9ce4944ba93c77a32072551ab771a2cda Mon Sep 17 00:00:00 2001 From: Michael Meyer Date: Thu, 14 Mar 2024 12:24:20 +0100 Subject: [PATCH 7/7] Add generic type hints to boxed hooks (#3633) When using complex type constructs in a boxed hook, the compiler could get confused and request a type hint on the call to the inner function. This adds all generic types of the outer hook function as explicit arguments to the call of the inner function. * Add generic types to boxed hooks * Create failing test --------- Co-authored-by: Michael Meyer --- packages/yew-macro/src/hook/mod.rs | 4 +++- .../tests/hook_attr/hook-trait-item-pass.rs | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 packages/yew-macro/tests/hook_attr/hook-trait-item-pass.rs diff --git a/packages/yew-macro/src/hook/mod.rs b/packages/yew-macro/src/hook/mod.rs index f22fd4f722e..a60ecbd551d 100644 --- a/packages/yew-macro/src/hook/mod.rs +++ b/packages/yew-macro/src/hook/mod.rs @@ -144,11 +144,13 @@ pub fn hook_impl(hook: HookFn) -> syn::Result { let as_boxed_fn = with_output.then(|| quote! { as #boxed_fn_type }); + let generic_types = generics.type_params().map(|t| &t.ident); + // We need boxing implementation for `impl Trait` arguments. quote! { let #boxed_inner_ident = ::std::boxed::Box::new( move |#ctx_ident: &mut ::yew::functional::HookContext| #inner_fn_rt { - #inner_fn_ident (#ctx_ident, #(#input_args,)*) + #inner_fn_ident :: <#(#generic_types,)*> (#ctx_ident, #(#input_args,)*) } ) #as_boxed_fn; diff --git a/packages/yew-macro/tests/hook_attr/hook-trait-item-pass.rs b/packages/yew-macro/tests/hook_attr/hook-trait-item-pass.rs new file mode 100644 index 00000000000..7fc8ae6dcc8 --- /dev/null +++ b/packages/yew-macro/tests/hook_attr/hook-trait-item-pass.rs @@ -0,0 +1,22 @@ +use std::marker::PhantomData; + +pub struct QueryState { + p: PhantomData +} + +pub trait MyTrait { + type Associated; +} + + +#[yew::hook] +pub fn use_query_state( + selector: impl yew::html::IntoPropValue, +) -> QueryState +where + Props: MyTrait, +{ + QueryState:: { p: PhantomData:: } +} + +fn main() {} \ No newline at end of file