mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
feat: add Scope::batch()
(#711)
This commit is contained in:
parent
9d142758ec
commit
42a58855a0
4 changed files with 73 additions and 7 deletions
|
@ -62,6 +62,7 @@ pub(crate) struct Runtime {
|
|||
RefCell<SecondaryMap<NodeId, RefCell<FxIndexSet<NodeId>>>>,
|
||||
pub pending_effects: RefCell<Vec<NodeId>>,
|
||||
pub resources: RefCell<SlotMap<ResourceId, AnyResource>>,
|
||||
pub batching: Cell<bool>,
|
||||
}
|
||||
|
||||
// This core Runtime impl block handles all the work of marking and updating
|
||||
|
@ -248,13 +249,17 @@ impl Runtime {
|
|||
|
||||
pub(crate) fn run_effects(runtime_id: RuntimeId) {
|
||||
_ = with_runtime(runtime_id, |runtime| {
|
||||
let effects = runtime.pending_effects.take();
|
||||
for effect_id in effects {
|
||||
runtime.update_if_necessary(effect_id);
|
||||
}
|
||||
runtime.run_your_effects();
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn run_your_effects(&self) {
|
||||
let effects = self.pending_effects.take();
|
||||
for effect_id in effects {
|
||||
self.update_if_necessary(effect_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dispose_node(&self, node: NodeId) {
|
||||
self.node_sources.borrow_mut().remove(node);
|
||||
self.node_subscribers.borrow_mut().remove(node);
|
||||
|
|
|
@ -442,6 +442,25 @@ impl Scope {
|
|||
.ok()
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// Batches any reactive updates, preventing effects from running until the whole
|
||||
/// function has run. This allows you to prevent rerunning effects if multiple
|
||||
/// signal updates might cause the same effect to run.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the runtime this scope belongs to has already been disposed.
|
||||
pub fn batch<T>(&self, f: impl FnOnce() -> T) -> T {
|
||||
with_runtime(self.runtime, move |runtime| {
|
||||
runtime.batching.set(true);
|
||||
let val = f();
|
||||
runtime.batching.set(false);
|
||||
runtime.run_your_effects();
|
||||
val
|
||||
})
|
||||
.expect(
|
||||
"tried to run a batched update in a runtime that has been disposed",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ScopeDisposer {
|
||||
|
|
|
@ -1912,7 +1912,7 @@ impl NodeId {
|
|||
runtime.mark_dirty(*self);
|
||||
|
||||
// notify subscribers
|
||||
if updated.is_some() {
|
||||
if updated.is_some() && !runtime.batching.get() {
|
||||
Runtime::run_effects(runtime_id);
|
||||
};
|
||||
updated
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#[cfg(not(feature = "stable"))]
|
||||
use leptos_reactive::{
|
||||
create_isomorphic_effect, create_memo, create_runtime, create_scope,
|
||||
create_signal,
|
||||
create_isomorphic_effect, create_memo, create_runtime, create_rw_signal,
|
||||
create_scope, create_signal, SignalSet,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "stable"))]
|
||||
|
@ -91,3 +91,45 @@ fn untrack_mutes_effect() {
|
|||
})
|
||||
.dispose()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stable"))]
|
||||
#[test]
|
||||
fn batching_actually_batches() {
|
||||
use std::{cell::Cell, rc::Rc};
|
||||
|
||||
create_scope(create_runtime(), |cx| {
|
||||
let first_name = create_rw_signal(cx, "Greg".to_string());
|
||||
let last_name = create_rw_signal(cx, "Johnston".to_string());
|
||||
|
||||
// simulate an arbitrary side effect
|
||||
let count = Rc::new(Cell::new(0));
|
||||
|
||||
create_isomorphic_effect(cx, {
|
||||
let count = count.clone();
|
||||
move |_| {
|
||||
_ = first_name();
|
||||
_ = last_name();
|
||||
|
||||
count.set(count.get() + 1);
|
||||
}
|
||||
});
|
||||
|
||||
// runs once initially
|
||||
assert_eq!(count.get(), 1);
|
||||
|
||||
// individual updates run effect once each
|
||||
first_name.set("Alice".to_string());
|
||||
assert_eq!(count.get(), 2);
|
||||
|
||||
last_name.set("Smith".to_string());
|
||||
assert_eq!(count.get(), 3);
|
||||
|
||||
// batched effect only runs twice
|
||||
cx.batch(move || {
|
||||
first_name.set("Bob".to_string());
|
||||
last_name.set("Williams".to_string());
|
||||
});
|
||||
assert_eq!(count.get(), 4);
|
||||
})
|
||||
.dispose()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue