A performant Flux/Redux state management library for Blazor that uses selectors to determine which components to re-render, just like Redux's useSelector
hook.
Badges | |
---|---|
NuGet: Blazux.Core | |
NuGet: Blazux.Web | |
License |
- Documentation: Tutorials, Features, etc...
- Samples:
- PlainSample: This shows you how you can use the
Blazux.Core
package to handle everything yourself. This is useful when you want for example your components to not inheritBlazuxComponent
. - WebCounterSample: This shows you how you can start using
Blazux
(using theBlazux.Web
package) with low boilerplate. This is what most developers would want to start with.
- PlainSample: This shows you how you can use the
As of the time of writing (24/05/2020), there are a couple of state management libraries for Blazor. Some of them try to follow Flux/Redux, others do their own thing. They are nonetheless made by competent developers that want to help the Blazor community.
However, when an action is dispatched, all the components subscribed to the store get re-rendered. Here's why that's bad:
- Renders can be costly.
- The more subscribed components your current page has, the less performant it will be.
- If a subscribed component passes complex props (e.g. a class) to one or more children, they will also get re-rendered because Blazor doesn't handle this (details here).
If you're familiar with React & Redux, you probably know the solution by now.
react-redux
has the useSelector hook, which lets you grab a "sub-state" from the store and subscribes your component in case it changes.
Blazux tries to do the same thing. While it only started out of my curiosity and experimenting, I think it is now more than usable.
Here's how a Counter component would look like using Blazux:
public class CounterComponent : BlazuxComponent<State>
{
protected int CurrentCount => UseSelector(s => s.CurrentCount);
protected void Increment() => Dispatch(new IncrementCounterAction());
}
The UseSelector(s => s.CurrentCount)
method tells the Store that this component is interested in the "sub-state" CurrentCount
if this is the first time it's called, otherwise it'll simply return the value of CurrentCount
.
When the IncrementCounterAction
action is dispatched and the CurrentCount
is changed, only the components subscribed to CurrentCount
will get re-rendered, not all the components. This is the main goal of Blazux.
UseSelector
takes ~0.07 ms, regardless of the number of components in the page.Dispatch
takes ~0.7 ms for 100 subscribed components in the page.- Components are only re-rendered when a portion of the state they subscribed to changes.
- If a component is subscribed to multiple portions of the state and more than one of them changes, the component is only re-rendered once.
- If you use
BlazuxComponent<TState>
, the component will unsubscribe from the store when it's disposed of (otherwise you'll have to do it manually). Which means no uncessary checks and state diffs.
Basically, performance shouldn't be an issue regardless of how complex your application might be. You can look at the PlainSample
project to see it in action.
If you find a bug or you want to see a functionality in this library, feel free to open an issue in the repository!
Of course, PRs are very welcome.