Skip to content

Commit ae2ebc9

Browse files
author
mc1098
authored
Add safe first_node fn (#2094)
`first_node` function can fail and in some situations, when the VNode has not been mounted yet, so this adds a safe version that returns an `Option<Node>` and refactors the previous version to use the "unchecked" prefix as it can and should panic if the first node cannot be found.
1 parent 78bb994 commit ae2ebc9

File tree

3 files changed

+24
-5
lines changed

3 files changed

+24
-5
lines changed

packages/yew/src/virtual_dom/vcomp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ mod tests {
391391
let test_node: Node = document().create_text_node("test").into();
392392
let test_node_ref = NodeRef::new(test_node);
393393
let check_node_ref = |vnode: VNode| {
394-
assert_eq!(vnode.first_node(), test_node_ref.get().unwrap());
394+
assert_eq!(vnode.unchecked_first_node(), test_node_ref.get().unwrap());
395395
};
396396

397397
let props = Props {

packages/yew/src/virtual_dom/vnode.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use gloo::console;
66
use std::cmp::PartialEq;
77
use std::fmt;
88
use std::iter::FromIterator;
9+
use wasm_bindgen::JsCast;
910

1011
use web_sys::{Element, Node};
1112

@@ -45,8 +46,23 @@ impl VNode {
4546
}
4647
}
4748

49+
/// Returns the first DOM node if available
50+
pub(crate) fn first_node(&self) -> Option<Node> {
51+
match self {
52+
VNode::VTag(vtag) => vtag.reference().cloned().map(JsCast::unchecked_into),
53+
VNode::VText(vtext) => vtext
54+
.reference
55+
.as_ref()
56+
.cloned()
57+
.map(JsCast::unchecked_into),
58+
VNode::VComp(vcomp) => vcomp.node_ref.get(),
59+
VNode::VList(vlist) => vlist.get(0).and_then(VNode::first_node),
60+
VNode::VRef(node) => Some(node.clone()),
61+
}
62+
}
63+
4864
/// Returns the first DOM node that is used to designate the position of the virtual DOM node.
49-
pub(crate) fn first_node(&self) -> Node {
65+
pub(crate) fn unchecked_first_node(&self) -> Node {
5066
match self {
5167
VNode::VTag(vtag) => vtag
5268
.reference()
@@ -67,7 +83,10 @@ impl VNode {
6783
crate::virtual_dom::vcomp::get_event_log(vcomp.id),
6884
);
6985
}),
70-
VNode::VList(vlist) => vlist.get(0).expect("VList is not mounted").first_node(),
86+
VNode::VList(vlist) => vlist
87+
.get(0)
88+
.expect("VList is not mounted")
89+
.unchecked_first_node(),
7190
VNode::VRef(node) => node.clone(),
7291
}
7392
}
@@ -85,7 +104,7 @@ impl VNode {
85104
.expect("VComp has no root vnode")
86105
.move_before(parent, next_sibling);
87106
}
88-
_ => super::insert_node(&self.first_node(), parent, next_sibling.as_ref()),
107+
_ => super::insert_node(&self.unchecked_first_node(), parent, next_sibling.as_ref()),
89108
};
90109
}
91110
}

packages/yew/src/virtual_dom/vtag.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ impl VDiff for VTag {
521521
}
522522
} else {
523523
let el = self.create_element(parent);
524-
super::insert_node(&el, parent, Some(&ancestor.first_node()));
524+
super::insert_node(&el, parent, ancestor.first_node().as_ref());
525525
ancestor.detach(parent);
526526
(None, el)
527527
}

0 commit comments

Comments
 (0)