WIP: Todomvc in progress

This commit is contained in:
Jonathan Kelley committed 2021-05-19 10:14:02 -04:00
1 parent 0d44f009b0
commit b843dbd367
10 files changed
+416 -219

No files matched your search

+4 -2
View File
@@ -1,9 +1,11 @@
[package]
name = "dioxus-recoil"
name = "recoil"
version = "0.0.0"
authors = ["Jonathan Kelley <jkelleyrtp@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dependencies]
dioxus-core = { path = "../core" }
uuid = "0.8.2"
+8 -4
View File
@@ -1,13 +1,17 @@
# Recoil.rs
# Recoil.rs - Official global state management solution for Dioxus Apps
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
Recoil.rs is officially supported by the Dioxus team. By doing so, are are "planting our flag in the stand" for atomic state management instead of bundled (Redux-style) state management. Atomic state management fits well with the internals of Dioxus, meaning Recoil.rs state management will be faster, more efficient, and less sensitive to data races than Redux-style apps.
Internally, Dioxus uses batching to speed up linear-style operations. Recoil.rs integrates with this batching optimization, making app-wide changes extremely fast. This way, Recoil.rs can be pushed significantly harder than Redux without the need to enable/disable debug flags to prevent performance slowdowns.
## Guide
A simple atom of state is defined globally as a const:
A simple atom of state is defined globally as a static:
```rust
static Light: Atom<&'static str> = atom(|_| "Green");
const 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.
@@ -16,7 +20,7 @@ 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
// The recoil root must be initialized at the top of the application before any use_recoils
recoil::init_recoil_root(&ctx, |_| {});
let color = use_recoil(&ctx, &TITLE);
+130 -5
View File
@@ -1,7 +1,132 @@
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
// ========================
// Important hooks
// ========================
pub fn init_recoil_root(ctx: Context) {}
pub fn use_recoil_value() {}
pub fn use_recoil() {}
pub fn use_set_recoil() {}
use dioxus_core::virtual_dom::Context;
pub struct RecoilContext {}
impl RecoilContext {
/// Get the value of an atom. Returns a reference to the underlying data.
pub fn get<T: PartialEq>(&self, t: &'static Atom<T>) -> &T {
todo!()
}
/// Replace an existing value with a new value
///
/// This does not replace the value instantly.
/// All calls to "get" will return the old value until the component is rendered.
pub fn set<T: PartialEq, O>(&self, t: &'static Atom<T>, new: T) {
self.modify(t, move |old| *old = new);
}
/// Modify lets you modify the value in place. However, because there's no previous value around to compare
/// the new one with, we are unable to memoize the change. As such, all downsteam users of this Atom will
/// be updated, causing all subsrcibed components to re-render.
///
/// This is fine for most values, but might not be performant when dealing with collections. For collections,
/// use the "Family" variants as these will stay memoized for inserts, removals, and modifications.
///
/// Note - like "set" this won't propogate instantly. Once all "gets" are dropped, only then will the update occur
pub fn modify<T: PartialEq, O>(&self, t: &'static Atom<T>, f: impl FnOnce(&mut T) -> O) -> O {
todo!()
}
}
pub fn use_recoil_context<T>(c: Context) -> &T {
todo!()
}
// pub fn use_callback<'a>(c: &Context<'a>, f: impl Fn() -> G) -> &'a RecoilContext {
// todo!()
// }
pub fn use_atom<'a, T: PartialEq>(c: Context<'a>, t: &'static Atom<T>) -> &'a T {
todo!()
}
pub trait Readable {}
impl<T: PartialEq> Readable for &'static Atom<T> {}
impl<K: PartialEq, V: PartialEq> Readable for &'static AtomFamily<K, V> {}
pub fn use_atom_family<'a, K: PartialEq, V: PartialEq>(
c: &Context<'a>,
t: &'static AtomFamily<K, V>,
g: K,
) -> &'a V {
todo!()
}
pub struct AtomBuilder<T: PartialEq> {
pub key: String,
pub manual_init: Option<Box<dyn Fn() -> T>>,
_never: std::marker::PhantomData<T>,
}
impl<T: PartialEq> AtomBuilder<T> {
pub fn new() -> Self {
Self {
key: "".to_string(),
manual_init: None,
_never: std::marker::PhantomData {},
}
}
pub fn init<A: Fn() -> T + 'static>(&mut self, f: A) {
self.manual_init = Some(Box::new(f));
}
pub fn set_key(&mut self, _key: &'static str) {}
}
// =====================================
// Atom
// =====================================
pub struct atom<T: PartialEq>(pub fn(&mut AtomBuilder<T>) -> T);
pub type Atom<T: PartialEq> = atom<T>;
// =====================================
// Atom Family
// =====================================
pub struct AtomFamilyBuilder<K, V> {
_never: std::marker::PhantomData<(K, V)>,
}
pub struct atom_family<K: PartialEq, V: PartialEq>(pub fn(&mut AtomFamilyBuilder<K, V>));
pub type AtomFamily<K: PartialEq, V: PartialEq> = atom_family<K, V>;
// =====================================
// Selectors
// =====================================
pub struct SelectorApi {}
impl SelectorApi {
pub fn get<T: PartialEq>(&self, t: &'static Atom<T>) -> &T {
todo!()
}
}
// pub struct SelectorBuilder<Out, const Built: bool> {
// _p: std::marker::PhantomData<Out>,
// }
// impl<O> SelectorBuilder<O, false> {
// pub fn getter(self, f: impl Fn(()) -> O) -> SelectorBuilder<O, true> {
// todo!()
// // std::rc::Rc::pin(value)
// // todo!()
// }
// }
pub struct selector<O>(pub fn(&SelectorApi) -> O);
// pub struct selector<O>(pub fn(SelectorBuilder<O, false>) -> SelectorBuilder<O, true>);
pub type Selector<O> = selector<O>;
pub fn use_selector<'a, O>(c: Context<'a>, s: &'static Selector<O>) -> &'a O {
todo!()
}