Skip to content

Commit

Permalink
Do not subscribe multiple times to a same dependency (#7)
Browse files Browse the repository at this point in the history
* Do not subscribe multiple times to a same dependency

* cargo fmt
  • Loading branch information
lukechu10 authored Mar 7, 2021
1 parent c99b9ce commit 43cbb34
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 6 deletions.
2 changes: 1 addition & 1 deletion maple-core-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl ToTokens for HtmlTree {
}

/// A macro for ergonomically creating complex UI structures.
///
///
/// TODO: write some more docs
#[proc_macro]
pub fn template(input: TokenStream) -> TokenStream {
Expand Down
2 changes: 1 addition & 1 deletion maple-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! # Maple API Documentation
//!
//! Maple is a VDOM-less web library with fine-grained reactivity.
//!
//!
//! This is the API docs for maple. If you are looking for the usage docs, checkout the [README](https://github.com/lukechu10/maple).
//!
//! ## Supported Targets
Expand Down
77 changes: 73 additions & 4 deletions maple-core/src/reactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,18 @@ impl<T> Signal<T> {
}

fn observe(&mut self, handler: Rc<Computation>) {
self.observers.push(handler);
// make sure handler is not already in self.observers
if self
.observers
.iter()
.find(|observer| {
observer.as_ref() as *const Computation == handler.as_ref() as *const Computation
/* do reference equality */
})
.is_none()
{
self.observers.push(handler);
}
}

fn update(&mut self, new_value: T) {
Expand All @@ -44,14 +55,14 @@ thread_local! {

/// Creates a new signal.
/// The function will return a pair of getter/setters to modify the signal and update corresponding dependencies.
///
///
/// # Example
/// ```rust
/// use maple_core::prelude::*;
///
///
/// let (state, set_state) = create_signal(0);
/// assert_eq!(*state(), 0);
///
///
/// set_state(1);
/// assert_eq!(*state(), 1);
/// ```
Expand Down Expand Up @@ -193,6 +204,64 @@ mod tests {
assert_eq!(*double(), 4);
}

#[test]
#[should_panic(expected = "cannot create cyclic dependency")]
fn cyclic_effects_fail() {
let (state, set_state) = create_signal(0);

create_effect({
let state = state.clone();
let set_state = set_state.clone();
move || {
set_state(*state() + 1);
}
});

set_state(1);
}

#[test]
#[should_panic(expected = "cannot create cyclic dependency")]
fn cyclic_effects_fail_2() {
let (state, set_state) = create_signal(0);

create_effect({
let state = state.clone();
let set_state = set_state.clone();
move || {
let value = *state();
set_state(value + 1);
}
});

set_state(1);
}

#[test]
fn effect_should_subscribe_once() {
let (state, set_state) = create_signal(0);

// use a Cell instead of a signal to prevent circular dependencies
// TODO: change to create_signal once explicit tracking is implemented
let counter = Rc::new(Cell::new(0));

create_effect({
let counter = counter.clone();
move || {
counter.set(counter.get() + 1);

// call state() twice but should subscribe once
state();
state();
}
});

assert_eq!(counter.get(), 1);

set_state(1);
assert_eq!(counter.get(), 2);
}

#[test]
fn memo() {
let (state, set_state) = create_signal(0);
Expand Down

0 comments on commit 43cbb34

Please sign in to comment.