Feat: major overhaul to diffing

This commit is contained in:
Jonathan Kelley committed 2021-05-15 12:03:08 -04:00
1 parent c809095124
commit 9810feebf5
37 files changed
+1470 -1129

No files matched your search

+118 -9
View File
@@ -1,10 +1,119 @@
// mod hooks;
// pub use hooks::use_context;
use std::collections::HashMap;
// pub mod prelude {
// use dioxus_core::prelude::Context;
// pub fn use_state<T, G>(ctx: &Context<G>, init: impl Fn() -> T) -> (T, impl Fn(T)) {
// let g = init();
// (g, |_| {})
// }
// }
use dioxus_core::prelude::*;
/*
a form of use_state explicitly for map-style collections (BTreeMap, HashMap, etc).
Why?
---
Traditionally, it's possible to use the "use_state" hook for collections in the React world.
Adding a new entry would look something similar to:
```js
let (map, set_map) = useState({});
set_map({ ...map, [key]: value });
```
The new value then causes the appropriate update when passed into children.
This is moderately efficient because the fields of the map are moved, but the data itself is not cloned.
However, if you used similar approach with Dioxus:
```rust
let (map, set_map) = use_state(ctx, || HashMap::new());
set_map({
let mut newmap = map.clone();
newmap.set(key, value);
newmap
})
```
Unfortunately, you'd be cloning the entire state every time a value is changed. The obvious solution is to
wrap every element in the HashMap with an Rc. That way, cloning the HashMap is on par with its JS equivalent.
Fortunately, we can make this operation even more efficient in Dioxus, leveraging the borrow rules of Rust.
This hook provides a memoized collection, memoized setters, and memoized getters. This particular hook is
extremely powerful for implementing lists and supporting core state management needs for small apps.
If you need something even more powerful, check out the dedicated atomic state management Dioxus Dataflow, which
uses the same memoization on top of the use_context API.
Here's a fully-functional todo app using the use_map API:
```rust
static TodoList: FC<()> = |ctx, props| {
let todos = use_map(ctx, || HashMap::new());
let input = use_ref(|| None);
ctx.render(rsx!{
div {
button {
"Add todo"
onclick: move |_| {
let new_todo = TodoItem::new(input.contents());
todos.insert(new_todo.id.clone(), new_todo);
input.clear();
}
}
button {
"Clear todos"
onclick: move |_| todos.clear()
}
input {
placeholder: "What needs to be done?"
ref: input
}
ul {
{todos.iter().map(|todo| rsx!(
li {
key: todo.id
span { "{todo.content}" }
button {"x", onclick: move |_| todos.remove(todo.key.clone())}
}
))}
}
}
})
}
```
*/
fn use_map() {}
// a form of "use_state" that allows collection memoization
// Elements are received as Rc<T> in case the underlying collection is shuffled around
// Setters/getters can be generated
fn use_collection<'a, T: Collection>(
ctx: &Context<'a>,
f: impl Fn() -> T,
) -> CollectionHandle<'a, T> {
ctx.use_hook(
|| {},
|h| {
//
CollectionHandle {
_p: Default::default(),
}
},
|h| {},
)
}
struct CollectionMemo {}
struct CollectionHandle<'a, T: Collection> {
_p: std::marker::PhantomData<&'a T>,
}
trait Collection {}
impl<K, V> Collection for std::collections::HashMap<K, V> {}
struct MapCollection<K, V> {
inner: HashMap<K, V>,
}
impl<K, V> MapCollection<K, V> {
fn set(&self, key: K, val: V) {
//
}
}