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

Asynchronous action handlers vs. action-reducer-effect-action-reducer - why the difference? #267

Open
szalapski opened this issue Nov 12, 2021 · 2 comments

Comments

@szalapski
Copy link

szalapski commented Nov 12, 2021

After implementing the same state management using both Fluxor and Blazor-State, it strikes me that the most significant difference is that Blazor-State combines the notions of Reducers and Effects into one thing, called "Handlers". In Blazor-State, a handler is by default asynchronous, so that you can dispatch (called "Send" in Blazor-State) an action, then its handler can modify the state, then call out to a web service or other "outside" thing asynchronous, then modify the state again. So, for a routine action that gets data from a service, in Blazor-State, I need only one action and one handler. The caller can do things while the handler starts running, then await the single dispatch call when we want to react to it. On the await, the component can (will) rerender with the newly changed state (e.g. to show a Loading spinner based on the state) and then after the await completes, the component can (will) rerender with the newly changed state (e.g. to remove the spinner and show the new data from the state).

Fluxor has separate Effects and Reducers, so to do the same thing in Fluxor, I need two separate actions and thus two reducers, and an effect: One parameterless action that results in a reducer and invokes the Effect, then the Effect calls an outside service in a background task that my component can't see, then the effect dispatches a second action, whose reducer can change the state with the newly received data.

My naive look at things makes me appreciate the simpler model of Blazor-State with its combined effects and reducers--I don't see what the added complexity of separating them (in Fluxor) gives me as a benefit.

Your good friend Mr. P. Morris wants to keep Fluxor to the same pattern established in Redux/Flux and so isn't enamored with combining them. But more interestingly for Blazor-State, he says: "I think you have actually found a bug in Blazor State rather than a feature. As the changes are not being notified to subscribers, then you have to have a call to StateHasChanged before the await in Step 2 in order to see the middle changes, but then you are putting UI logic into your reducer and also tying your logic to a single UI framework. Essentially, your state is getting concerned with rendering details, and that's not a good mix."

But I see it as a feature and not a bug; there are many cases where I might want to change my state, let the components render, then change the state again and let them render again. It seems that narrower case is common enough to justify it.

I also don't see a confusion of concerns: the handler (what he calls reducer) need not call StateHasChanged, but it need only await the first asynchronous as in any ordinary asynchronous fashion. The component will automatically rerender on the first await.

Now there is nowhere in this pattern to allow any intermediate changes to cause a rerender--say I make three changes to the state, and await the first and second changes; the second change will not cause a rerender. How would you handle such a need to rerender if I wanted to update the state three times in a handler?

And finally, reacting to Mr. P. Morris, do you think this is a bug or a good feature? And is it a good feature just because it is useful, or does it actually follow from some design/architecture decision to break from the Flux pattern?

(This is spurred by a discussion in the Fluxor issues.)

@StevenTCramer
Copy link
Collaborator

If you go back in history of the two repositories you will see I started Blazor-State a few days before Pete started Fluxor. We hadn't talked to each other in a while and both thought this concept was the most import thing to build for Blazor. A few days in we chatted. I thought he had seen my repo and was trolling when he said what he was working on. :) We share many of the same philosophies, yet we offer enough differences to hopefully support the community and give valuable options.

Not distinguishing between what Pete calls "effects and reducers" was a specific design decision. I think the developer should be aware of the differences in their handlers but I didn't and still don't think it requires a structural change in the architecture. Handlers work fine for both.

The concern in the thread seems to be about when subscriptions are automatically fired. What Pete calls a bug and what you call a feature, I don't think it is a bug nor a feature. It is a byproduct of how Blazor is implemented.

I do NOT use this by-product to trigger loading spinners. I use a loading middleware to handle all of these things in the UI. ( On my backlog to add this to the TimeWarp Architecture so others can use it. But testing, a basic documentation structure and Auth are in front of that currently).

The automatic firing of the subscription will happen after the handler completes. I guess one could fire these in the middle of a handler but that was not the design intention.

@szalapski
Copy link
Author

szalapski commented Nov 16, 2021

I think I agree. Though I appreciate Pete's purity to the flux model, I don't see much benefit to that--it makes the complex things possible but doesn't make the simple things simple.

Now if only I could understand/find/contribute a better approach on #266 I would introduce Blazor-State to my team.

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