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

Suggestion: R3 signals (ReactiveProperty++) #283

Open
fedeAlterio opened this issue Dec 21, 2024 · 2 comments
Open

Suggestion: R3 signals (ReactiveProperty++) #283

fedeAlterio opened this issue Dec 21, 2024 · 2 comments

Comments

@fedeAlterio
Copy link

fedeAlterio commented Dec 21, 2024

Hey!

I love this rebirth of Rx and everything you did in this repo.
I was wondering if angular signals could be a good addition for this library.
Signals are pretty much the same a ReactiveProperties, but with the (huge) plus of automatically recompute the value based on other properties (Computed signals).

I already created a possible implementation based completely on R3, and I think its great.
Maybe could be integrated here? What you think?

Thank you!

@fedeAlterio fedeAlterio changed the title Suggestion: R3 signals Suggestion: R3 signals (ReactiveProperty++) Dec 21, 2024
@neuecc
Copy link
Member

neuecc commented Dec 23, 2024

Thank you for the suggestion.
I'm not very familiar with Angular, so I appreciate getting these good ideas - they're helpful.
Wouldn't ReadOnlyReactiveProperty satisfy the needs of Computed properties?
That said, it seems like a system with many additional ideas that make it an improved/enhanced version.

Since I don't think this should be a core functionality, I believe it would be better to keep it as an external extension that people can optionally use if they want to.

@fedeAlterio
Copy link
Author

fedeAlterio commented Dec 23, 2024

Yes probably you are right about the external extension.

With ReactiveProperties and ReadOnlyReactiveProperty you can do everything, sometimes can be less readable and more difficult.
The main difference from computed signals and ReadonlyReactiveProperty is that, with computedSignals, you don't have to specify which are the properties you depend by, they will be automatically tracked. Basically in one function you are specifiyng both the "dependencies" and the computation.

I created a small comparison:

Signals

public class ExampleWithSignals
{
    public ExampleWithSignals()
    {
        ComputedFromName = Signal.Computed(() => $"Computed value is {Name.Value}");
        IsNameValid = Signal.AsyncComputed(async cancellationToken =>
        {
            var name = Name.Value;
            await Task.Delay(1000, cancellationToken); 
            return !string.IsNullOrWhiteSpace(name);
        }, false, ConcurrentChangeStrategy.CancelCurrent);

        // The idea is that is signals we can execute arbitrary functions, so we can use if, switch, function calls etc
        // The properties will be automatically tracked. 
        // Same with async functions
        CanLogin = Signal.Computed(() =>
        {
            // If IsNameValid.IsComputing is true, we dont even subscribe to IsNameValid changes
            // If IsNameValid.IsComputing is true, and IsNameValid.Value is false. we dont even subscribe to Password changes
            if (IsNameValid.IsComputing.Value || !IsNameValid.Value)
            {
                return false;
            }

            return !string.IsNullOrWhiteSpace(Password.Value);
        });

        // This is equivalent to the Signal.Computed above
        // Is usefull if we want to apply some other operators before converting the observable to a signal
        CanLogin = Signal.ComputedObservable(() =>
        {
            if (IsNameValid.IsComputing.Value || !IsNameValid.Value)
            {
                return false;
            }

            return !string.IsNullOrWhiteSpace(Password.Value);
        })
        .ToSignal();
    }

    Signal<string> Name { get; } = new("");
    Signal<string> Password { get; } = new("");
    IReadOnlySignal<string> ComputedFromName { get; }
    IAsyncReadOnlySignal<bool> IsNameValid { get; }
    IReadOnlySignal<bool> CanLogin { get; }
    IReadOnlySignal<(string name, string password)> NamePasswordTuple { get; set; }
}

ReactiveProperties

public class ExampleWithReactiveProperties
{
    public ExampleWithReactiveProperties()
    {
        ComputedFromName = Name.Select(x => $"Computed value is {x}")
                               .ToReadOnlyReactiveProperty("");

        IsNameValid = ComputedFromName.SelectAwait(async (name, cancellationToken) =>
        {
            IsNameValidIsExecuting.Value = true;

            try
            {
                await Task.Delay(1000, cancellationToken); // simulate som
                return !string.IsNullOrWhiteSpace(name);
            }
            finally
            {
                IsNameValidIsExecuting.Value = false;
            }
        }, AwaitOperation.Switch).ToReadOnlyReactiveProperty();


        // Here I am trying to reproduce exactly what copmuted signals do
        // Of course this is not how I would write this logic without signals :)
        CanLogin = IsNameValidIsExecuting.Select(isExecuting => isExecuting switch
        {
            true => Observable.Return(false),
            false => IsNameValid.Select(isNameValid => isNameValid switch
            {
                false =>  Observable.Return(false),
                true => Password.Select(p => !string.IsNullOrWhiteSpace(p))
            }).Switch()
        }).Switch()
        .ToReadOnlyReactiveProperty();
    }

    ReactiveProperty<string> Name { get; } = new("");
    ReactiveProperty<string> Password { get; } = new("");
    ReadOnlyReactiveProperty<string> ComputedFromName { get; }
    ReadOnlyReactiveProperty<bool> IsNameValid { get; }
    ReactiveProperty<bool> IsNameValidIsExecuting { get; } = new(false);
    ReadOnlyReactiveProperty<bool> CanLogin { get; }
}

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