(component: FC, props: P, key: Option<&'a str>) -> Self {
// let bad_props = unsafe { transmogrify(props) };
+ let bump = ctx.bump();
let caller_ref = component as *const ();
+ let props = bump.alloc(props);
- // let raw_props = props as *const P as *const ();
+ let raw_props = props as *const P as *const ();
- // let props_comparator = move |other: &VComponent| {
- // // Safety:
- // // We are guaranteed that the props will be of the same type because
- // // there is no way to create a VComponent other than this `new` method.
- // //
- // // Therefore, if the render functions are identical (by address), then so will be
- // // props type paramter (because it is the same render function). Therefore, we can be
- // // sure
- // if caller_ref == other.user_fc {
- // let g = other.raw_ctx.downcast_ref::
().unwrap();
- // // let real_other = unsafe { &*(other.raw_props as *const _ as *const P) };
- // &props == g
- // } else {
- // false
- // }
- // };
+ let comparator: Option<&dyn Fn(&VComponent) -> bool> = {
+ if P::CAN_BE_MEMOIZED {
+ Some(bump.alloc(move |other: &VComponent| {
+ // Safety:
+ // We are guaranteed that the props will be of the same type because
+ // there is no way to create a VComponent other than this `new` method.
+ //
+ // Therefore, if the render functions are identical (by address), then so will be
+ // props type paramter (because it is the same render function). Therefore, we can be
+ // sure
+ if caller_ref == other.user_fc {
+ // let g = other.raw_ctx.downcast_ref::
().unwrap();
+ let real_other = unsafe { &*(other.raw_props as *const _ as *const P) };
+ &props == &real_other
+ } else {
+ false
+ }
+ }))
+ } else {
+ None
+ }
+ };
// let prref: &'a P = props.as_ref();
- let caller: Rc VNode> = Rc::new(move |scope| {
- //
- // let props2 = bad_props;
- // props.as_ref()
- // let ctx = Context {
- // props: prref,
- // scope,
- // };
- todo!()
- // component(ctx)
- });
- // let caller = Rc::new(create_closure(component, raw_props));
+ // let r = create_closure(component, raw_props);
+ // let caller: Rc Fn(&'g Scope) -> VNode<'g>> = Rc::new(move |scope| {
+ // // r(scope);
+ // //
+ // // let props2 = bad_props;
+ // // props.as_ref();
+ // // let ctx = Context {
+ // // props: prref,
+ // // scope,
+ // // };
+ // // let ctx: Context<'g, P> = todo!();
+ // // todo!()
+ // // let r = component(ctx);
+ // todo!()
+ // });
+ let caller = create_closure(component, raw_props);
+
+ // let caller: Rc VNode> = Rc::new(create_closure(component, raw_props));
let key = match key {
Some(key) => NodeKey::new(key),
None => NodeKey(None),
};
+ // raw_props: Box::new(props),
+ // comparator: Rc::new(props_comparator),
Self {
key,
- ass_scope: Rc::new(RefCell::new(None)),
+ ass_scope: RefCell::new(None),
user_fc: caller_ref,
- // raw_props: Box::new(props),
- _p: PhantomData,
- children: &[],
+ comparator,
+ raw_props,
+ children,
caller,
- // comparator: Rc::new(props_comparator),
- stable_addr: Rc::new(RefCell::new(None)),
+ stable_addr: RefCell::new(None),
}
}
}
+type Captured<'a> = Rc Fn(&'r Scope) -> VNode<'r> + 'a>;
+
+fn create_closure<'a, P: Properties + 'a>(
+ component: FC,
+ raw_props: *const (),
+) -> Rc Fn(&'r Scope) -> VNode<'r>> {
+ // ) -> impl for<'r> Fn(&'r Scope) -> VNode<'r> {
+ let g: Captured = Rc::new(move |scp: &Scope| -> VNode {
+ // cast back into the right lifetime
+ let safe_props: &'_ P = unsafe { &*(raw_props as *const P) };
+ // let ctx: Context = todo!();
+ let ctx: Context = Context {
+ props: safe_props,
+ scope: scp,
+ };
+
+ let g = component(ctx);
+ let g2 = unsafe { std::mem::transmute(g) };
+ g2
+ });
+ let r: Captured<'static> = unsafe { std::mem::transmute(g) };
+ r
+}
+
pub struct VFragment<'src> {
pub key: NodeKey<'src>,
pub children: &'src [VNode<'src>],
}
+
+impl<'a> VFragment<'a> {
+ pub fn new(key: Option<&'a str>, children: &'a [VNode<'a>]) -> Self {
+ let key = match key {
+ Some(key) => NodeKey::new(key),
+ None => NodeKey(None),
+ };
+
+ Self { key, children }
+ }
+}
diff --git a/packages/core/src/patch.rs b/packages/core/src/patch.rs
index 98d3959ba..6638ea1f2 100644
--- a/packages/core/src/patch.rs
+++ b/packages/core/src/patch.rs
@@ -146,6 +146,7 @@ pub struct EditMachine<'lock> {
pub traversal: Traversal,
next_temporary: u32,
forcing_new_listeners: bool,
+ pub cur_height: u32,
// // if the current node is a "known" node
// // any actions that modify this node should update the mapping
@@ -158,6 +159,7 @@ impl<'lock> EditMachine<'lock> {
Self {
// current_known: None,
traversal: Traversal::new(),
+ cur_height: 0,
next_temporary: 0,
forcing_new_listeners: false,
emitter: EditList::<'lock>::default(),
diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs
index b84e79101..5d0d62de8 100644
--- a/packages/core/src/virtual_dom.rs
+++ b/packages/core/src/virtual_dom.rs
@@ -32,6 +32,7 @@ use std::{
pin::Pin,
rc::{Rc, Weak},
};
+pub type ScopeIdx = generational_arena::Index;
/// An integrated virtual node system that progresses events and diffs UI trees.
/// Differences are converted into patches which a renderer can use to draw the UI.
@@ -52,8 +53,8 @@ pub struct VirtualDom {
/// a strong allocation to the "caller" for the original component and its props
#[doc(hidden)]
- _root_caller: Rc>,
-
+ _root_caller: Rc,
+ // _root_caller: Rc>,
/// Type of the original ctx. This is stored as TypeId so VirtualDom does not need to be generic.
///
/// Whenver props need to be updated, an Error will be thrown if the new props do not
@@ -137,7 +138,8 @@ impl VirtualDom {
// Normally, a component would be passed as a child in the RSX macro which automatically produces OpaqueComponents
// Here, we need to make it manually, using an RC to force the Weak reference to stick around for the main scope.
- let _root_caller: Rc> = Rc::new(move |scope| {
+ let _root_caller: Rc = Rc::new(move |scope| {
+ // let _root_caller: Rc> = Rc::new(move |scope| {
// the lifetime of this closure is just as long as the lifetime on the scope reference
// this closure moves root props (which is static) into this closure
let props = unsafe { &*(&root_props as *const _) };
@@ -154,10 +156,11 @@ impl VirtualDom {
// Make the first scope
// We don't run the component though, so renderers will need to call "rebuild" when they initialize their DOM
let link = components.clone();
- let event_channel = Rc::new(move || {});
+
let base_scope = components
.with(|arena| {
arena.insert_with(move |myidx| {
+ let event_channel = _event_queue.new_channel(0, myidx);
Scope::new(caller_ref, myidx, None, 0, event_channel, link, &[])
})
})
@@ -175,7 +178,11 @@ impl VirtualDom {
/// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch
/// Currently this doesn't do what we want it to do
pub fn rebuild<'s>(&'s mut self) -> Result> {
- let mut diff_machine = DiffMachine::new();
+ let mut diff_machine = DiffMachine::new(
+ self.components.clone(),
+ self.base_scope,
+ self.event_queue.clone(),
+ );
// Schedule an update and then immediately call it on the root component
// This is akin to a hook being called from a listener and requring a re-render
@@ -190,10 +197,6 @@ impl VirtualDom {
Ok(diff_machine.consume())
}
-
- pub fn base_scope(&self) -> &Scope {
- todo!()
- }
}
// ======================================
@@ -248,7 +251,9 @@ impl VirtualDom {
self.components.try_get_mut(id)?.call_listener(event)?;
- let mut diff_machine = DiffMachine::new();
+ let mut diff_machine =
+ DiffMachine::new(self.components.clone(), id, self.event_queue.clone());
+
self.progress_completely(&mut diff_machine)?;
Ok(diff_machine.consume())
@@ -263,212 +268,48 @@ impl VirtualDom {
diff_machine: &'_ mut DiffMachine<'s>,
) -> Result<()> {
// Add this component to the list of components that need to be difed
- #[allow(unused_assignments)]
- let mut cur_height: u32 = 0;
+ // #[allow(unused_assignments)]
+ // let mut cur_height: u32 = 0;
// Now, there are events in the queue
- let mut seen_nodes = HashSet::::new();
let mut updates = self.event_queue.0.as_ref().borrow_mut();
// Order the nodes by their height, we want the biggest nodes on the top
// This prevents us from running the same component multiple times
updates.sort_unstable();
+ log::debug!("There are: {:#?} updates to be processed", updates.len());
+
// Iterate through the triggered nodes (sorted by height) and begin to diff them
for update in updates.drain(..) {
+ log::debug!("Running updates for: {:#?}", update);
// Make sure this isn't a node we've already seen, we don't want to double-render anything
// If we double-renderer something, this would cause memory safety issues
- if seen_nodes.contains(&update.idx) {
+ if diff_machine.seen_nodes.contains(&update.idx) {
continue;
}
// Now, all the "seen nodes" are nodes that got notified by running this listener
- seen_nodes.insert(update.idx.clone());
+ diff_machine.seen_nodes.insert(update.idx.clone());
// Start a new mutable borrow to components
// We are guaranteeed that this scope is unique because we are tracking which nodes have modified
let cur_component = self.components.try_get_mut(update.idx).unwrap();
+ // let inner: &'s mut _ = unsafe { &mut *self.components.0.borrow().arena.get() };
+ // let cur_component = inner.get_mut(update.idx).unwrap();
cur_component.run_scope()?;
diff_machine.diff_node(cur_component.old_frame(), cur_component.next_frame());
- cur_height = cur_component.height;
+ // cur_height = cur_component.height;
- log::debug!(
- "Processing update: {:#?} with height {}",
- &update.idx,
- cur_height
- );
-
- // Now, the entire subtree has been invalidated. We need to descend depth-first and process
- // any updates that the diff machine has proprogated into the component lifecycle queue
- while let Some(event) = diff_machine.lifecycle_events.pop_front() {
- match event {
- // A new component has been computed from the diffing algorithm
- // create a new component in the arena, run it, move the diffing machine to this new spot, and then diff it
- // this will flood the lifecycle queue with new updates to build up the subtree
- LifeCycleEvent::Mount {
- caller,
- root_id: id,
- stable_scope_addr,
- } => {
- log::debug!("Mounting a new component");
-
- // We're modifying the component arena while holding onto references into the assoiated bump arenas of its children
- // those references are stable, even if the component arena moves around in memory, thanks to the bump arenas.
- // However, there is no way to convey this to rust, so we need to use unsafe to pierce through the lifetime.
-
- // Insert a new scope into our component list
- let idx = self.components.with(|components| {
- components.insert_with(|new_idx| {
- let height = cur_height + 1;
- Scope::new(
- caller,
- new_idx,
- Some(cur_component.arena_idx),
- height,
- self.event_queue.new_channel(height, new_idx),
- self.components.clone(),
- &[],
- )
- })
- })?;
-
- {
- let cur_component = self.components.try_get_mut(update.idx).unwrap();
- let mut ch = cur_component.descendents.borrow_mut();
- ch.insert(idx);
- std::mem::drop(ch);
- }
-
- // Grab out that component
- let new_component = self.components.try_get_mut(idx).unwrap();
-
- // Actually initialize the caller's slot with the right address
- *stable_scope_addr.upgrade().unwrap().as_ref().borrow_mut() = Some(idx);
-
- // Run the scope for one iteration to initialize it
- new_component.run_scope()?;
-
- // Navigate the diff machine to the right point in the output dom
- diff_machine.change_list.load_known_root(id);
-
- // And then run the diff algorithm
- diff_machine
- .diff_node(new_component.old_frame(), new_component.next_frame());
-
- // Finally, insert this node as a seen node.
- seen_nodes.insert(idx);
- }
-
- // A component has remained in the same location but its properties have changed
- // We need to process this component and then dump the output lifecycle events into the queue
- LifeCycleEvent::PropsChanged {
- caller,
- root_id,
- stable_scope_addr,
- } => {
- log::debug!("Updating a component after its props have changed");
-
- // Get the stable index to the target component
- // This *should* exist due to guarantees in the diff algorithm
- let idx = stable_scope_addr
- .upgrade()
- .unwrap()
- .as_ref()
- .borrow()
- .unwrap();
-
- // Grab out that component
- let component = self.components.try_get_mut(idx).unwrap();
-
- // We have to move the caller over or running the scope will fail
- component.update_caller(caller);
-
- // Run the scope
- component.run_scope()?;
-
- // Navigate the diff machine to the right point in the output dom
- diff_machine.change_list.load_known_root(root_id);
-
- // And then run the diff algorithm
- diff_machine.diff_node(component.old_frame(), component.next_frame());
-
- // Finally, insert this node as a seen node.
- seen_nodes.insert(idx);
- }
-
- // A component's parent has updated, but its properties did not change.
- // This means the caller ptr is invalidated and needs to be updated, but the component itself does not need to be re-ran
- LifeCycleEvent::SameProps {
- caller,
- stable_scope_addr,
- ..
- } => {
- // In this case, the parent made a new VNode that resulted in the same props for us
- // However, since our caller is located in a Bump frame, we need to update the caller pointer (which is now invalid)
- log::debug!("Received the same props");
-
- // Get the stable index to the target component
- // This *should* exist due to guarantees in the diff algorithm
- let idx = stable_scope_addr
- .upgrade()
- .unwrap()
- .as_ref()
- .borrow()
- .unwrap();
-
- // Grab out that component
- let component = self.components.try_get_mut(idx).unwrap();
-
- // We have to move the caller over or running the scope will fail
- component.update_caller(caller);
-
- // This time, we will not add it to our seen nodes since we did not actually run it
- }
-
- LifeCycleEvent::Remove {
- root_id,
- stable_scope_addr,
- } => {
- let id = stable_scope_addr
- .upgrade()
- .unwrap()
- .as_ref()
- .borrow()
- .unwrap();
-
- log::warn!("Removing node {:#?}", id);
-
- // This would normally be recursive but makes sense to do linear to
- let mut children_to_remove = VecDeque::new();
- children_to_remove.push_back(id);
-
- // Accumulate all the child components that need to be removed
- while let Some(child_id) = children_to_remove.pop_back() {
- let comp = self.components.try_get(child_id).unwrap();
- let children = comp.descendents.borrow();
- for child in children.iter() {
- children_to_remove.push_front(*child);
- }
- log::debug!("Removing component: {:#?}", child_id);
- self.components
- .with(|components| components.remove(child_id).unwrap())
- .unwrap();
- }
- }
-
- LifeCycleEvent::Replace {
- caller,
- root_id: id,
- ..
- } => {
- unimplemented!("This feature (Replace) is unimplemented")
- }
- }
- }
+ // log::debug!(
+ // "Processing update: {:#?} with height {}",
+ // &update.idx,
+ // cur_height
+ // );
}
Ok(())
@@ -492,7 +333,7 @@ pub struct Scope {
// IDs of children that this scope has created
// This enables us to drop the children and their children when this scope is destroyed
- descendents: RefCell>,
+ pub(crate) descendents: RefCell>,
child_nodes: &'static [VNode<'static>],
@@ -510,8 +351,8 @@ pub struct Scope {
pub event_channel: Rc,
// pub event_queue: EventQueue,
- pub caller: Weak>,
-
+ pub caller: Weak,
+ // pub caller: Weak>,
pub hookidx: RefCell,
// ==========================
@@ -545,8 +386,9 @@ impl Scope {
//
// Scopes cannot be made anywhere else except for this file
// Therefore, their lifetimes are connected exclusively to the virtual dom
- fn new<'creator_node>(
- caller: Weak>,
+ pub fn new<'creator_node>(
+ caller: Weak,
+ // caller: Weak>,
arena_idx: ScopeIdx,
parent: Option,
height: u32,
@@ -572,13 +414,17 @@ impl Scope {
// Not the best solution, so TODO on removing this in favor of a dedicated resource abstraction.
let caller = unsafe {
std::mem::transmute::<
- Weak>,
- Weak>,
+ Weak,
+ Weak,
+ // Weak>,
+ // Weak>,
>(caller)
};
+ let child_nodes = unsafe { std::mem::transmute(child_nodes) };
+
Self {
- child_nodes: &[],
+ child_nodes: child_nodes,
caller,
parent,
arena_idx,
@@ -594,11 +440,14 @@ impl Scope {
}
}
- pub fn update_caller<'creator_node>(&mut self, caller: Weak>) {
+ pub fn update_caller<'creator_node>(&mut self, caller: Weak) {
+ // pub fn update_caller<'creator_node>(&mut self, caller: Weak>) {
let broken_caller = unsafe {
std::mem::transmute::<
- Weak>,
- Weak>,
+ Weak,
+ Weak,
+ // Weak>,
+ // Weak>,
>(caller)
};
@@ -630,8 +479,10 @@ impl Scope {
.ok_or(Error::FatalInternal("Failed to get caller"))?;
// Cast the caller ptr from static to one with our own reference
- let c2: &OpaqueComponent<'static> = caller.as_ref();
- let c3: &OpaqueComponent<'sel> = unsafe { std::mem::transmute(c2) };
+ let c2: &OpaqueComponent = caller.as_ref();
+ let c3: &OpaqueComponent = unsafe { std::mem::transmute(c2) };
+ // let c2: &OpaqueComponent<'static> = caller.as_ref();
+ // let c3: &OpaqueComponent<'sel> = unsafe { std::mem::transmute(c2) };
let unsafe_head = unsafe { self.own_vnodes(c3) };
@@ -641,7 +492,7 @@ impl Scope {
}
// this is its own function so we can preciesly control how lifetimes flow
- unsafe fn own_vnodes<'a>(&'a self, f: &OpaqueComponent<'a>) -> VNode<'static> {
+ unsafe fn own_vnodes<'a>(&'a self, f: &OpaqueComponent) -> VNode<'static> {
let new_head: VNode<'a> = f(self);
let out: VNode<'static> = std::mem::transmute(new_head);
out
@@ -959,22 +810,25 @@ Any function prefixed with "use" should not be called conditionally.
// We actually allocate the properties for components in their parent's properties
// We then expose a handle to use those props for render in the form of "OpaqueComponent"
-pub(crate) type OpaqueComponent<'e> = dyn for<'b> Fn(&'b Scope) -> VNode<'b> + 'e;
+pub type OpaqueComponent = dyn for<'b> Fn(&'b Scope) -> VNode<'b>;
#[derive(PartialEq, Debug, Clone, Default)]
-pub(crate) struct EventQueue(pub Rc>>);
+pub struct EventQueue(pub Rc>>);
impl EventQueue {
pub fn new_channel(&self, height: u32, idx: ScopeIdx) -> Rc {
let inner = self.clone();
let marker = HeightMarker { height, idx };
- Rc::new(move || inner.0.as_ref().borrow_mut().push(marker))
+ Rc::new(move || {
+ log::debug!("channel updated {:#?}", marker);
+ inner.0.as_ref().borrow_mut().push(marker)
+ })
}
}
/// A helper type that lets scopes be ordered by their height
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) struct HeightMarker {
+pub struct HeightMarker {
pub idx: ScopeIdx,
pub height: u32,
}
@@ -1050,20 +904,20 @@ impl ActiveFrame {
)
}
- fn from_frames(a: BumpFrame, b: BumpFrame) -> Self {
+ pub fn from_frames(a: BumpFrame, b: BumpFrame) -> Self {
Self {
generation: 0.into(),
frames: [a, b],
}
}
- fn cur_frame(&self) -> &BumpFrame {
+ pub fn cur_frame(&self) -> &BumpFrame {
match *self.generation.borrow() & 1 == 0 {
true => &self.frames[0],
false => &self.frames[1],
}
}
- fn cur_frame_mut(&mut self) -> &mut BumpFrame {
+ pub fn cur_frame_mut(&mut self) -> &mut BumpFrame {
match *self.generation.borrow() & 1 == 0 {
true => &mut self.frames[0],
false => &mut self.frames[1],
@@ -1098,7 +952,7 @@ impl ActiveFrame {
}
}
- fn next(&mut self) -> &mut BumpFrame {
+ pub fn next(&mut self) -> &mut BumpFrame {
*self.generation.borrow_mut() += 1;
if *self.generation.borrow() % 2 == 0 {
diff --git a/packages/hooks/src/lib.rs b/packages/hooks/src/lib.rs
index 847cf79e4..ddbe01699 100644
--- a/packages/hooks/src/lib.rs
+++ b/packages/hooks/src/lib.rs
@@ -84,7 +84,7 @@ fn use_map() {}
// Elements are received as Rc in case the underlying collection is shuffled around
// Setters/getters can be generated
fn use_collection<'a, T: Collection>(
- ctx: &Context<'a>,
+ ctx: &impl Scoped<'a>,
f: impl Fn() -> T,
) -> CollectionHandle<'a, T> {
ctx.use_hook(
diff --git a/packages/recoil/examples/callback.rs b/packages/recoil/examples/callback.rs
index 3d1c75b68..be67683b4 100644
--- a/packages/recoil/examples/callback.rs
+++ b/packages/recoil/examples/callback.rs
@@ -20,7 +20,7 @@ fn update_title(api: &RecoilApi) {
}
static App: FC<()> = |ctx| {
- let title = use_read(ctx, &TITLE);
+ let title = use_read(&ctx, &TITLE);
let next_light = use_recoil_api(ctx, |api| move |_| update_title(&api));
rsx! { in ctx,
diff --git a/packages/recoil/src/lib.rs b/packages/recoil/src/lib.rs
index e73428600..634d9442e 100644
--- a/packages/recoil/src/lib.rs
+++ b/packages/recoil/src/lib.rs
@@ -32,7 +32,7 @@ mod traits {
// Atoms, selectors, and their family variants are readable
pub trait Readable: Sized + Copy {
fn use_read<'a, P: 'static>(self, ctx: Context<'a, P>) -> &'a T {
- hooks::use_read(ctx, self)
+ hooks::use_read(&ctx, self)
}
// This returns a future of the value
@@ -95,9 +95,9 @@ mod atoms {
const EXAMPLE_ATOM: Atom = |_| 10;
// ensure that atoms are both read and write
- let _ = use_read(ctx, &EXAMPLE_ATOM);
- let _ = use_read_write(ctx, &EXAMPLE_ATOM);
- let _ = use_write(ctx, &EXAMPLE_ATOM);
+ let _ = use_read(&ctx, &EXAMPLE_ATOM);
+ let _ = use_read_write(&ctx, &EXAMPLE_ATOM);
+ let _ = use_write(&ctx, &EXAMPLE_ATOM);
}
}
}
@@ -161,7 +161,7 @@ mod atomfamily {
fn test(ctx: Context<()>) {
let title = Titles.select(&10).use_read(ctx);
- let t2 = use_read(ctx, &Titles.select(&10));
+ let t2 = use_read(&ctx, &Titles.select(&10));
}
}
}
@@ -368,7 +368,7 @@ mod root {
mod hooks {
use super::*;
- use dioxus_core::{hooks::use_ref, prelude::Context};
+ use dioxus_core::{hooks::use_ref, prelude::Context, virtual_dom::Scoped};
pub fn use_init_recoil_root(ctx: Context
, cfg: impl Fn(())) {
ctx.use_create_context(move || RefCell::new(RecoilRoot::new()))
@@ -381,12 +381,12 @@ mod hooks {
///
/// You can use this method to create controllers that perform much more complex actions than set/get
/// However, be aware that "getting" values through this hook will not subscribe the component to any updates.
- pub fn use_recoil_api<'a, P>(ctx: Context<'a, P>) -> &Rc {
+ pub fn use_recoil_api<'a>(ctx: &impl Scoped<'a>) -> &'a Rc {
ctx.use_context::()
}
- pub fn use_write<'a, T: AtomValue, P>(
- ctx: Context<'a, P>,
+ pub fn use_write<'a, T: AtomValue>(
+ ctx: &impl Scoped<'a>,
// todo: this shouldn't need to be static
writable: impl Writable,
) -> &'a Rc {
@@ -412,10 +412,10 @@ mod hooks {
/// Read the atom and get the Rc directly to the Atom's slot
/// This is useful if you need the memoized Atom value. However, Rc is not as easy to
/// work with as
- pub fn use_read_raw<'a, T: AtomValue, P: 'static>(
- ctx: Context<'a, P>,
+ pub fn use_read_raw<'a, T: AtomValue>(
+ ctx: &impl Scoped<'a>,
readable: impl Readable,
- ) -> &Rc {
+ ) -> &'a Rc {
struct ReadHook {
value: Rc,
consumer_id: u32,
@@ -449,10 +449,7 @@ mod hooks {
}
///
- pub fn use_read<'a, T: AtomValue, P: 'static>(
- ctx: Context<'a, P>,
- readable: impl Readable,
- ) -> &'a T {
+ pub fn use_read<'a, T: AtomValue>(ctx: &impl Scoped<'a>, readable: impl Readable) -> &'a T {
use_read_raw(ctx, readable).as_ref()
}
@@ -471,8 +468,8 @@ mod hooks {
/// // equivalent to:
/// let (title, set_title) = (use_read(ctx, &Title), use_write(ctx, &Title));
/// ```
- pub fn use_read_write<'a, T: AtomValue + 'static, P: 'static>(
- ctx: Context<'a, P>,
+ pub fn use_read_write<'a, T: AtomValue + 'static>(
+ ctx: &impl Scoped<'a>,
writable: impl Writable,
) -> (&'a T, &'a Rc) {
(use_read(ctx, writable), use_write(ctx, writable))
diff --git a/packages/web/examples/children.rs b/packages/web/examples/children.rs
new file mode 100644
index 000000000..0c7bebb7f
--- /dev/null
+++ b/packages/web/examples/children.rs
@@ -0,0 +1,36 @@
+//! Basic example that renders a simple VNode to the browser.
+
+use dioxus_core::prelude::*;
+use dioxus_web::*;
+
+fn main() {
+ // Setup logging
+ wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
+ console_error_panic_hook::set_once();
+
+ // Run the app
+ wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
+}
+
+static App: FC<()> = |ctx| {
+ ctx.render(rsx! {
+ Calcier {
+ h2 {"abc 1"}
+ h2 {"abc 2"}
+ h2 {"abc 3"}
+ h2 {"abc 4"}
+ h2 {"abc 5"}
+ }
+ })
+};
+
+static Calcier: FC<()> = |ctx| {
+ ctx.render(rsx! {
+ div {
+ h1 {
+ "abc 0"
+ }
+ {ctx.children()}
+ }
+ })
+};
diff --git a/packages/web/examples/context.rs b/packages/web/examples/context.rs
index 6653d61ca..17f2dea0e 100644
--- a/packages/web/examples/context.rs
+++ b/packages/web/examples/context.rs
@@ -52,7 +52,7 @@ struct ButtonProps {
id: u8,
}
-fn CustomButton(ctx: Context, props: &ButtonProps) -> VNode {
+fn CustomButton(ctx: Context) -> VNode {
let names = ctx.use_context::();
let name = names.0[ctx.id as usize];
diff --git a/packages/web/examples/fragment.rs b/packages/web/examples/fragment.rs
new file mode 100644
index 000000000..1f3e63049
--- /dev/null
+++ b/packages/web/examples/fragment.rs
@@ -0,0 +1,25 @@
+//! Basic example that renders a simple VNode to the browser.
+
+use dioxus_core::prelude::*;
+use dioxus_web::*;
+
+fn main() {
+ // Setup logging
+ wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
+ console_error_panic_hook::set_once();
+
+ // Run the app
+ wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
+}
+
+static App: FC<()> = |ctx| {
+ ctx.render(rsx! {
+ h2 { "abc 1" }
+ div {
+ "hello world!"
+ }
+ Fragment {
+ h2 { "abc 2"}
+ }
+ })
+};
diff --git a/packages/web/examples/helloworld.rs b/packages/web/examples/helloworld.rs
new file mode 100644
index 000000000..480adace4
--- /dev/null
+++ b/packages/web/examples/helloworld.rs
@@ -0,0 +1,11 @@
+use dioxus_web::prelude::*;
+
+fn main() {
+ wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App))
+}
+
+fn App(ctx: Context<()>) -> VNode {
+ ctx.render(rsx! {
+ div { "Hello, world!" }
+ })
+}
diff --git a/packages/web/examples/many.rs b/packages/web/examples/many.rs
new file mode 100644
index 000000000..d595468f1
--- /dev/null
+++ b/packages/web/examples/many.rs
@@ -0,0 +1,21 @@
+use dioxus_core::prelude::*;
+use dioxus_web::WebsysRenderer;
+
+fn main() {
+ wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
+ console_error_panic_hook::set_once();
+
+ log::info!("hello world");
+ wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
+}
+
+static Example: FC<()> = |ctx| {
+ ctx.render(rsx! {
+ div {
+ span {
+ class: "px-2 py-1 flex w-36 mt-4 items-center text-xs rounded-md font-semibold text-yellow-500 bg-yellow-100"
+ "DUE DATE : 18 JUN"
+ }
+ }
+ })
+};
diff --git a/packages/web/examples/rsxt.rs b/packages/web/examples/rsxt.rs
index dbe85d207..94fb9407d 100644
--- a/packages/web/examples/rsxt.rs
+++ b/packages/web/examples/rsxt.rs
@@ -53,7 +53,7 @@ struct ButtonProps<'src, F: Fn(MouseEvent)> {
handler: F
}
-fn CustomButton<'b, 'a, F: Fn(MouseEvent)>(ctx: Context<'a>, props: &'b ButtonProps<'b, F>) -> VNode {
+fn CustomButton<'a, F: Fn(MouseEvent)>(ctx: Context<'a, ButtonProps<'a, F>>) -> VNode {
ctx.render(rsx!{
button {
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
@@ -74,7 +74,7 @@ impl PartialEq for ButtonProps<'_, F> {
struct PlaceholderProps {
val: &'static str
}
-fn Placeholder(ctx: Context, props: &PlaceholderProps) -> VNode {
+fn Placeholder(ctx: Context) -> VNode {
ctx.render(rsx!{
div {
"child: {ctx.val}"
diff --git a/packages/web/examples/todomvcsingle.rs b/packages/web/examples/todomvcsingle.rs
index a2f6eacbe..8320cd198 100644
--- a/packages/web/examples/todomvcsingle.rs
+++ b/packages/web/examples/todomvcsingle.rs
@@ -149,11 +149,11 @@ pub fn FilterToggles(ctx: Context<()>) -> VNode {
.iter()
.map(|(name, path, filter)| {
rsx!(
- li {
- class: "{name}"
- a { "{name}",
+ li { class: "{name}"
+ a {
href: "{path}",
onclick: move |_| reducer.set_filter(&filter),
+ "{name}",
}
}
)
@@ -168,7 +168,7 @@ pub fn FilterToggles(ctx: Context<()>) -> VNode {
footer {
span {
strong {"{items_left}"}
- span {"{item_text} left"}
+ span { "{item_text} left" }
}
ul {
class: "filters"
@@ -180,8 +180,7 @@ pub fn FilterToggles(ctx: Context<()>) -> VNode {
pub fn Footer(ctx: Context<()>) -> VNode {
rsx! { in ctx,
- footer {
- class: "info"
+ footer { class: "info"
p {"Double-click to edit a todo"}
p {
"Created by "