From 544990a6b408109d34b6363740befacae73fd4e4 Mon Sep 17 00:00:00 2001 From: Muhammad Hamza Date: Wed, 20 Jul 2022 21:32:26 +0500 Subject: [PATCH] Remove component NodeRef (#2783) * don't attach noderef to components, add test case * remove node_ref from VNode and VComp * fmt & macro tests * remove uneeded test & todo this test is done at compile time. there's no node_ref field so it can't be set * feature soundness & clippy * add marker field, in an attempt to reduce bundle size * Update migration guide --- examples/nested_list/src/list.rs | 8 +- .../yew-macro/src/html_tree/html_component.rs | 3 +- .../tests/html_macro/component-fail.rs | 16 + .../tests/html_macro/component-fail.stderr | 342 +++++++++++------- .../tests/html_macro/component-pass.rs | 18 +- packages/yew/src/dom_bundle/bcomp.rs | 82 +---- packages/yew/src/html/conversion.rs | 2 +- packages/yew/src/html/mod.rs | 13 - packages/yew/src/virtual_dom/vcomp.rs | 23 +- packages/yew/tests/common/mod.rs | 4 + .../yew/from-0_19_0-to-0_20_0.mdx | 9 + 11 files changed, 279 insertions(+), 241 deletions(-) diff --git a/examples/nested_list/src/list.rs b/examples/nested_list/src/list.rs index 66d999cce9d..53c2101945e 100644 --- a/examples/nested_list/src/list.rs +++ b/examples/nested_list/src/list.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use yew::html::{ChildrenRenderer, NodeRef}; +use yew::html::ChildrenRenderer; use yew::prelude::*; use yew::virtual_dom::{VChild, VComp}; @@ -46,10 +46,8 @@ where impl From for Html { fn from(variant: ListVariant) -> Html { match variant.props { - Variants::Header(props) => { - VComp::new::(props, NodeRef::default(), None).into() - } - Variants::Item(props) => VComp::new::(props, NodeRef::default(), None).into(), + Variants::Header(props) => VComp::new::(props, None).into(), + Variants::Item(props) => VComp::new::(props, None).into(), } } } diff --git a/packages/yew-macro/src/html_tree/html_component.rs b/packages/yew-macro/src/html_tree/html_component.rs index 3ec0ac4ba2c..0a69eaf979b 100644 --- a/packages/yew-macro/src/html_tree/html_component.rs +++ b/packages/yew-macro/src/html_tree/html_component.rs @@ -106,7 +106,6 @@ impl ToTokens for HtmlComponent { Some(quote! { ::yew::html::ChildrenRenderer::new(#children) }) }; let build_props = props.build_properties_tokens(&props_ty, children_renderer); - let node_ref = props.special().wrap_node_ref_attr(); let key = props.special().wrap_key_attr(); let use_close_tag = close .as_ref() @@ -122,7 +121,7 @@ impl ToTokens for HtmlComponent { { #use_close_tag let __yew_props = #build_props; - ::yew::virtual_dom::VChild::<#ty>::new(__yew_props, #node_ref, #key) + ::yew::virtual_dom::VChild::<#ty>::new(__yew_props, #key) } }); } diff --git a/packages/yew-macro/tests/html_macro/component-fail.rs b/packages/yew-macro/tests/html_macro/component-fail.rs index e5c9e9985be..5da187d2f5e 100644 --- a/packages/yew-macro/tests/html_macro/component-fail.rs +++ b/packages/yew-macro/tests/html_macro/component-fail.rs @@ -65,6 +65,20 @@ fn compile_fail() { html! { }; html! { }; html! { }; + html! { }; + html! { }; + html! { }; + html! { }; + html! { }; + html! { }; + html! { }; + html! { }; + html! { }; + html! { }; + html! { }; + html! { }; + html! { }; + html! { }; html! { }; html! { }; html! { }; @@ -79,6 +93,8 @@ fn compile_fail() { html! { }; html! { }; html! { }; + html! { }; + html! { }; html! { }; html! { }; html! { }; diff --git a/packages/yew-macro/tests/html_macro/component-fail.stderr b/packages/yew-macro/tests/html_macro/component-fail.stderr index 2e068c63b21..fb02ae65600 100644 --- a/packages/yew-macro/tests/html_macro/component-fail.stderr +++ b/packages/yew-macro/tests/html_macro/component-fail.stderr @@ -148,135 +148,225 @@ error: `ref` can only be specified once 67 | html! { }; | ^^^ +error: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes) + --> tests/html_macro/component-fail.rs:68:20 + | +68 | html! { }; + | ^^^^ + error: base props expression must appear last in list of props + --> tests/html_macro/component-fail.rs:69:20 + | +69 | html! { }; + | ^^^^^^^ + +error: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes) --> tests/html_macro/component-fail.rs:70:20 | -70 | html! { }; +70 | html! { }; + | ^^^^ + +error: base props expression must appear last in list of props + --> tests/html_macro/component-fail.rs:71:20 + | +71 | html! { }; + | ^^^^^^^ + +error: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes) + --> tests/html_macro/component-fail.rs:72:20 + | +72 | html! { }; + | ^^^^ + +error: base props expression must appear last in list of props + --> tests/html_macro/component-fail.rs:73:20 + | +73 | html! { }; + | ^^^^^^^ + +error: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes) + --> tests/html_macro/component-fail.rs:74:20 + | +74 | html! { }; + | ^^^^ + +error: base props expression must appear last in list of props + --> tests/html_macro/component-fail.rs:75:20 + | +75 | html! { }; + | ^^^^^^^ + +error: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes) + --> tests/html_macro/component-fail.rs:76:28 + | +76 | html! { }; + | ^^^^ + +error: base props expression must appear last in list of props + --> tests/html_macro/component-fail.rs:77:28 + | +77 | html! { }; + | ^^^^^^^ + +error: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes) + --> tests/html_macro/component-fail.rs:78:39 + | +78 | html! { }; + | ^^^^ + +error: base props expression must appear last in list of props + --> tests/html_macro/component-fail.rs:79:39 + | +79 | html! { }; + | ^^^^^^^ + +error: `with` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes) + --> tests/html_macro/component-fail.rs:80:51 + | +80 | html! { }; + | ^^^^ + +error: `r#ref` can only be specified once but is given here again + --> tests/html_macro/component-fail.rs:81:31 + | +81 | html! { }; + | ^^^^^ + +error: base props expression must appear last in list of props + --> tests/html_macro/component-fail.rs:84:20 + | +84 | html! { }; | ^^^^^^^^ error: expected identifier, found keyword `type` - --> tests/html_macro/component-fail.rs:71:20 + --> tests/html_macro/component-fail.rs:85:20 | -71 | html! { }; +85 | html! { }; | ^^^^ expected identifier, found keyword | help: escape `type` to use it as an identifier | -71 | html! { }; +85 | html! { }; | ++ error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression. - --> tests/html_macro/component-fail.rs:72:24 + --> tests/html_macro/component-fail.rs:86:24 | -72 | html! { }; +86 | html! { }; | ^^ error: expected a valid Rust identifier - --> tests/html_macro/component-fail.rs:73:20 + --> tests/html_macro/component-fail.rs:87:20 | -73 | html! { }; +87 | html! { }; | ^^^^^^^^^^^^^^^^^ error: expected an expression following this equals sign - --> tests/html_macro/component-fail.rs:75:26 + --> tests/html_macro/component-fail.rs:89:26 | -75 | html! { }; +89 | html! { }; | ^ error: `int` can only be specified once but is given here again - --> tests/html_macro/component-fail.rs:76:26 + --> tests/html_macro/component-fail.rs:90:26 | -76 | html! { }; +90 | html! { }; | ^^^ error: `int` can only be specified once but is given here again - --> tests/html_macro/component-fail.rs:76:32 + --> tests/html_macro/component-fail.rs:90:32 | -76 | html! { }; +90 | html! { }; | ^^^ error: `ref` can only be specified once - --> tests/html_macro/component-fail.rs:81:35 + --> tests/html_macro/component-fail.rs:95:35 | -81 | html! { }; +95 | html! { }; | ^^^ -error: this closing tag has no corresponding opening tag - --> tests/html_macro/component-fail.rs:84:13 +error: `r#ref` can only be specified once but is given here again + --> tests/html_macro/component-fail.rs:97:37 | -84 | html! { }; - | ^^^^^^^^ +97 | html! { }; + | ^^^^^ + +error: this closing tag has no corresponding opening tag + --> tests/html_macro/component-fail.rs:100:13 + | +100 | html! { }; + | ^^^^^^^^ error: this opening tag has no corresponding closing tag - --> tests/html_macro/component-fail.rs:85:13 - | -85 | html! { }; - | ^^^^^^^ + --> tests/html_macro/component-fail.rs:101:13 + | +101 | html! { }; + | ^^^^^^^ error: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<>`) - --> tests/html_macro/component-fail.rs:86:28 - | -86 | html! { }; - | ^^^^^^^^^^^^^^^ + --> tests/html_macro/component-fail.rs:102:28 + | +102 | html! { }; + | ^^^^^^^^^^^^^^^ error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression. - --> tests/html_macro/component-fail.rs:90:24 - | -90 | html! { }; - | ^^^ + --> tests/html_macro/component-fail.rs:106:24 + | +106 | html! { }; + | ^^^ error: cannot specify the `children` prop when the component already has children - --> tests/html_macro/component-fail.rs:108:26 + --> tests/html_macro/component-fail.rs:124:26 | -108 | +124 | | ^^^^^^^^ error: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<>`) - --> tests/html_macro/component-fail.rs:115:9 + --> tests/html_macro/component-fail.rs:131:9 | -115 | { 2 } +131 | { 2 } | ^^^^^^^^^^^^^^^^^^ error: only simple identifiers are allowed in the shorthand property syntax - --> tests/html_macro/component-fail.rs:118:21 + --> tests/html_macro/component-fail.rs:134:21 | -118 | html! { }; +134 | html! { }; | ^^^^^^^^^^^^^^^^^^^^ error: missing label for property value. If trying to use the shorthand property syntax, only identifiers may be used - --> tests/html_macro/component-fail.rs:119:21 + --> tests/html_macro/component-fail.rs:135:21 | -119 | html! { }; +135 | html! { }; | ^^^^^ error: missing label for property value. If trying to use the shorthand property syntax, only identifiers may be used - --> tests/html_macro/component-fail.rs:120:21 + --> tests/html_macro/component-fail.rs:136:21 | -120 | html! { }; +136 | html! { }; | ^^^^^^^^^^^^^^ error: only an expression may be assigned as a property - --> tests/html_macro/component-fail.rs:131:34 + --> tests/html_macro/component-fail.rs:147:34 | -131 | html! { }; +147 | html! { }; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: only an expression may be assigned as a property. Consider removing this semicolon - --> tests/html_macro/component-fail.rs:132:61 + --> tests/html_macro/component-fail.rs:148:61 | -132 | html! { }; +148 | html! { }; | ^ error[E0425]: cannot find value `blah` in this scope - --> tests/html_macro/component-fail.rs:68:22 + --> tests/html_macro/component-fail.rs:82:22 | -68 | html! { }; +82 | html! { }; | ^^^^ not found in this scope error[E0425]: cannot find value `props` in this scope - --> tests/html_macro/component-fail.rs:69:30 + --> tests/html_macro/component-fail.rs:83:30 | -69 | html! { }; +83 | html! { }; | ^^^^^ not found in this scope error[E0308]: mismatched types @@ -291,51 +381,51 @@ error[E0308]: mismatched types found struct `std::ops::Range<_>` error[E0609]: no field `value` on type `ChildProperties` - --> tests/html_macro/component-fail.rs:69:20 + --> tests/html_macro/component-fail.rs:83:20 | -69 | html! { }; +83 | html! { }; | ^^^^^ unknown field | = note: available fields are: `string`, `int` error[E0609]: no field `r#type` on type `ChildProperties` - --> tests/html_macro/component-fail.rs:71:20 + --> tests/html_macro/component-fail.rs:85:20 | -71 | html! { }; +85 | html! { }; | ^^^^ unknown field | = note: available fields are: `string`, `int` error[E0599]: no method named `r#type` found for struct `ChildPropertiesBuilder` in the current scope - --> tests/html_macro/component-fail.rs:71:20 + --> tests/html_macro/component-fail.rs:85:20 | 4 | #[derive(Clone, Properties, PartialEq)] | ---------- method `r#type` not found for this ... -71 | html! { }; +85 | html! { }; | ^^^^ method not found in `ChildPropertiesBuilder` error[E0609]: no field `unknown` on type `ChildProperties` - --> tests/html_macro/component-fail.rs:74:20 + --> tests/html_macro/component-fail.rs:88:20 | -74 | html! { }; +88 | html! { }; | ^^^^^^^ unknown field | = note: available fields are: `string`, `int` error[E0599]: no method named `unknown` found for struct `ChildPropertiesBuilder` in the current scope - --> tests/html_macro/component-fail.rs:74:20 + --> tests/html_macro/component-fail.rs:88:20 | 4 | #[derive(Clone, Properties, PartialEq)] | ---------- method `unknown` not found for this ... -74 | html! { }; +88 | html! { }; | ^^^^^^^ method not found in `ChildPropertiesBuilder` error[E0277]: the trait bound `(): IntoPropValue` is not satisfied - --> tests/html_macro/component-fail.rs:77:33 + --> tests/html_macro/component-fail.rs:91:33 | -77 | html! { }; +91 | html! { }; | ------ ^^ the trait `IntoPropValue` is not implemented for `()` | | | required by a bound introduced by this call @@ -351,9 +441,9 @@ note: required by a bound in `ChildPropertiesBuilder::string` = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `{integer}: IntoPropValue` is not satisfied - --> tests/html_macro/component-fail.rs:78:33 + --> tests/html_macro/component-fail.rs:92:33 | -78 | html! { }; +92 | html! { }; | ------ ^ the trait `IntoPropValue` is not implemented for `{integer}` | | | required by a bound introduced by this call @@ -369,9 +459,9 @@ note: required by a bound in `ChildPropertiesBuilder::string` = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `{integer}: IntoPropValue` is not satisfied - --> tests/html_macro/component-fail.rs:79:34 + --> tests/html_macro/component-fail.rs:93:34 | -79 | html! { }; +93 | html! { }; | ------ ^ the trait `IntoPropValue` is not implemented for `{integer}` | | | required by a bound introduced by this call @@ -386,19 +476,27 @@ note: required by a bound in `ChildPropertiesBuilder::string` | ------ required by a bound in this = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `(): IntoPropValue` is not satisfied - --> tests/html_macro/component-fail.rs:80:31 +error[E0609]: no field `r#ref` on type `ChildProperties` + --> tests/html_macro/component-fail.rs:96:26 + | +96 | html! { }; + | ^^^^^ unknown field | -80 | html! { }; - | ^^ - | | - | the trait `IntoPropValue` is not implemented for `()` - | required by a bound introduced by this call + = note: available fields are: `string`, `int` + +error[E0599]: no method named `r#ref` found for struct `ChildPropertiesBuilder` in the current scope + --> tests/html_macro/component-fail.rs:96:26 + | +4 | #[derive(Clone, Properties, PartialEq)] + | ---------- method `r#ref` not found for this +... +96 | html! { }; + | ^^^^^ method not found in `ChildPropertiesBuilder` error[E0277]: the trait bound `u32: IntoPropValue` is not satisfied - --> tests/html_macro/component-fail.rs:82:24 + --> tests/html_macro/component-fail.rs:98:24 | -82 | html! { }; +98 | html! { }; | --- ^^^^ the trait `IntoPropValue` is not implemented for `u32` | | | required by a bound introduced by this call @@ -414,9 +512,9 @@ note: required by a bound in `ChildPropertiesBuilder::int` = note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `AssertAllProps: HasProp` is not satisfied - --> tests/html_macro/component-fail.rs:83:14 + --> tests/html_macro/component-fail.rs:99:14 | -83 | html! { }; +99 | html! { }; | ^^^^^ the trait `HasProp` is not implemented for `AssertAllProps` | note: required because of the requirements on the impl of `HasAllProps` for `CheckChildPropertiesAll` @@ -433,57 +531,57 @@ note: required by a bound in `yew::html::component::properties::__macro::PreBuil = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0609]: no field `children` on type `ChildProperties` - --> tests/html_macro/component-fail.rs:87:14 - | -87 | html! { { "Not allowed" } }; - | ^^^^^ unknown field - | - = note: available fields are: `string`, `int` - = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/html_macro/component-fail.rs:103:14 + | +103 | html! { { "Not allowed" } }; + | ^^^^^ unknown field + | + = note: available fields are: `string`, `int` + = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no method named `children` found for struct `ChildPropertiesBuilder` in the current scope - --> tests/html_macro/component-fail.rs:87:14 - | -4 | #[derive(Clone, Properties, PartialEq)] - | ---------- method `children` not found for this + --> tests/html_macro/component-fail.rs:103:14 + | +4 | #[derive(Clone, Properties, PartialEq)] + | ---------- method `children` not found for this ... -87 | html! { { "Not allowed" } }; - | ^^^^^ method not found in `ChildPropertiesBuilder` - | - = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) +103 | html! { { "Not allowed" } }; + | ^^^^^ method not found in `ChildPropertiesBuilder` + | + = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0609]: no field `children` on type `ChildProperties` - --> tests/html_macro/component-fail.rs:94:10 - | -94 | - | ^^^^^ unknown field - | - = note: available fields are: `string`, `int` - = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) + --> tests/html_macro/component-fail.rs:110:10 + | +110 | + | ^^^^^ unknown field + | + = note: available fields are: `string`, `int` + = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `AssertAllProps: HasProp<_ChildContainerProperties::children, _>` is not satisfied - --> tests/html_macro/component-fail.rs:99:14 - | -99 | html! { }; - | ^^^^^^^^^^^^^^ the trait `HasProp<_ChildContainerProperties::children, _>` is not implemented for `AssertAllProps` - | + --> tests/html_macro/component-fail.rs:115:14 + | +115 | html! { }; + | ^^^^^^^^^^^^^^ the trait `HasProp<_ChildContainerProperties::children, _>` is not implemented for `AssertAllProps` + | note: required because of the requirements on the impl of `HasAllProps` for `CheckChildContainerPropertiesAll` - --> tests/html_macro/component-fail.rs:24:17 - | -24 | #[derive(Clone, Properties, PartialEq)] - | ^^^^^^^^^^ - = note: required because of the requirements on the impl of `AllPropsFor` for `AssertAllProps` + --> tests/html_macro/component-fail.rs:24:17 + | +24 | #[derive(Clone, Properties, PartialEq)] + | ^^^^^^^^^^ + = note: required because of the requirements on the impl of `AllPropsFor` for `AssertAllProps` note: required by a bound in `yew::html::component::properties::__macro::PreBuild::::build` - --> $WORKSPACE/packages/yew/src/html/component/properties.rs - | - | Token: AllPropsFor, - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `yew::html::component::properties::__macro::PreBuild::::build` - = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) + --> $WORKSPACE/packages/yew/src/html/component/properties.rs + | + | Token: AllPropsFor, + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `yew::html::component::properties::__macro::PreBuild::::build` + = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `AssertAllProps: HasProp<_ChildContainerProperties::children, _>` is not satisfied - --> tests/html_macro/component-fail.rs:100:14 + --> tests/html_macro/component-fail.rs:116:14 | -100 | html! { }; +116 | html! { }; | ^^^^^^^^^^^^^^ the trait `HasProp<_ChildContainerProperties::children, _>` is not implemented for `AssertAllProps` | note: required because of the requirements on the impl of `HasAllProps` for `CheckChildContainerPropertiesAll` @@ -500,25 +598,25 @@ note: required by a bound in `yew::html::component::properties::__macro::PreBuil = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `VChild: From` is not satisfied - --> tests/html_macro/component-fail.rs:101:31 + --> tests/html_macro/component-fail.rs:117:31 | -101 | html! { { "Not allowed" } }; +117 | html! { { "Not allowed" } }; | ^^^^^^^^^^^^^ the trait `From` is not implemented for `VChild` | = note: required because of the requirements on the impl of `Into>` for `yew::virtual_dom::VText` error[E0277]: the trait bound `VChild: From` is not satisfied - --> tests/html_macro/component-fail.rs:102:29 + --> tests/html_macro/component-fail.rs:118:29 | -102 | html! { <> }; +118 | html! { <> }; | ^ the trait `From` is not implemented for `VChild` | = note: required because of the requirements on the impl of `Into>` for `VNode` error[E0277]: the trait bound `VChild: From` is not satisfied - --> tests/html_macro/component-fail.rs:103:30 + --> tests/html_macro/component-fail.rs:119:30 | -103 | html! { }; +119 | html! { }; | ^^^^^ the trait `From` is not implemented for `VChild` | = note: required because of the requirements on the impl of `Into>` for `VNode` diff --git a/packages/yew-macro/tests/html_macro/component-pass.rs b/packages/yew-macro/tests/html_macro/component-pass.rs index bc703f9a5f3..dd960dfaecf 100644 --- a/packages/yew-macro/tests/html_macro/component-pass.rs +++ b/packages/yew-macro/tests/html_macro/component-pass.rs @@ -100,6 +100,8 @@ pub struct ChildProperties { pub string: ::std::string::String, #[prop_or_default] pub r#fn: ::std::primitive::i32, + #[prop_or_default] + pub r#ref: ::yew::NodeRef, pub int: ::std::primitive::i32, #[prop_or_default] pub opt_str: ::std::option::Option<::std::string::String>, @@ -181,11 +183,11 @@ fn compile_pass() { <> - - - - ::Properties as ::std::default::Default>::default() /> - ::Properties as ::std::default::Default>::default() /> + + + + ::Properties as ::std::default::Default>::default() /> + ::Properties as ::std::default::Default>::default() /> }; @@ -227,7 +229,7 @@ fn compile_pass() { let node_ref = <::yew::NodeRef as ::std::default::Default>::default(); ::yew::html! { <> - + }; @@ -235,7 +237,7 @@ fn compile_pass() { let node_ref = <::yew::NodeRef as ::std::default::Default>::default(); ::yew::html! { <> - + }; @@ -332,12 +334,10 @@ fn compile_pass() { ::std::vec![ ChildrenVariants::Child(::yew::virtual_dom::VChild::new( ::default(), - <::yew::NodeRef as ::std::default::Default>::default(), ::std::option::Option::None, )), ChildrenVariants::AltChild(::yew::virtual_dom::VChild::new( (), - <::yew::NodeRef as ::std::default::Default>::default(), ::std::option::Option::None )), ] diff --git a/packages/yew/src/dom_bundle/bcomp.rs b/packages/yew/src/dom_bundle/bcomp.rs index 8edce7d21a0..608bcf15076 100644 --- a/packages/yew/src/dom_bundle/bcomp.rs +++ b/packages/yew/src/dom_bundle/bcomp.rs @@ -18,9 +18,6 @@ pub(super) struct BComp { // A internal NodeRef passed around to track this components position. This // is "stable", i.e. does not change when reconciled. internal_ref: NodeRef, - // The user-passed NodeRef from VComp. Might change every time we reconcile. - // Gets linked to the internal ref - node_ref: NodeRef, key: Option, } @@ -64,11 +61,10 @@ impl Reconcilable for VComp { let VComp { type_id, mountable, - node_ref, key, + .. } = self; let internal_ref = NodeRef::default(); - node_ref.link(internal_ref.clone()); let scope = mountable.mount( root, @@ -82,7 +78,6 @@ impl Reconcilable for VComp { internal_ref.clone(), BComp { type_id, - node_ref, internal_ref, key, scope, @@ -117,16 +112,9 @@ impl Reconcilable for VComp { next_sibling: NodeRef, bcomp: &mut Self::Bundle, ) -> NodeRef { - let VComp { - mountable, - node_ref, - key, - type_id: _, - } = self; + let VComp { mountable, key, .. } = self; bcomp.key = key; - let old_ref = std::mem::replace(&mut bcomp.node_ref, node_ref); - bcomp.node_ref.reuse(old_ref); mountable.reuse(bcomp.scope.borrow(), next_sibling); bcomp.internal_ref.clone() } @@ -148,11 +136,10 @@ mod feat_hydration { let VComp { type_id, mountable, - node_ref, key, + .. } = self; let internal_ref = NodeRef::default(); - node_ref.link(internal_ref.clone()); let scoped = mountable.hydrate( root.clone(), @@ -167,7 +154,6 @@ mod feat_hydration { BComp { type_id, scope: scoped, - node_ref, internal_ref, key, }, @@ -282,31 +268,6 @@ mod tests { check_key(html! { }); } - #[test] - fn set_component_node_ref() { - let test_node: Node = document().create_text_node("test").into(); - let test_node_ref = NodeRef::new(test_node); - let check_node_ref = |vnode: VNode| { - let vcomp = match vnode { - VNode::VComp(vcomp) => vcomp, - _ => unreachable!("should be a vcomp"), - }; - assert_eq!(vcomp.node_ref, test_node_ref); - }; - - let props = Props { - field_1: 1, - field_2: 1, - }; - let props_2 = props.clone(); - - check_node_ref(html! { }); - check_node_ref(html! { }); - check_node_ref(html! { }); - check_node_ref(html! { }); - check_node_ref(html! { }); - } - #[test] fn vchild_partialeq() { let vchild1: VChild = VChild::new( @@ -314,7 +275,6 @@ mod tests { field_1: 1, field_2: 1, }, - NodeRef::default(), None, ); @@ -323,7 +283,6 @@ mod tests { field_1: 1, field_2: 1, }, - NodeRef::default(), None, ); @@ -332,7 +291,6 @@ mod tests { field_1: 2, field_2: 2, }, - NodeRef::default(), None, ); @@ -439,45 +397,17 @@ mod tests { } #[test] - fn reset_node_ref() { + fn component_node_ref_stays_none() { let (root, scope, parent) = setup_parent(); let node_ref = NodeRef::default(); let elem = html! { }; let (_, elem) = elem.attach(&root, &scope, &parent, NodeRef::default()); scheduler::start_now(); - let parent_node = parent.deref(); - assert_eq!(node_ref.get(), parent_node.first_child()); + assert!(node_ref.get().is_none(), "components don't have node refs"); elem.detach(&root, &parent, false); scheduler::start_now(); - assert!(node_ref.get().is_none()); - } - - #[test] - fn reset_ancestors_node_ref() { - let (root, scope, parent) = setup_parent(); - - let mut bundle = Bundle::new(); - let node_ref_a = NodeRef::default(); - let node_ref_b = NodeRef::default(); - let elem = html! { }; - let node_a = bundle.reconcile(&root, &scope, &parent, NodeRef::default(), elem); - scheduler::start_now(); - let node_a = node_a.get().unwrap(); - - assert!(node_ref_a.get().is_some(), "node_ref_a should be bound"); - - let elem = html! { }; - let node_b = bundle.reconcile(&root, &scope, &parent, NodeRef::default(), elem); - scheduler::start_now(); - let node_b = node_b.get().unwrap(); - - assert_eq!(node_a, node_b, "Comp should have reused the element"); - assert!(node_ref_b.get().is_some(), "node_ref_b should be bound"); - assert!( - node_ref_a.get().is_none(), - "node_ref_a should have been reset when the element was reused." - ); + assert!(node_ref.get().is_none(), "components don't have node refs"); } } diff --git a/packages/yew/src/html/conversion.rs b/packages/yew/src/html/conversion.rs index 465f0d58563..348c3400f53 100644 --- a/packages/yew/src/html/conversion.rs +++ b/packages/yew/src/html/conversion.rs @@ -318,7 +318,7 @@ mod test { } } - let header = VChild::new((), NodeRef::default(), None); + let header = VChild::new((), None); let footer = html_nested! { }; let children = html! {
{"main"}
}; diff --git a/packages/yew/src/html/mod.rs b/packages/yew/src/html/mod.rs index a0a4f8698f6..68c4f63c5a5 100644 --- a/packages/yew/src/html/mod.rs +++ b/packages/yew/src/html/mod.rs @@ -138,19 +138,6 @@ mod feat_csr { use super::*; impl NodeRef { - /// Reuse an existing `NodeRef` - pub(crate) fn reuse(&self, node_ref: Self) { - // Avoid circular references - if self == &node_ref { - return; - } - - let mut this = self.0.borrow_mut(); - let mut existing = node_ref.0.borrow_mut(); - this.node = existing.node.take(); - this.link = existing.link.take(); - } - /// Link a downstream `NodeRef` pub(crate) fn link(&self, node_ref: Self) { // Avoid circular references diff --git a/packages/yew/src/virtual_dom/vcomp.rs b/packages/yew/src/virtual_dom/vcomp.rs index 55a5603bd88..02f96beb414 100644 --- a/packages/yew/src/virtual_dom/vcomp.rs +++ b/packages/yew/src/virtual_dom/vcomp.rs @@ -14,11 +14,11 @@ use super::Key; use crate::dom_bundle::BSubtree; #[cfg(feature = "hydration")] use crate::dom_bundle::Fragment; -#[cfg(feature = "csr")] -use crate::html::Scoped; +use crate::html::BaseComponent; #[cfg(any(feature = "ssr", feature = "csr"))] use crate::html::{AnyScope, Scope}; -use crate::html::{BaseComponent, NodeRef}; +#[cfg(feature = "csr")] +use crate::html::{NodeRef, Scoped}; #[cfg(feature = "ssr")] use crate::platform::io::BufWriter; @@ -26,15 +26,15 @@ use crate::platform::io::BufWriter; pub struct VComp { pub(crate) type_id: TypeId, pub(crate) mountable: Box, - pub(crate) node_ref: NodeRef, pub(crate) key: Option, + // for some reason, this reduces the bundle size by ~2-3 KBs + _marker: u32, } impl fmt::Debug for VComp { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("VComp") .field("type_id", &self.type_id) - .field("node_ref", &self.node_ref) .field("mountable", &"..") .field("key", &self.key) .finish() @@ -46,8 +46,8 @@ impl Clone for VComp { Self { type_id: self.type_id, mountable: self.mountable.copy(), - node_ref: self.node_ref.clone(), key: self.key.clone(), + _marker: 0, } } } @@ -164,7 +164,6 @@ pub struct VChild { /// The component properties pub props: Rc, /// Reference to the mounted node - node_ref: NodeRef, key: Option, } @@ -172,7 +171,6 @@ impl Clone for VChild { fn clone(&self) -> Self { VChild { props: Rc::clone(&self.props), - node_ref: self.node_ref.clone(), key: self.key.clone(), } } @@ -192,10 +190,9 @@ where COMP: BaseComponent, { /// Creates a child component that can be accessed and modified by its parent. - pub fn new(props: COMP::Properties, node_ref: NodeRef, key: Option) -> Self { + pub fn new(props: COMP::Properties, key: Option) -> Self { Self { props: Rc::new(props), - node_ref, key, } } @@ -206,21 +203,21 @@ where COMP: BaseComponent, { fn from(vchild: VChild) -> Self { - VComp::new::(vchild.props, vchild.node_ref, vchild.key) + VComp::new::(vchild.props, vchild.key) } } impl VComp { /// Creates a new `VComp` instance. - pub fn new(props: Rc, node_ref: NodeRef, key: Option) -> Self + pub fn new(props: Rc, key: Option) -> Self where COMP: BaseComponent, { VComp { type_id: TypeId::of::(), - node_ref, mountable: Box::new(PropsWrapper::::new(props)), key, + _marker: 0, } } } diff --git a/packages/yew/tests/common/mod.rs b/packages/yew/tests/common/mod.rs index 52474e82320..0d56b773930 100644 --- a/packages/yew/tests/common/mod.rs +++ b/packages/yew/tests/common/mod.rs @@ -13,3 +13,7 @@ pub fn obtain_result_by_id(id: &str) -> String { .expect("No result found. Most likely, the application crashed and burned") .inner_html() } + +pub fn output_element() -> web_sys::Element { + gloo_utils::document().get_element_by_id("output").unwrap() +} diff --git a/website/docs/migration-guides/yew/from-0_19_0-to-0_20_0.mdx b/website/docs/migration-guides/yew/from-0_19_0-to-0_20_0.mdx index 27ec305aa7a..d0473857911 100644 --- a/website/docs/migration-guides/yew/from-0_19_0-to-0_20_0.mdx +++ b/website/docs/migration-guides/yew/from-0_19_0-to-0_20_0.mdx @@ -49,3 +49,12 @@ The reducer function can see all previous changes at the time they are run. `start_app*` has been replaced by `yew::Renderer`. You need to enable feature `render` to use `yew::Renderer`. + +## `ref` prop for Components + +Components no longer have a `ref` prop. Trying to add a node ref to a component +will result in a compile error + +Previously node ref passed to a component was bound to the first element rendered by it. +If this behavior is still desired, it is recommended to use add a `r#ref` field to the +component's properties and bind it manually