fix hydration
This commit is contained in:
1 parent
d17a04931b
commit
940108f242
6 files changed
+83
-36
No files matched your search
@@ -75,8 +75,8 @@ pub use crate::innerlude::{
|
|||||||
fc_to_builder, generation, schedule_update, schedule_update_any, use_hook, vdom_is_rendering,
|
fc_to_builder, generation, schedule_update, schedule_update_any, use_hook, vdom_is_rendering,
|
||||||
AnyValue, Attribute, AttributeValue, CapturedError, Component, DynamicNode, Element, ElementId,
|
AnyValue, Attribute, AttributeValue, CapturedError, Component, DynamicNode, Element, ElementId,
|
||||||
Event, Fragment, HasAttributes, IntoDynNode, Mutation, Mutations, NoOpMutations, Properties,
|
Event, Fragment, HasAttributes, IntoDynNode, Mutation, Mutations, NoOpMutations, Properties,
|
||||||
RenderReturn, ScopeId, Task, Template, TemplateAttribute, TemplateNode, VComponent, VNode,
|
RenderReturn, ScopeId, ScopeState, Task, Template, TemplateAttribute, TemplateNode, VComponent,
|
||||||
VNodeInner, VPlaceholder, VText, VirtualDom, WriteMutations,
|
VNode, VNodeInner, VPlaceholder, VText, VirtualDom, WriteMutations,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The purpose of this module is to alleviate imports of many common types
|
/// The purpose of this module is to alleviate imports of many common types
|
||||||
@@ -89,7 +89,7 @@ pub mod prelude {
|
|||||||
push_future, remove_future, schedule_update, schedule_update_any, spawn, spawn_forever,
|
push_future, remove_future, schedule_update, schedule_update_any, spawn, spawn_forever,
|
||||||
suspend, use_error_boundary, use_hook, AnyValue, Attribute, Component, Element,
|
suspend, use_error_boundary, use_hook, AnyValue, Attribute, Component, Element,
|
||||||
ErrorBoundary, Event, EventHandler, Fragment, HasAttributes, IntoAttributeValue,
|
ErrorBoundary, Event, EventHandler, Fragment, HasAttributes, IntoAttributeValue,
|
||||||
IntoDynNode, Properties, Runtime, RuntimeGuard, ScopeId, Task, Template, TemplateAttribute,
|
IntoDynNode, Properties, Runtime, RuntimeGuard, ScopeId, ScopeState, Task, Template,
|
||||||
TemplateNode, Throw, VNode, VNodeInner, VirtualDom,
|
TemplateAttribute, TemplateNode, Throw, VNode, VNodeInner, VirtualDom,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -234,6 +234,47 @@ impl VNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the mounted id for a dynamic node index
|
||||||
|
pub fn mounted_dynamic_node(
|
||||||
|
&self,
|
||||||
|
dynamic_node_idx: usize,
|
||||||
|
dom: &VirtualDom,
|
||||||
|
) -> Option<ElementId> {
|
||||||
|
let mount = self.mount.get().as_usize()?;
|
||||||
|
|
||||||
|
match &self.dynamic_nodes[dynamic_node_idx] {
|
||||||
|
DynamicNode::Text(_) | DynamicNode::Placeholder(_) => dom
|
||||||
|
.mounts
|
||||||
|
.get(mount)?
|
||||||
|
.mounted_dynamic_nodes
|
||||||
|
.get(dynamic_node_idx)
|
||||||
|
.map(|id| ElementId(*id)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the mounted id for a root node index
|
||||||
|
pub fn mounted_root(&self, root_idx: usize, dom: &VirtualDom) -> Option<ElementId> {
|
||||||
|
let mount = self.mount.get().as_usize()?;
|
||||||
|
|
||||||
|
dom.mounts.get(mount)?.root_ids.get(root_idx).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the mounted id for a dynamic attribute index
|
||||||
|
pub fn mounted_dynamic_attribute(
|
||||||
|
&self,
|
||||||
|
dynamic_attribute_idx: usize,
|
||||||
|
dom: &VirtualDom,
|
||||||
|
) -> Option<ElementId> {
|
||||||
|
let mount = self.mount.get().as_usize()?;
|
||||||
|
|
||||||
|
dom.mounts
|
||||||
|
.get(mount)?
|
||||||
|
.mounted_attributes
|
||||||
|
.get(dynamic_attribute_idx)
|
||||||
|
.copied()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A static layout of a UI tree that describes a set of dynamic and static nodes.
|
/// A static layout of a UI tree that describes a set of dynamic and static nodes.
|
||||||
|
|||||||
@@ -147,13 +147,13 @@ impl Runtime {
|
|||||||
/// render! { div {} }
|
/// render! { div {} }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct RuntimeGuard(Rc<Runtime>);
|
pub struct RuntimeGuard(());
|
||||||
|
|
||||||
impl RuntimeGuard {
|
impl RuntimeGuard {
|
||||||
/// Create a new runtime guard that sets the current Dioxus runtime. The runtime will be reset when the guard is dropped
|
/// Create a new runtime guard that sets the current Dioxus runtime. The runtime will be reset when the guard is dropped
|
||||||
pub fn new(runtime: Rc<Runtime>) -> Self {
|
pub fn new(runtime: Rc<Runtime>) -> Self {
|
||||||
push_runtime(runtime.clone());
|
push_runtime(runtime);
|
||||||
Self(runtime)
|
Self(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run a function with a given runtime and scope in context
|
/// Run a function with a given runtime and scope in context
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ pub fn init_eval() {
|
|||||||
/// Reprents the ssr-target's provider of evaluators.
|
/// Reprents the ssr-target's provider of evaluators.
|
||||||
pub struct SSREvalProvider;
|
pub struct SSREvalProvider;
|
||||||
impl EvalProvider for SSREvalProvider {
|
impl EvalProvider for SSREvalProvider {
|
||||||
fn new_evaluator(&self, _: String) -> Result<Rc<dyn Evaluator>, EvalError> {
|
fn new_evaluator(&self, _: String) -> Result<Box<dyn Evaluator>, EvalError> {
|
||||||
Ok(Rc::new(SSREvaluator) as Rc<dyn Evaluator + 'static>)
|
Ok(Box::new(SSREvaluator) as Box<dyn Evaluator + 'static>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ impl Evaluator for SSREvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an UnboundedReceiver to receive messages from the evaluated JavaScript.
|
/// Gets an UnboundedReceiver to receive messages from the evaluated JavaScript.
|
||||||
async fn recv(&self) -> Result<serde_json::Value, EvalError> {
|
async fn recv(&mut self) -> Result<serde_json::Value, EvalError> {
|
||||||
std::future::pending::<()>().await;
|
std::future::pending::<()>().await;
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ eval = [
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
dioxus = { workspace = true }
|
dioxus = { workspace = true }
|
||||||
wasm-bindgen-test = "0.3.29"
|
wasm-bindgen-test = "0.3.29"
|
||||||
dioxus-ssr = { workspace = true}
|
dioxus-ssr = { workspace = true, default-features = false }
|
||||||
gloo-timers = "0.2.3"
|
gloo-timers = "0.2.3"
|
||||||
gloo-dialogs = "0.1.1"
|
gloo-dialogs = "0.1.1"
|
||||||
dioxus-web = { path = ".", features = ["hydrate"] }
|
dioxus-web = { path = ".", features = ["hydrate"] }
|
||||||
|
|||||||
@@ -36,10 +36,7 @@ impl WebsysDom {
|
|||||||
ids: &mut Vec<u32>,
|
ids: &mut Vec<u32>,
|
||||||
to_mount: &mut Vec<ElementId>,
|
to_mount: &mut Vec<ElementId>,
|
||||||
) -> Result<(), RehydrationError> {
|
) -> Result<(), RehydrationError> {
|
||||||
let vnode = match scope.root_node() {
|
let vnode = scope.root_node();
|
||||||
dioxus_core::RenderReturn::Ready(ready) => ready,
|
|
||||||
_ => return Err(VNodeNotInitialized),
|
|
||||||
};
|
|
||||||
self.rehydrate_vnode(dom, vnode, ids, to_mount)
|
self.rehydrate_vnode(dom, vnode, ids, to_mount)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +54,7 @@ impl WebsysDom {
|
|||||||
root,
|
root,
|
||||||
ids,
|
ids,
|
||||||
to_mount,
|
to_mount,
|
||||||
Some(*vnode.root_ids.borrow().get(i).ok_or(VNodeNotInitialized)?),
|
Some(vnode.mounted_root(i, dom).ok_or(VNodeNotInitialized)?),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -80,9 +77,11 @@ impl WebsysDom {
|
|||||||
let mut mounted_id = root_id;
|
let mut mounted_id = root_id;
|
||||||
for attr in *attrs {
|
for attr in *attrs {
|
||||||
if let dioxus_core::TemplateAttribute::Dynamic { id } = attr {
|
if let dioxus_core::TemplateAttribute::Dynamic { id } = attr {
|
||||||
let attribute = &vnode.dynamic_attrs[*id];
|
let attributes = &*vnode.dynamic_attrs[*id];
|
||||||
let id = attribute.mounted_element();
|
let id = vnode
|
||||||
attribute.attribute_type().for_each(|attribute| {
|
.mounted_dynamic_attribute(*id, dom)
|
||||||
|
.ok_or(VNodeNotInitialized)?;
|
||||||
|
for attribute in attributes {
|
||||||
let value = &attribute.value;
|
let value = &attribute.value;
|
||||||
mounted_id = Some(id);
|
mounted_id = Some(id);
|
||||||
if let AttributeValue::Listener(_) = value {
|
if let AttributeValue::Listener(_) = value {
|
||||||
@@ -90,7 +89,7 @@ impl WebsysDom {
|
|||||||
to_mount.push(id);
|
to_mount.push(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(id) = mounted_id {
|
if let Some(id) = mounted_id {
|
||||||
@@ -102,9 +101,15 @@ impl WebsysDom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => {
|
TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => self
|
||||||
self.rehydrate_dynamic_node(dom, &vnode.dynamic_nodes[*id], ids, to_mount)?;
|
.rehydrate_dynamic_node(
|
||||||
}
|
dom,
|
||||||
|
&vnode.dynamic_nodes[*id],
|
||||||
|
*id,
|
||||||
|
vnode,
|
||||||
|
ids,
|
||||||
|
to_mount,
|
||||||
|
)?,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -114,28 +119,29 @@ impl WebsysDom {
|
|||||||
&mut self,
|
&mut self,
|
||||||
dom: &VirtualDom,
|
dom: &VirtualDom,
|
||||||
dynamic: &DynamicNode,
|
dynamic: &DynamicNode,
|
||||||
|
dynamic_node_index: usize,
|
||||||
|
vnode: &VNode,
|
||||||
ids: &mut Vec<u32>,
|
ids: &mut Vec<u32>,
|
||||||
to_mount: &mut Vec<ElementId>,
|
to_mount: &mut Vec<ElementId>,
|
||||||
) -> Result<(), RehydrationError> {
|
) -> Result<(), RehydrationError> {
|
||||||
tracing::trace!("rehydrate dynamic node: {:?}", dynamic);
|
tracing::trace!("rehydrate dynamic node: {:?}", dynamic);
|
||||||
match dynamic {
|
match dynamic {
|
||||||
dioxus_core::DynamicNode::Text(text) => {
|
dioxus_core::DynamicNode::Text(_) | dioxus_core::DynamicNode::Placeholder(_) => {
|
||||||
ids.push(text.mounted_element().ok_or(VNodeNotInitialized)?.0 as u32);
|
ids.push(
|
||||||
}
|
vnode
|
||||||
dioxus_core::DynamicNode::Placeholder(placeholder) => {
|
.mounted_dynamic_node(dynamic_node_index, dom)
|
||||||
ids.push(placeholder.mounted_element().ok_or(VNodeNotInitialized)?.0 as u32);
|
.ok_or(VNodeNotInitialized)?
|
||||||
|
.0 as u32,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
dioxus_core::DynamicNode::Component(comp) => {
|
dioxus_core::DynamicNode::Component(comp) => {
|
||||||
let scope = comp.mounted_scope().ok_or(VNodeNotInitialized)?;
|
let scope = comp
|
||||||
self.rehydrate_scope(
|
.mounted_scope(dynamic_node_index, vnode, dom)
|
||||||
dom.get_scope(scope).ok_or(VNodeNotInitialized)?,
|
.ok_or(VNodeNotInitialized)?;
|
||||||
dom,
|
self.rehydrate_scope(scope, dom, ids, to_mount)?;
|
||||||
ids,
|
|
||||||
to_mount,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
dioxus_core::DynamicNode::Fragment(fragment) => {
|
dioxus_core::DynamicNode::Fragment(fragment) => {
|
||||||
for vnode in *fragment {
|
for vnode in fragment {
|
||||||
self.rehydrate_vnode(dom, vnode, ids, to_mount)?;
|
self.rehydrate_vnode(dom, vnode, ids, to_mount)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user