Cysharp / R3

The new future of dotnet/reactive and UniRx.
MIT License
2.32k stars 103 forks source link

ReactiveProperty re-subscription #128

Closed lavstudia closed 9 months ago

lavstudia commented 9 months ago

ReactiveProperty with subscriptions (in one place), without changing the value, duplicates the OnValueLang call. How to avoid calling OnValueLang multiple times without changing the value?

Code:

...

_language = new ReactiveProperty<string>("en");

IDisposable languageSub1 = _language.Subscribe(OnValueLang);
languageSub1.Dispose();
IDisposable languageSub2 = _language.Subscribe(OnValueLang);
languageSub2.Dispose();
IDisposable languageSub3 = _language.Subscribe(OnValueLang);
languageSub3.Dispose();

...

private void OnValueLang(string lang)
{
    GD.Print("LANG!!!!!!!! ", lang);
}

Log:

LANG!!!!!!!! en
LANG!!!!!!!! en
LANG!!!!!!!! en
michaelstonis commented 9 months ago

This looks like a case where you want to make use of the Publish operator.

_language = new ReactiveProperty<string>("en");

var languageConnection = _language.Publish();

var languageConnectionDisposable = _language.Connect();

IDisposable languageSub1 = languageConnection.Subscribe(OnValueLang);
languageSub1.Dispose();
IDisposable languageSub2 = languageConnection.Subscribe(OnValueLang);
languageSub2.Dispose();
IDisposable languageSub3 = languageConnection.Subscribe(OnValueLang);
languageSub3.Dispose();

...

languageConnectionDisposable.Dispose();
neuecc commented 9 months ago

Otherwise, use Skip(1).

lavstudia commented 9 months ago

Thanks for the answer! This will work. But there is a feeling that this is not the most elegant solution. 1) What if I have many similar variables? Then I have a lot of code and the effectiveness of using ReactiveProperty is in doubt. 2) Skip(1) - this is much better, but then I’m guaranteed to miss the value and have to go after it myself ReactiveProperty.Value/CurrentValue.

Perhaps I was not entirely able to describe the task.

There is a feeling that there should be a simpler way to indicate that using a ReactiveProperty with a subscription to a value will only respond to changes in this value, and when subsequently unsubscribing and subscribing again (in the context of one class), it will not send the current value at the time of subscription. duplicating the call.

What happens to me (state machine): 1) Go to the state instance 2) I create subscriptions for all necessary ReactiveProperty 3) At some point I move to another state 4) Unsubscribe from all (previously subscribed) ReactiveProperty 5) I do something in a different state 6) Return to the previous state 7) You can come back again on punts 1) ... 6)

This problem can be solved using the following example: https://github.com/chickensoft-games/GoDotCollections/blob/main/Chickensoft.GoDotCollections/src/AutoProp.cs in Action? Sync

neuecc commented 9 months ago

When subscribing for the second time and the current value is not needed, I don't understand what the problem is with using Skip(1). Also, AutoProp.Sync seems to be raise the current value just like Subscribe.

lavstudia commented 9 months ago

For me, the best subject to solve my problem is ReactiveProperty (from the list of Subjects: Subject, ReactiveProperty, ReplaySubject, and ReplayFrameSubject). The default behavior of ReactiveProperty is to get the current value when subscribing. Everything is fine, but why do I need to get the current value from ReactiveProperty every time I subscribe? Subscription should provide new/changed values ​​as they arrive. But at the same time, I immediately get the value when subscribing.

Skip(1) - of course it works, but it seems redundant and looks like a crutch.

1) There must be another kind of Subject that does not give a value when subscribed by default. Because if I really need the current value, I can get it myself ReactiveProperty.Value 2) Alternatively, you can implement another Subscribe option, which will not immediately transmit the current value.

neuecc commented 9 months ago

Every Subscribe is independent, your first sample is a different Subscribe, so it would be natural to raise an initial value.