fix: get rollover working

This commit is contained in:
Jonathan Kelley 2022-12-13 14:44:47 -08:00
parent 79e786aca5
commit 5c20e651da
7 changed files with 61 additions and 25 deletions

View file

@ -57,6 +57,7 @@ reqwest = { version = "0.11.9", features = ["json"] }
fern = { version = "0.6.0", features = ["colored"] }
thiserror = "1.0.30"
env_logger = "0.9.0"
simple_logger = "4.0.0"
[profile.release]
opt-level = 3

View file

@ -20,6 +20,9 @@ fn app(cx: Scope) -> Element {
Link { to: "/blog", li { "blog" } }
Link { to: "/blog/tim", li { "tims' blog" } }
Link { to: "/blog/bill", li { "bills' blog" } }
Link { to: "/blog/james",
li { "james amazing' blog" }
}
Link { to: "/apples", li { "go to apples" } }
}
Route { to: "/", Home {} }
@ -42,11 +45,17 @@ fn BlogList(cx: Scope) -> Element {
}
fn BlogPost(cx: Scope) -> Element {
let Some(id) = use_route(cx).segment("id") else {
return cx.render(rsx! { div { "No blog post id" } })
};
log::debug!("rendering blog post {}", id);
cx.render(rsx! { div { "{id:?}" } })
cx.render(rsx! {
div {
h3 { "blog post: {id:?}" }
Link { to: "/blog/", "back to blog list" }
}
})
}

View file

@ -36,6 +36,7 @@ serde = { version = "1", features = ["derive"], optional = true }
anyhow = "1.0.66"
smallbox = "0.8.1"
log = "0.4.17"
[dev-dependencies]
tokio = { version = "*", features = ["full"] }

View file

@ -108,9 +108,10 @@ impl VirtualDom {
});
for root in node.root_ids {
let id = root.get().unwrap();
if id.0 != 0 {
self.try_reclaim(id);
if let Some(id) = root.get() {
if id.0 != 0 {
self.try_reclaim(id);
}
}
}
}
@ -131,7 +132,9 @@ impl VirtualDom {
node.dynamic_nodes.iter().for_each(|child| match child {
// Only descend if the props are borrowed
DynamicNode::Component(c) if !c.static_props => {
self.ensure_drop_safety(c.scope.get().unwrap());
if let Some(scope) = c.scope.get() {
self.ensure_drop_safety(scope);
}
c.props.take();
}

View file

@ -113,7 +113,7 @@ impl<'b> VirtualDom {
idx: usize,
) {
match (left_node, right_node) {
(Text(left), Text(right)) => self.diff_vtext(left, right),
(Text(left), Text(right)) => self.diff_vtext(left, right, node),
(Fragment(left), Fragment(right)) => self.diff_non_empty_fragment(left, right),
(Placeholder(left), Placeholder(right)) => right.id.set(left.id.get()),
(Component(left), Component(right)) => self.diff_vcomponent(left, right, node, idx),
@ -174,6 +174,10 @@ impl<'b> VirtualDom {
right_template: &'b VNode<'b>,
idx: usize,
) {
if std::ptr::eq(left, right) {
return;
}
// Replace components that have different render fns
if left.render_fn != right.render_fn {
let created = self.create_component_node(right_template, right, idx);
@ -193,7 +197,16 @@ impl<'b> VirtualDom {
}
// Make sure the new vcomponent has the right scopeid associated to it
let scope_id = left.scope.get().unwrap();
let Some(scope_id) = left.scope.get() else {
return;
};
// let scope_id = left.scope.get().unwrap_or_else(|| {
// panic!(
// "A component should always have a scope associated to it. {:?}\n {:#?}",
// right.name,
// std::backtrace::Backtrace::force_capture()
// )
// });
right.scope.set(Some(scope_id));
@ -260,21 +273,26 @@ impl<'b> VirtualDom {
/// }
/// ```
fn light_diff_templates(&mut self, left: &'b VNode<'b>, right: &'b VNode<'b>) {
match matching_components(left, right) {
None => self.replace(left, right),
Some(components) => components
.into_iter()
.enumerate()
.for_each(|(idx, (l, r))| self.diff_vcomponent(l, r, right, idx)),
}
self.replace(left, right)
// match matching_components(left, right) {
// None => self.replace(left, right),
// Some(components) => components
// .into_iter()
// .enumerate()
// .for_each(|(idx, (l, r))| self.diff_vcomponent(l, r, right, idx)),
// }
}
/// Diff the two text nodes
///
/// This just moves the ID of the old node over to the new node, and then sets the text of the new node if it's
/// different.
fn diff_vtext(&mut self, left: &'b VText<'b>, right: &'b VText<'b>) {
let id = left.id.get().unwrap();
fn diff_vtext(&mut self, left: &'b VText<'b>, right: &'b VText<'b>, node: &'b VNode<'b>) {
let id = left
.id
.get()
.unwrap_or_else(|| self.next_element(node, &[0]));
right.id.set(Some(id));
if left.value != right.value {
let value = unsafe { std::mem::transmute(right.value) };
@ -327,11 +345,12 @@ impl<'b> VirtualDom {
match dyn_node {
Component(comp) => {
let scope = comp.scope.take().unwrap();
match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
RenderReturn::Sync(Ok(t)) => self.clean_up_node(t),
_ => todo!("cannot handle nonstandard nodes"),
};
if let Some(scope) = comp.scope.take() {
match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
RenderReturn::Sync(Ok(t)) => self.clean_up_node(t),
_ => todo!("cannot handle nonstandard nodes"),
};
}
}
Text(t) => {
if let Some(id) = t.id.take() {

View file

@ -520,7 +520,6 @@ impl VirtualDom {
pin_mut!(deadline);
self.process_events();
println!("rendering with dirty scopes {:#?}", self.dirty_scopes);
loop {
// first, unload any complete suspense trees
@ -548,8 +547,6 @@ impl VirtualDom {
if let Some(dirty) = self.dirty_scopes.iter().next().cloned() {
self.dirty_scopes.remove(&dirty);
println!("diffing scope {:?}", dirty);
// if the scope is currently suspended, then we should skip it, ignoring any tasks calling for an update
if self.is_scope_suspended(dirty.id) {
continue;

View file

@ -16,6 +16,7 @@ fn app(cx: Scope) -> Element {
Link { to: "/blog", li { "blog" } }
Link { to: "/blog/tim", li { "tims' blog" } }
Link { to: "/blog/bill", li { "bills' blog" } }
Link { to: "/blog/james", li { "james amazing' blog" } }
Link { to: "/apples", li { "go to apples" } }
}
Route { to: "/", Home {} }
@ -42,5 +43,10 @@ fn BlogPost(cx: Scope) -> Element {
log::trace!("rendering blog post {}", id);
cx.render(rsx! { div { "{id:?}" } })
cx.render(rsx! {
div {
h3 { "blog post: {id:?}" }
Link { to: "/blog/", "back to blog list" }
}
})
}