dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.41k stars 10k forks source link

Consider Using IObservable<T> + Reactive Extensions (Rx) for Events #16284

Closed RehanSaeed closed 5 years ago

RehanSaeed commented 6 years ago

According to the docs you can subscribe and raise events like so:

<button @onclick(OnClick)>Click me (child component)</button>

@functions {
    public Action OnSomeEvent { get; set; }

    private void OnClick()
    {
        OnSomeEvent?.Invoke();
    }
}

It's interesting that you are not using C# events. It would be great if IObservable<T> could somehow be used so you could easily use Reactive Extensions (Rx) to debounce events being raised or any of the other 101 other uses for Rx.

How do you unsubscribe from an event in Blazor? When a component is torn down, are events unsubscribed for you? IObservable<T> uses the IDisposable pattern quite nicely for this purpose.

rstropek commented 6 years ago

This description should just demonstrate some basic fundamentals about data binding. In practice, you would probably work with a state object. There, you can use events or reactive programming.

RehanSaeed commented 6 years ago

This is what I'm imagining:

<button id="foo">Click me (child component)</button>

@functions {
    private Subject<T> someEvent;
    public IObservable<T> WhenSomeEvent { get; set; }

    public void OnInit()
    {
        var subscription = this.foo.onclick
            .Sample(TimeSpan.FromSeconds(3))
            .Subscribe(x => {
                someEvent.OnNext(x);
            });

        subscription.Dispose(); // Unregister the event.
    }
}
SteveSandersonMS commented 6 years ago

It's interesting that you are not using C# events.

I'm not sure how we'd use C# events for this. Where does the event itself live? We'd have to have some kind of object to represent the <button>, but there's nothing like that, and it's not the kind of pattern commonplace in SPA frameworks. I'd consider the current design to have a lot less overhead.

It would be great if IObservable could somehow be used so you could easily use Reactive Extensions (Rx) to debounce events being raised or any of the other 101 other uses for Rx.

Ideally I'd hope you could do something like:

<button @onclick(Trigger(someObservable))>Click me</button>

@functions
{
    MyObservable someObservable = new MyObservable();
}

... where Trigger is a method that returns an action that knows how to cause a MyObservable to issue a notification.

Is something like that possible with Rx?

How do you unsubscribe from an event in Blazor?

Implement IDisposable (e.g., @implements IDisposable at the top of the file). Then put your unsubscription logic in your Dispose method. It gets called when the component is removed.

I hope this answers the questions! Our goal is certainly to compose well with libraries like Rx, but we're not expecting to be coupled specifically to any of them.

feldrim commented 6 years ago

Although the issue is closed, I wonder how events like "text changed" on a text box can be handled. A button can trigger an event but how a text change event implemented is a mystery to me.

I came across the problem while trying to add a search bar feature on a data table. When user types more than 3 letters in a text box, ""text changed event" should be triggered after 300 milliseconds. But I couldn't manage it. It might be most probably due to my lack of knowledge on Blazor, Razor syntax or C# in general but I believe there must be a way about event handling needs somewhere there.