mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-22 20:23:09 +00:00
Feat: about to consolidate context and scope
This commit is contained in:
parent
3de54d0b52
commit
4c8130c4e4
5 changed files with 136 additions and 9 deletions
|
@ -1 +1,3 @@
|
|||
# Hello examples
|
||||
# Examples
|
||||
|
||||
Most of these examples are run through webview so you don't need the dioxus cli installed to preview the functionality. Anything labeled `_web` will need to be compiled with Dioxus CLI.
|
||||
|
|
38
examples/external_updates.rs
Normal file
38
examples/external_updates.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
//! Example: External Updates
|
||||
//! -------------------------
|
||||
//! Cause updates to the VirtualDOM state from outside the component lifecycle.
|
||||
//! The root props could be changed or the use_receiver hook could be used.
|
||||
//!
|
||||
//!
|
||||
|
||||
fn main() {
|
||||
let (recv, sender) = channel();
|
||||
|
||||
async_std::task::spawn({
|
||||
for location in ["a", "b", "c", "d"] {
|
||||
sender.send(location);
|
||||
}
|
||||
});
|
||||
|
||||
let app = diouxs_webview::launch_with_props(App, RootProps { recv }).await;
|
||||
}
|
||||
|
||||
struct RootProps {
|
||||
navigator: Receiver<&'static str>,
|
||||
}
|
||||
|
||||
fn App(ctx: Context, props: &RootProps) -> DomTree {
|
||||
let router = use_router(&ctx, |router| {});
|
||||
|
||||
let navigator = use_history(&ctx);
|
||||
|
||||
use_receiver(&ctx, || props.recv.clone(), |to| navigator.navigate(to));
|
||||
|
||||
ctx.render(rsx! {
|
||||
div {
|
||||
a { href="/dogs/"}
|
||||
a { href="/cats/"}
|
||||
{content}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -8,4 +8,35 @@
|
|||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
diouxs_webview::launch(App).run().await
|
||||
}
|
||||
|
||||
fn App(ctx: Context, props: &()) -> DomTree {
|
||||
let router = use_router(&ctx, |router| {
|
||||
//
|
||||
router.get("/dogs/:dogId/").render(|ctx, request| {
|
||||
rsx! {
|
||||
div {
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/cats/:catId/").render(|ctx, request| {
|
||||
rsx! {
|
||||
div {
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ctx.render(rsx! {
|
||||
div {
|
||||
a { href="/dogs/"}
|
||||
a { href="/cats/"}
|
||||
{router.render()}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -22,9 +22,9 @@ use crate::{arena::ScopeArena, innerlude::*};
|
|||
use bumpalo::Bump;
|
||||
use generational_arena::Arena;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
any::{Any, TypeId},
|
||||
cell::{RefCell, UnsafeCell},
|
||||
collections::HashSet,
|
||||
collections::{HashMap, HashSet},
|
||||
fmt::Debug,
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
|
@ -50,6 +50,10 @@ pub struct VirtualDom {
|
|||
/// All components dump their updates into a queue to be processed
|
||||
pub(crate) event_queue: EventQueue,
|
||||
|
||||
/// Global contexts shared within the VirtualDOM
|
||||
/// These are anchored to individual scopes, making them inaccessible if a context is created from a sibiling
|
||||
pub(crate) contexts: HashMap<ContextId, Box<dyn Any>>,
|
||||
|
||||
/// a strong allocation to the "caller" for the original component and its props
|
||||
#[doc(hidden)]
|
||||
_root_caller: Rc<OpaqueComponent<'static>>,
|
||||
|
@ -152,6 +156,7 @@ impl VirtualDom {
|
|||
_root_caller,
|
||||
base_scope,
|
||||
event_queue,
|
||||
contexts: Default::default(),
|
||||
components: ScopeArena::new(components),
|
||||
_root_prop_type: TypeId::of::<P>(),
|
||||
}
|
||||
|
@ -720,8 +725,6 @@ impl<'a> Context<'a> {
|
|||
todo!("Children API not yet implemented for component Context")
|
||||
}
|
||||
|
||||
pub fn callback(&self, _f: impl Fn(()) + 'a) {}
|
||||
|
||||
/// Create a subscription that schedules a future render for the reference component
|
||||
pub fn schedule_update(&self) -> impl Fn() -> () {
|
||||
self.scope.event_queue.schedule_update(&self.scope)
|
||||
|
@ -763,12 +766,15 @@ impl<'scope> Context<'scope> {
|
|||
idx: 0.into(),
|
||||
};
|
||||
|
||||
let safe_nodes: VNode<'scope> = lazy_nodes.into_vnode(&ctx);
|
||||
let root: VNode<'static> = unsafe { std::mem::transmute(safe_nodes) };
|
||||
DomTree { root }
|
||||
DomTree {
|
||||
root: unsafe {
|
||||
std::mem::transmute::<VNode<'scope>, VNode<'static>>(lazy_nodes.into_vnode(&ctx))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We need to pin the hook so it doesn't move as we initialize the list of hooks
|
||||
type Hook = Pin<Box<dyn std::any::Any>>;
|
||||
|
||||
impl<'scope> Context<'scope> {
|
||||
|
@ -833,6 +839,16 @@ impl<'scope> Context<'scope> {
|
|||
// We extend the lifetime of the internal state
|
||||
runner(unsafe { &mut *(internal_state as *mut _) })
|
||||
}
|
||||
|
||||
fn create_context_provider<T: 'static>(&self, init: impl Fn() -> T) {}
|
||||
|
||||
fn try_consume_context<T: 'static>(&self) -> Result<&T> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn consume_context<T: 'static>(&self) -> &T {
|
||||
self.try_consume_context().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
mod support {
|
||||
|
@ -894,6 +910,18 @@ mod support {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Hash)]
|
||||
pub struct ContextId {
|
||||
// Which component is the scope in
|
||||
original: ScopeIdx,
|
||||
|
||||
// What's the height of the scope
|
||||
height: u32,
|
||||
|
||||
// Which scope is it (in order)
|
||||
id: u32,
|
||||
}
|
||||
}
|
||||
|
||||
mod tests {
|
||||
|
|
28
packages/recoil/README.md
Normal file
28
packages/recoil/README.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Recoil.rs
|
||||
Recoil.rs provides a global state management API for Dioxus apps built on the concept of "atomic state." Instead of grouping state together into a single bundle ALA Redux, Recoil provides individual building blocks of state called Atoms. These atoms can be set/get anywhere in the app and combined to craft complex state. Recoil should be easier to learn and more efficient than Redux. Recoil.rs is modeled after the Recoil.JS project and pulls in
|
||||
|
||||
|
||||
## Guide
|
||||
|
||||
A simple atom of state is defined globally as a const:
|
||||
|
||||
```rust
|
||||
static Light: Atom<&'static str> = atom(|_| "Green");
|
||||
```
|
||||
|
||||
This atom of state is initialized with a value of `"Green"`. The atom that is returned does not actually contain any values. Instead, the atom's key - which is automatically generated in this instance - is used in the context of a Recoil App.
|
||||
|
||||
This is then later used in components like so:
|
||||
|
||||
```rust
|
||||
fn App(ctx: Context, props: &()) -> DomTree {
|
||||
// The recoil root must be initialized at the top of the application before any uses
|
||||
recoil::init_recoil_root(&ctx, |_| {});
|
||||
|
||||
let color = use_recoil(&ctx, &TITLE);
|
||||
|
||||
ctx.render(rsx!{
|
||||
h1 {"Color of light: {color}"}
|
||||
})
|
||||
}
|
||||
```
|
Loading…
Reference in a new issue