Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] Combine signals with timed events, such as debounce or throttle #128

Open
axos88 opened this issue Nov 1, 2024 · 3 comments
Open

Comments

@axos88
Copy link

axos88 commented Nov 1, 2024

I'm coming from the Angular world, and having rxjs operators is a blast.

After reading the book I'm not quite sure how to implement some of the operators, such as combining signal updates with wall-clock-timed updates, such as throttling or debouncing (yes, leptos-use has them, but a more detailed explanation on how it actually works would be welcome), and doing something like zip, creating a signal that zips a bunch of other signals, and waits until they all update before updating itself.

let (a, a_set) = signal(0);
let (b, b_set) = signal(0);
let (c, c_set) = signal(0);

let zipped = ????(move || (a(), b(), c()));
a_set(1);
b_set(2);
c_set(3); // zipped updates with (1,2,3)
a_set(2);
b_set(3);
c_set(4); // zipped updates with (2,3,4)

@gbj
Copy link
Contributor

gbj commented Nov 1, 2024

It's important to note that the equivalent in Rust to rxjs's Observables is the Stream trait in the futures crate.

In one sense, what you're asking may be more obvious than you think:

#[component]
pub fn App() -> impl IntoView {
    let (a, a_set) = signal(0);
    let (b, b_set) = signal(0);
    let (c, c_set) = signal(0);

    let zipped = move || (a(), b(), c());
    a_set(1);
    b_set(2);
    c_set(3); 
    a_set(2);
    b_set(3);
    c_set(4);
    Effect::new(move |_| {
        leptos::logging::log!("{:?}", zipped());
    });
}

For me, on 0.7/git main, this logs (2, 3, 4). (It's more or less the same thing on 0.6, but you used plain signal() so I assume you're using 0.7)

This highlights a very important difference between signals and streams. (AFAIK this is also true of Angular signals vs. rxjs observables, but I have not used them enough to know.) Signals are designed to notify effects as few times as possible, and use effects to synchronize their current value with the outside world. Unlike streams, they are allowed to drop intermediate values. This makes the more efficient for something like UI state (in which you only care about the latest value, and you want to drop any preceding values and just update to the latest), but makes them fundamentally incorrect if you're trying to model what a stream does, which is to include every item you send to it.

So, depends on the use case, but either what you wrote is already correct, or you should use some kind of Stream instead.

@axos88
Copy link
Author

axos88 commented Nov 2, 2024

I believe your example works only because you create the effect after writing to the signals. Try moving the effect to after the creation of zipped, and possibly move the signal setting to a different timeplane - push of a button or something like that.

You may be on to something with streams - but i again have no idea how to integrate them into leptos's reactive system.

So that would be worth mentioning in the book as well?

@gbj
Copy link
Contributor

gbj commented Nov 2, 2024

I believe your example works only because you create the effect after writing to the signals. Try moving the effect to after the creation of zipped,

Same result on 0.7, logs (2, 3, 4). Effects are scheduled slightly differently on 0.6 and prior but it still logs (2, 3, 4), so not sure what you mean.

You may be on to something with streams - but i again have no idea how to integrate them into leptos's reactive system.

So that would be worth mentioning in the book as well?

Could be worth reading this discussion. I guess I can increment my count of how many times anyone's asked about this from one (in my reply there) to two 😄

Not everything can fit into the book, of course. But searching the docs for "stream" will also link you to the ways of converting between signals and streams. (See more in the discussion above.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants