wip: remove runner on hook and then update docs

This commit is contained in:
Jonathan Kelley committed 2022-01-02 02:15:04 -05:00
1 parent 7d41a16208
commit d1560450ba
95 files changed
+1339 -675

No files matched your search

+12 -19
View File
@@ -473,9 +473,16 @@ impl<'bump> DiffState<'bump> {
// Check the most common cases first
// these are *actual* elements, not wrappers around lists
(Text(old), Text(new)) => {
self.diff_text_nodes(old, new, old_node, new_node);
if let Some(root) = old.id.get() {
if old.text != new.text {
self.mutations.set_text(new.text, root.as_u64());
}
self.scopes.update_node(new_node, root);
new.id.set(Some(root));
}
}
(Element(old), Element(new)) => self.diff_element_nodes(old, new, old_node, new_node),
(Placeholder(old), Placeholder(new)) => {
if let Some(root) = old.id.get() {
self.scopes.update_node(new_node, root);
@@ -483,10 +490,13 @@ impl<'bump> DiffState<'bump> {
}
}
(Element(old), Element(new)) => self.diff_element_nodes(old, new, old_node, new_node),
// These two sets are pointers to nodes but are not actually nodes themselves
(Component(old), Component(new)) => {
self.diff_component_nodes(old_node, new_node, *old, *new)
}
(Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new),
// The normal pathway still works, but generates slightly weird instructions
@@ -506,23 +516,6 @@ impl<'bump> DiffState<'bump> {
}
}
fn diff_text_nodes(
&mut self,
old: &'bump VText<'bump>,
new: &'bump VText<'bump>,
_old_node: &'bump VNode<'bump>,
new_node: &'bump VNode<'bump>,
) {
if let Some(root) = old.id.get() {
if old.text != new.text {
self.mutations.set_text(new.text, root.as_u64());
}
self.scopes.update_node(new_node, root);
new.id.set(Some(root));
}
}
fn diff_element_nodes(
&mut self,
old: &'bump VElement<'bump>,
+4 -4
View File
@@ -65,10 +65,10 @@ pub(crate) mod innerlude {
}
pub use crate::innerlude::{
Attribute, Component, DioxusElement, DomEdit, Element, ElementId, EventHandler, EventPriority,
IntoVNode, LazyNodes, Listener, Mutations, NodeFactory, Properties, SchedulerMsg, Scope,
ScopeId, ScopeState, TaskId, UserEvent, VComponent, VElement, VFragment, VNode, VPlaceholder,
VText, VirtualDom,
Attribute, Component, DioxusElement, DomEdit, Element, ElementId, ElementIdIterator, Event,
EventHandler, EventPriority, IntoVNode, LazyNodes, Listener, Mutations, NodeFactory,
Properties, SchedulerMsg, Scope, ScopeId, ScopeState, TaskId, UserEvent, VComponent, VElement,
VFragment, VNode, VPlaceholder, VText, VirtualDom,
};
pub mod prelude {
+18 -12
View File
@@ -320,6 +320,18 @@ impl ScopeArena {
pub fn root_node(&self, id: ScopeId) -> &VNode {
self.fin_head(id)
}
// this is totally okay since all our nodes are always in a valid state
pub fn get_element(&self, id: ElementId) -> Option<&VNode> {
let ptr = self.nodes.borrow().get(id.0).cloned();
match ptr {
Some(ptr) => {
let node = unsafe { &*ptr };
Some(unsafe { extend_vnode(node) })
}
None => None,
}
}
}
/// Components in Dioxus use the "Context" object to interact with their lifecycle.
@@ -620,7 +632,7 @@ impl ScopeState {
/// struct SharedState(&'static str);
///
/// static App: Component = |cx| {
/// cx.use_hook(|_| cx.provide_context(SharedState("world")), |_| {}, |_| {});
/// cx.use_hook(|_| cx.provide_context(SharedState("world")));
/// rsx!(cx, Child {})
/// }
///
@@ -711,17 +723,13 @@ impl ScopeState {
/// ```ignore
/// // use_ref is the simplest way of storing a value between renders
/// fn use_ref<T: 'static>(initial_value: impl FnOnce() -> T) -> &RefCell<T> {
/// use_hook(
/// || Rc::new(RefCell::new(initial_value())),
/// |state| state,
/// )
/// use_hook(|| Rc::new(RefCell::new(initial_value())))
/// }
/// ```
pub fn use_hook<'src, State: 'static, Output: 'src>(
pub fn use_hook<'src, State: 'static>(
&'src self,
initializer: impl FnOnce(usize) -> State,
runner: impl FnOnce(&'src mut State) -> Output,
) -> Output {
) -> &'src mut State {
let mut vals = self.hook_vals.borrow_mut();
let hook_len = vals.len();
@@ -731,7 +739,7 @@ impl ScopeState {
vals.push(self.hook_arena.alloc(initializer(hook_len)));
}
let state = vals
vals
.get(cur_idx)
.and_then(|inn| {
self.hook_idx.set(cur_idx + 1);
@@ -746,9 +754,7 @@ impl ScopeState {
You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
Functions prefixed with "use" should never be called conditionally.
"###,
);
runner(state)
)
}
/// The "work in progress frame" represents the frame that is currently being worked on.
+104
View File
@@ -260,6 +260,10 @@ impl VirtualDom {
self.channel.0.clone()
}
pub fn get_element(&self, id: ElementId) -> Option<&VNode> {
self.scopes.get_element(id)
}
/// Add a new message to the scheduler queue directly.
///
///
@@ -1003,3 +1007,103 @@ impl EmptyBuilder {
pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element) -> T::Builder {
T::builder()
}
pub struct Event<T> {
data: Arc<T>,
_cancel: std::rc::Rc<std::cell::Cell<bool>>,
}
impl<T> std::ops::Deref for Event<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.data.as_ref()
}
}
impl<T> Event<T> {
pub fn cancel(&self) {}
pub fn timestamp(&self) {}
pub fn triggered_element(&self) -> Option<Element> {
None
}
}
pub struct ElementIdIterator<'a> {
vdom: &'a VirtualDom,
// Heuristcally we should never bleed into 5 completely nested fragments/components
// Smallvec lets us stack allocate our little stack machine so the vast majority of cases are sane
stack: smallvec::SmallVec<[(u16, &'a VNode<'a>); 5]>,
}
impl<'a> ElementIdIterator<'a> {
pub fn new(vdom: &'a VirtualDom, node: &'a VNode<'a>) -> Self {
Self {
vdom,
stack: smallvec::smallvec![(0, node)],
}
}
}
impl<'a> Iterator for ElementIdIterator<'a> {
type Item = &'a VNode<'a>;
fn next(&mut self) -> Option<&'a VNode<'a>> {
let mut should_pop = false;
let mut returned_node = None;
let mut should_push = None;
while returned_node.is_none() {
if let Some((count, node)) = self.stack.last_mut() {
match node {
// We can only exit our looping when we get "real" nodes
VNode::Element(_) | VNode::Text(_) | VNode::Placeholder(_) => {
// We've recursed INTO an element/text
// We need to recurse *out* of it and move forward to the next
// println!("Found element! Returning it!");
should_pop = true;
returned_node = Some(&**node);
}
// If we get a fragment we push the next child
VNode::Fragment(frag) => {
let _count = *count as usize;
if _count >= frag.children.len() {
should_pop = true;
} else {
should_push = Some(&frag.children[_count]);
}
}
// For components, we load their root and push them onto the stack
VNode::Component(sc) => {
// todo!();
let scope = self.vdom.get_scope(sc.scope.get().unwrap()).unwrap();
// Simply swap the current node on the stack with the root of the component
*node = scope.root_node();
}
}
} else {
// If there's no more items on the stack, we're done!
return None;
}
if should_pop {
self.stack.pop();
if let Some((id, _)) = self.stack.last_mut() {
*id += 1;
}
should_pop = false;
}
if let Some(push) = should_push {
self.stack.push((0, push));
should_push = None;
}
}
returned_node
}
}