wip: parity document

This commit is contained in:
Jonathan Kelley 2021-05-26 11:22:44 -04:00
parent ee67654f58
commit ba975410f9
7 changed files with 115 additions and 51 deletions

View File

@ -5,6 +5,10 @@ Welcome to the first iteration of the Dioxus Virtual DOM! This release brings su
- Server-rendering with custom ToString implementation
- State management
- Build CLI
- Foundational hooks
- Context API
- Basic suspense
- Controlled components
----
## Project: Initial VDOM support (TBD)
> Get the initial VDom + Event System + Patching + Diffing + Component framework up and running
@ -80,18 +84,25 @@ Welcome to the first iteration of the Dioxus Virtual DOM! This release brings su
- [x] Tweak macro parsing for better errors
- [x] dirty tagging, compression
- [x] code health
- [ ] name spacing so svg works
- [ ] fix keys on elements
- [ ] controlled components (kinda tuff since we need all these different platforms)
- [ ] Their own crate
- [ ] Re-exported through the `dioxus` crate (not core)
- [ ] Hooks
- [ ] Re-exported through the `dioxus` crate (not essential to core virtualdom)
## Less-essential todos
- [ ] Make events lazy (use traits + Box<dyn>) - not sure what this means anymore
- [ ] Beef up the dioxus CLI tool to report build progress
- [ ] Extract arena logic out for better safety guarantees
- [ ] Extract BumpFrame logic out for better safety guarantees
- [ ] make SSR follow HTML spec
- [ ] fix keys on elements
- [ ] MIRI tests
- [ ] all synthetic events filled out
- [ ] double check event targets and stuff
- [ ] Documentation overhaul
- [ ] Website
- [ ] controlled components
lower priority features
- [ ] Attributes on elements should implement format_args instead of string fmt

34
notes/Parity.md Normal file
View File

@ -0,0 +1,34 @@
# Parity with React
Sorted by priority
| Feature | Dioxus | React |
| ---------------------- | ------ | ----- |
| Conditional Rendering | ✅ | ✅ |
| Map, Iterator | ✅ | ✅ |
| Keyed Components | ✅ | ✅ |
| Web | ✅ | ✅ |
| Desktop (webview) | ✅ | ✅ |
| Context | ✅ | ✅ |
| Hook | ✅ | ✅ |
| SSR | ✅ | ✅ |
| Runs natively | ✅ | 👀 |
| Null components | 👀 | ✅ |
| Fragments | 👀 | ✅ |
| Component Children | 👀 | ✅ |
| NodeRef | 👀 | ✅ |
| Controlled Inputs | 👀 | ✅ |
| No-div components | 👀 | ✅ |
| CSS/Inline Styles | 👀 | ✅ |
| 1st class global state | 👀 | ✅ |
| -------------------- | ----- | ----- |
| 1st class router | 👀 | ✅ |
| Suspense | 👀 | 👀 |
| Animation | 👀 | ✅ |
| Mobile | 👀 | ✅ |
| Desktop (native) | 👀 | ✅ |
| 3D Renderer | 👀 | ✅ |
| -------------------- | ----- | ----- |
| Portal | 👀 | ✅ |
| Error boundary | 👀 | ✅ |
| Code-splitting | 👀 | ✅ |

View File

@ -8,8 +8,8 @@ edition = "2018"
[dependencies]
dioxus-core = { path = "../core" }
uuid = "0.8.2"
[dev-dependencies]
uuid = { version = "0.8.2", features = ["v4"] }
dioxus-web = { path = "../web" }
wasm-bindgen-futures = "*"

View File

@ -2,16 +2,22 @@ use std::collections::HashMap;
use dioxus_core::prelude::*;
use recoil::*;
use uuid::Uuid;
const TODOS: AtomFamily<&str, Todo> = |_| HashMap::new();
const TODOS: AtomFamily<Uuid, Todo> = |_| HashMap::new();
#[derive(PartialEq)]
struct Todo {
checked: bool,
title: String,
contents: String,
}
static App: FC<()> = |ctx, _| {
use_init_recoil_root(ctx);
let todos = use_recoil_family(ctx, &TODOS);
rsx! { in ctx,
div {
"Basic Todolist with AtomFamilies in Recoil.rs"
@ -19,11 +25,20 @@ static App: FC<()> = |ctx, _| {
}
};
static Child: FC<()> = |ctx, _| {
// let todo = use_recoil_value(ctx, &TODOS);
#[derive(Props, PartialEq)]
struct ChildProps {
id: Uuid,
}
static Child: FC<ChildProps> = |ctx, props| {
let (todo, set_todo) = use_recoil_state(ctx, &TODOS.select(&props.id));
rsx! { in ctx,
div {
h1 {"{todo.title}"}
input { type: "checkbox", name: "scales", checked: "{todo.checked}" }
label { "{todo.contents}", for: "scales" }
p {"{todo.contents}"}
}
}
};

View File

@ -18,8 +18,9 @@ const D_SELECTOR: SelectorFamilyBorrowed<i32, i32> = |api, key| -> &i32 {
};
static App: FC<()> = |ctx, _| {
let title = use_recoil_value(ctx, &C_SELECTOR);
use_init_recoil_root(ctx);
let title = use_recoil_value(ctx, &C_SELECTOR);
let title = "";
rsx! { in ctx,
div {

View File

@ -43,6 +43,7 @@ pub struct CollectionSelection<T> {
_never: PhantomData<T>,
}
impl<T> Readable<T> for CollectionSelection<T> {}
impl<T> Writeable<T> for CollectionSelection<T> {}
// =================
// Selectors
@ -125,22 +126,26 @@ mod hooks {
pub fn use_set_state<'a, T: PartialEq>(
c: Context<'a>,
t: &'static impl Writeable<T>,
t: &impl Writeable<T>,
) -> &'a Rc<dyn Fn(T)> {
todo!()
}
pub fn use_recoil_state<'a, T: PartialEq + 'static>(
ctx: Context<'a>,
readable: &'static impl Writeable<T>,
writeable: &impl Writeable<T>,
) -> (&'a T, &'a Rc<dyn Fn(T)>) {
todo!()
}
pub fn use_recoil_value<'a, T: PartialEq>(
pub fn use_recoil_value<'a, T: PartialEq>(ctx: Context<'a>, t: &impl Readable<T>) -> &'a T {
todo!()
}
pub fn use_recoil_family<'a, K, V, C: FamilyCollection<K, V>>(
ctx: Context<'a>,
t: &'static impl Readable<T>,
) -> &'a T {
t: &AtomFamily<K, V, C>,
) -> &'a C {
todo!()
}

View File

@ -13,16 +13,24 @@ use recoil::*;
use std::collections::HashMap;
use uuid::Uuid;
const APP_STYLE: &'static str = include_str!("./todomvc/style.css");
#[derive(PartialEq, Clone, Copy)]
pub enum FilterState {
All,
Active,
Completed,
}
fn main() {
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App));
#[derive(Debug, PartialEq, Clone)]
pub struct TodoItem {
pub id: Uuid,
pub checked: bool,
pub contents: String,
}
// Declare our global app state
const TODO_LIST: Atom<HashMap<Uuid, TodoItem>> = atom(|_| Default::default());
const FILTER: Atom<FilterState> = atom(|_| FilterState::All);
const TODOS_LEFT: selector<usize> = selector(|api| api.get(&TODO_LIST).len());
const TODO_LIST: Atom<HashMap<Uuid, TodoItem>> = |_| Default::default();
const FILTER: Atom<FilterState> = |_| FilterState::All;
const TODOS_LEFT: Selector<usize> = |api| api.get(&TODO_LIST).len();
// Implement a simple abstraction over sets/gets of multiple atoms
struct TodoManager(RecoilApi);
@ -64,32 +72,7 @@ impl TodoManager {
}
}
#[derive(PartialEq, Clone, Copy)]
pub enum FilterState {
All,
Active,
Completed,
}
#[derive(Debug, PartialEq, Clone)]
pub struct TodoItem {
pub id: Uuid,
pub checked: bool,
pub contents: String,
}
fn App(ctx: Context, props: &()) -> DomTree {
use_init_recoil_root(ctx);
rsx! { in ctx,
div { id: "app", style { "{APP_STYLE}" }
TodoList {}
Footer {}
}
}
}
pub fn TodoList(ctx: Context, props: &()) -> DomTree {
pub fn TodoList(ctx: Context, _props: &()) -> DomTree {
let draft = use_state_new(&ctx, || "".to_string());
let todos = use_recoil_value(&ctx, &TODO_LIST);
let filter = use_recoil_value(&ctx, &FILTER);
@ -154,9 +137,9 @@ pub fn TodoEntry(ctx: Context, props: &TodoEntryProps) -> DomTree {
))
}
pub fn FilterToggles(ctx: Context, props: &()) -> DomTree {
let reducer = use_recoil_context::<TodoManager>(ctx);
let items_left = use_selector(ctx, &TODOS_LEFT);
pub fn FilterToggles(ctx: Context, _props: &()) -> DomTree {
let reducer = use_recoil_callback(ctx, |api| TodoManager(api));
let items_left = use_recoil_value(ctx, &TODOS_LEFT);
let toggles = [
("All", "", FilterState::All),
@ -168,10 +151,9 @@ pub fn FilterToggles(ctx: Context, props: &()) -> DomTree {
rsx!(
li {
class: "{name}"
a {
a { "{name}",
href: "{path}",
onclick: move |_| reducer.set_filter(&filter),
"{name}"
}
}
)
@ -196,7 +178,7 @@ pub fn FilterToggles(ctx: Context, props: &()) -> DomTree {
}
}
pub fn Footer(ctx: Context, props: &()) -> DomTree {
pub fn Footer(ctx: Context, _props: &()) -> DomTree {
rsx! { in ctx,
footer {
class: "info"
@ -212,3 +194,19 @@ pub fn Footer(ctx: Context, props: &()) -> DomTree {
}
}
}
const APP_STYLE: &'static str = include_str!("./todomvc/style.css");
fn App(ctx: Context, _props: &()) -> DomTree {
use_init_recoil_root(ctx);
rsx! { in ctx,
div { id: "app", style { "{APP_STYLE}" }
TodoList {}
Footer {}
}
}
}
fn main() {
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App));
}