mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
Merge pull request #2974 from leptos-rs/more-stores
Improve efficiency of keyed stores
This commit is contained in:
commit
2bdacf636e
3 changed files with 34 additions and 34 deletions
|
@ -95,7 +95,10 @@ pub fn App() -> impl IntoView {
|
||||||
<input type="submit"/>
|
<input type="submit"/>
|
||||||
</form>
|
</form>
|
||||||
<ol>
|
<ol>
|
||||||
<For each=move || store.todos().iter_keyed() key=|row| row.id().get() let:todo>
|
// because `todos` is a keyed field, `store.todos()` returns a struct that
|
||||||
|
// directly implements IntoIterator, so we can use it in <For/> and
|
||||||
|
// it will manage reactivity for the store fields correctly
|
||||||
|
<For each=move || store.todos() key=|row| row.id().get() let:todo>
|
||||||
<TodoRow store todo/>
|
<TodoRow store todo/>
|
||||||
</For>
|
</For>
|
||||||
|
|
||||||
|
@ -154,17 +157,14 @@ fn TodoRow(
|
||||||
|
|
||||||
<button on:click=move |_| {
|
<button on:click=move |_| {
|
||||||
let id = todo.id().get();
|
let id = todo.id().get();
|
||||||
store
|
store.todos().write().retain(|todo| todo.id != id);
|
||||||
.todos()
|
|
||||||
.update(|todos| {
|
|
||||||
todos.remove(id);
|
|
||||||
});
|
|
||||||
}>"X"</button>
|
}>"X"</button>
|
||||||
<input
|
<input
|
||||||
type="date"
|
type="date"
|
||||||
prop:value=move || {
|
prop:value=move || {
|
||||||
todo.status().scheduled_for_date().map(|n| n.get().to_string())
|
todo.status().scheduled_for_date().map(|n| n.get().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
class:hidden=move || !todo.status().scheduled_for()
|
class:hidden=move || !todo.status().scheduled_for()
|
||||||
on:change:target=move |ev| {
|
on:change:target=move |ev| {
|
||||||
if let Some(date) = todo.status().scheduled_for_date() {
|
if let Some(date) = todo.status().scheduled_for_date() {
|
||||||
|
|
|
@ -95,13 +95,7 @@ where
|
||||||
{
|
{
|
||||||
type Value = T;
|
type Value = T;
|
||||||
type Reader = Mapped<Inner::Reader, T>;
|
type Reader = Mapped<Inner::Reader, T>;
|
||||||
type Writer = KeyedSubfieldWriteGuard<
|
type Writer = MappedMut<WriteGuard<ArcTrigger, Inner::Writer>, T>;
|
||||||
Inner,
|
|
||||||
Prev,
|
|
||||||
K,
|
|
||||||
T,
|
|
||||||
MappedMut<WriteGuard<ArcTrigger, Inner::Writer>, T>,
|
|
||||||
>;
|
|
||||||
type UntrackedWriter =
|
type UntrackedWriter =
|
||||||
MappedMut<WriteGuard<ArcTrigger, Inner::UntrackedWriter>, T>;
|
MappedMut<WriteGuard<ArcTrigger, Inner::UntrackedWriter>, T>;
|
||||||
|
|
||||||
|
@ -125,11 +119,7 @@ where
|
||||||
let path = self.path().into_iter().collect::<StorePath>();
|
let path = self.path().into_iter().collect::<StorePath>();
|
||||||
let trigger = self.get_trigger(path.clone());
|
let trigger = self.get_trigger(path.clone());
|
||||||
let guard = WriteGuard::new(trigger, self.inner.writer()?);
|
let guard = WriteGuard::new(trigger, self.inner.writer()?);
|
||||||
let guard = MappedMut::new(guard, self.read, self.write);
|
Some(MappedMut::new(guard, self.read, self.write))
|
||||||
Some(KeyedSubfieldWriteGuard {
|
|
||||||
inner: self.clone(),
|
|
||||||
guard: Some(guard),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn untracked_writer(&self) -> Option<Self::UntrackedWriter> {
|
fn untracked_writer(&self) -> Option<Self::UntrackedWriter> {
|
||||||
|
@ -336,15 +326,21 @@ where
|
||||||
type Value = T;
|
type Value = T;
|
||||||
|
|
||||||
fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
|
fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
|
||||||
self.writer()
|
let guard = self.writer()?;
|
||||||
|
Some(KeyedSubfieldWriteGuard {
|
||||||
|
inner: self.clone(),
|
||||||
|
guard: Some(guard),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_write_untracked(
|
fn try_write_untracked(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<impl DerefMut<Target = Self::Value>> {
|
) -> Option<impl DerefMut<Target = Self::Value>> {
|
||||||
self.writer().map(|mut writer| {
|
let mut guard = self.writer()?;
|
||||||
writer.untrack();
|
guard.untrack();
|
||||||
writer
|
Some(KeyedSubfieldWriteGuard {
|
||||||
|
inner: self.clone(),
|
||||||
|
guard: Some(guard),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -642,18 +638,21 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Inner, Prev, K, T> KeyedSubfield<Inner, Prev, K, T>
|
impl<Inner, Prev, K, T> IntoIterator for KeyedSubfield<Inner, Prev, K, T>
|
||||||
where
|
where
|
||||||
Self: Clone,
|
Self: Clone,
|
||||||
for<'a> &'a T: IntoIterator,
|
for<'a> &'a T: IntoIterator,
|
||||||
Inner: StoreField<Value = Prev>,
|
Inner: Clone + StoreField<Value = Prev> + 'static,
|
||||||
Prev: 'static,
|
Prev: 'static,
|
||||||
K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
|
K: Debug + Send + Sync + PartialEq + Eq + Hash + 'static,
|
||||||
T: IndexMut<usize>,
|
T: IndexMut<usize> + 'static,
|
||||||
T::Output: Sized,
|
T::Output: Sized,
|
||||||
{
|
{
|
||||||
|
type Item = AtKeyed<Inner, Prev, K, T>;
|
||||||
|
type IntoIter = StoreFieldKeyedIter<Inner, Prev, K, T>;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn iter_keyed(self) -> StoreFieldKeyedIter<Inner, Prev, K, T> {
|
fn into_iter(self) -> StoreFieldKeyedIter<Inner, Prev, K, T> {
|
||||||
// reactively track changes to this field
|
// reactively track changes to this field
|
||||||
let trigger = self.get_trigger(self.path().into_iter().collect());
|
let trigger = self.get_trigger(self.path().into_iter().collect());
|
||||||
trigger.track();
|
trigger.track();
|
||||||
|
|
|
@ -60,20 +60,21 @@ impl TriggerMap {
|
||||||
pub struct FieldKeys<K> {
|
pub struct FieldKeys<K> {
|
||||||
spare_keys: Vec<StorePathSegment>,
|
spare_keys: Vec<StorePathSegment>,
|
||||||
current_key: usize,
|
current_key: usize,
|
||||||
keys: HashMap<K, (StorePathSegment, usize)>,
|
keys: FxHashMap<K, (StorePathSegment, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K> FieldKeys<K>
|
impl<K> FieldKeys<K>
|
||||||
where
|
where
|
||||||
K: Debug + Hash + PartialEq + Eq,
|
K: Debug + Hash + PartialEq + Eq,
|
||||||
{
|
{
|
||||||
pub fn new(from_iter: impl IntoIterator<Item = K>) -> Self {
|
pub fn new(from_keys: Vec<K>) -> Self {
|
||||||
let mut current_key = 0;
|
let mut keys = FxHashMap::with_capacity_and_hasher(
|
||||||
let mut keys = HashMap::new();
|
from_keys.len(),
|
||||||
for (idx, key) in from_iter.into_iter().enumerate() {
|
Default::default(),
|
||||||
let segment = current_key.into();
|
);
|
||||||
|
for (idx, key) in from_keys.into_iter().enumerate() {
|
||||||
|
let segment = idx.into();
|
||||||
keys.insert(key, (segment, idx));
|
keys.insert(key, (segment, idx));
|
||||||
current_key += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -104,7 +105,7 @@ where
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, key)| (key, idx))
|
.map(|(idx, key)| (key, idx))
|
||||||
.collect::<HashMap<K, usize>>();
|
.collect::<FxHashMap<K, usize>>();
|
||||||
|
|
||||||
// remove old keys and recycle the slots
|
// remove old keys and recycle the slots
|
||||||
self.keys.retain(|key, old_entry| match new_keys.get(key) {
|
self.keys.retain(|key, old_entry| match new_keys.get(key) {
|
||||||
|
|
Loading…
Reference in a new issue