wip: remove runner on hook and then update docs
This commit is contained in:
1 parent
7d41a16208
commit
d1560450ba
95 files changed
+1339
-675
No files matched your search
+12
-19
@@ -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>,
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user