move diffing into the global runtime

This commit is contained in:
Evan Almloff committed 2024-01-05 09:32:50 -06:00
1 parent f42ef3ef9d
commit c70e2bfcb6
8 files changed
+152 -210

No files matched your search

+14 -81
View File
@@ -1,7 +1,7 @@
use crate::{
any_props::AnyProps,
any_props::VProps,
innerlude::{DynamicNode, EventHandler, VComponent, VNodeId, VText},
innerlude::{DynamicNode, EventHandler, VComponent, VText},
nodes::{IntoAttributeValue, IntoDynNode, RenderReturn},
runtime::Runtime,
scope_context::ScopeContext,
@@ -9,7 +9,7 @@ use crate::{
};
use std::{
any::Any,
cell::{Cell, Ref, RefCell, UnsafeCell},
cell::{Ref, RefCell},
fmt::{Arguments, Debug},
future::Future,
rc::Rc,
@@ -47,16 +47,9 @@ pub struct ScopeState {
pub(crate) runtime: Rc<Runtime>,
pub(crate) context_id: ScopeId,
pub(crate) render_cnt: Cell<usize>,
pub(crate) last_rendered_node: Option<RenderReturn>,
pub(crate) hooks: RefCell<Vec<Box<UnsafeCell<dyn Any>>>>,
pub(crate) hook_idx: Cell<usize>,
pub(crate) borrowed_props: RefCell<Vec<*const VComponent>>,
pub(crate) element_refs_to_drop: RefCell<Vec<VNodeId>>,
pub(crate) attributes_to_drop_before_render: RefCell<Vec<*const Attribute>>,
pub(crate) props: Option<Box<dyn AnyProps>>,
pub(crate) props: Box<dyn AnyProps>,
}
impl Drop for ScopeState {
@@ -75,13 +68,6 @@ impl<'src> ScopeState {
self.context().name
}
/// Get the current render since the inception of this component
///
/// This can be used as a helpful diagnostic when debugging hooks/renders, etc
pub fn generation(&self) -> usize {
self.render_cnt.get()
}
/// Get a handle to the currently active head node arena for this Scope
///
/// This is useful for traversing the tree outside of the VirtualDom, such as in a custom renderer or in SSR.
@@ -98,15 +84,7 @@ impl<'src> ScopeState {
///
/// Returns [`None`] if the tree has not been built yet.
pub fn try_root_node(&self) -> Option<&RenderReturn> {
let ptr = self.current_frame().node.get();
if ptr.is_null() {
return None;
}
let r: &RenderReturn = unsafe { &*ptr };
unsafe { std::mem::transmute(r) }
self.last_rendered_node.as_ref()
}
/// Get the height of this Scope - IE the number of scopes above it.
@@ -354,21 +332,19 @@ impl<'src> ScopeState {
&'src self,
mut callback: impl FnMut(Event<T>) + 'src,
) -> AttributeValue {
AttributeValue::Listener(RefCell::new(Some(Box::new(
move |event: Event<dyn Any>| {
if let Ok(data) = event.data.downcast::<T>() {
callback(Event {
propagates: event.propagates,
data,
});
}
},
))))
AttributeValue::Listener(Box::new(move |event: Event<dyn Any>| {
if let Ok(data) = event.data.downcast::<T>() {
callback(Event {
propagates: event.propagates,
data,
});
}
}))
}
/// Create a new [`AttributeValue`] with a value that implements [`AnyValue`]
pub fn any_value<T: AnyValue>(&'src self, value: T) -> AttributeValue {
AttributeValue::Any(RefCell::new(Some(Box::new(value))))
AttributeValue::Any(Box::new(value))
}
/// Mark this component as suspended and then return None
@@ -377,47 +353,4 @@ impl<'src> ScopeState {
cx.suspend();
None
}
/// Store a value between renders. The foundational hook for all other hooks.
///
/// Accepts an `initializer` closure, which is run on the first use of the hook (typically the initial render). The return value of this closure is stored for the lifetime of the component, and a mutable reference to it is provided on every render as the return value of `use_hook`.
///
/// When the component is unmounted (removed from the UI), the value is dropped. This means you can return a custom type and provide cleanup code by implementing the [`Drop`] trait
///
/// # Example
///
/// ```
/// use dioxus_core::ScopeState;
///
/// // prints a greeting on the initial render
/// pub fn use_hello_world(cx: &ScopeState) {
/// cx.use_hook(|| println!("Hello, world!"));
/// }
/// ```
#[allow(clippy::mut_from_ref)]
pub fn use_hook<State: 'static>(&self, initializer: impl FnOnce() -> State) -> &mut State {
let cur_hook = self.hook_idx.get();
let mut hooks = self.hooks.try_borrow_mut().expect("The hook list is already borrowed: This error is likely caused by trying to use a hook inside a hook which violates the rules of hooks.");
if cur_hook >= hooks.len() {
hooks.push(Box::new(UnsafeCell::new(initializer())));
}
hooks
.get(cur_hook)
.and_then(|inn| {
self.hook_idx.set(cur_hook + 1);
let raw_ref = unsafe { &mut *inn.get() };
raw_ref.downcast_mut::<State>()
})
.expect(
r#"
Unable to retrieve the hook that was initialized at this index.
Consult the `rules of hooks` to understand how to use hooks properly.
You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
Functions prefixed with "use" should never be called conditionally.
"#,
)
}
}