Best RX Practice: Choose With Side Effect or Use Subscription?

I am converting events (paging events from buttons) to IObservable and receiving the result from the service asynchronously.

As a side effect, I need to update the child mode. I have two solutions:

  • Side effect when choosing:

        //Converting events to a "stream" of search results.
        IObservable<SearchResult> resultsFromPageChange = Observable.FromEventPattern<EventArgs>(this,
            "PageChangedEvent")
            .Throttle(TimeSpan.FromMilliseconds(500))
            .Select(async ev =>
             {
                 var input = new SearchResultInput()
                 {
                     PageSize = PageSize,
                     PageIndex = PageIndex,
                     SearchOptions = _currentSearchOptions,
                     SearchText = SearchText.Value
                 };
                 var result = await GetPagedComponents(input);
                 //Side effect
                 ActivateAttributesView(result.Components.FirstOrDefault());
    
                 return result;
             }).Switch(); //flatten and take most recent.
    
          

  • Do side effect on subscription:

        //Converting events to a "stream" of search results.
        IObservable<SearchResult> resultsFromPageChange = Observable.FromEventPattern<EventArgs>(this,
            "PageChangedEvent")
            .Throttle(TimeSpan.FromMilliseconds(500))
            .Select(async ev =>
            {
                var input = new SearchResultInput()
                {
                    PageSize = PageSize,
                    PageIndex = PageIndex,
                    SearchOptions = _currentSearchOptions,
                    SearchText = SearchText.Value
                };
                return await GetPagedComponents(input);
            }).Switch(); //flatten and take most recent.
    
        //Do side effect in the subscribe
        resultsFromPageChange.Subscribe(x =>
        {
            if (x != null)
                ActivateAttributesView(x.Components.FirstOrDefault());
        });
    
          

Both methods work. Which solution should I choose and why?

THX.

Because the question is why this creates values ​​at all, here's the complete code:

        //Converting events to a "stream" of search results.
        IObservable<SearchResult> resultsFromPageChange = Observable.FromEventPattern<EventArgs>(this,
            "PageChangedEvent")
            .Throttle(TimeSpan.FromMilliseconds(500))
            .Select(async ev =>
            {

                var input = new SearchResultInput()
                {
                    PageSize = PageSize,
                    PageIndex = PageIndex,
                    SearchOptions = _currentSearchOptions,
                    SearchString = SearchString.Value
                };

                return await SearchComponentsPaged(input);

            }).Switch(); //flatten and take most recent.

        SearchString = new ReactiveProperty<string>(""); //Bound to TextBox.Text 

        //Create a "stream" of search results from a string given by user (SearchString)
        SearchResult = SearchString
            .SetValidateNotifyError(s => _componentDataService.ValidateSearchStringLength(s).Errors)
            .Throttle(TimeSpan.FromMilliseconds(500))
            .Select(async term =>
            {
                var input = new SearchResultInput()
                    {
                        PageSize = PageSize,
                        PageIndex = PageIndex,
                        SearchOptions = _currentSearchOptions,
                        SearchString = term
                    };

                return await SearchComponentsPaged(input);

            })
            .Switch()
            .Merge(resultsFromPageChange) //Merge the result of paging and text changing.  
            .ToReactiveProperty();

        //Update Attributes view
        SearchResult.Subscribe(searchResult =>
        {
            if (searchResult != null)
            {
                ActivateAttributesView(searchResult.Components.FirstOrDefault());
                SearchResult.Value.TotalItemsCount = searchResult.TotalItemsCount;
            }

        });

      

This is actually sending a search query to the DB when the search string changes and getting page-by-page results OR getting another page with the same search string when the PageChangedEvent page is received. Does .Merge (...) include a subscription?

+3


source to share


2 answers


I would go with my second solution. It is more flexible as different subscribers can choose different side effects. It also decouples issues, the Rx request generates data and the subscriber uses the data as he wants.



+4


source


This is the best practice for picking and where to be pure functions (side effect free). This shows intent much more clearly.



Also, since observables can be combined and you can reuse the data stream elsewhere, it's best to make the side effects explicit.

+1


source







All Articles