mrpmorris / Fluxor

Fluxor is a zero boilerplate Flux/Redux library for Microsoft .NET and Blazor.
MIT License
1.25k stars 144 forks source link

Page does not refresh after state change when inheriting #254

Closed Rhywden closed 2 years ago

Rhywden commented 2 years ago

I basically followed the instructions, added

@inherits Fluxor.Blazor.Web.Components.FluxorComponent

to the top of the page, injected the proper state like so:

[Inject]
private IState<RoomState> RoomState { get; set; }

but when some other source dispatches a change to the RoomState it does not get picked up. It's only when I switch pages or manually subscribe to RoomState.StateChanged and call StateHasChanged from the event handler that the changes get picked up.

mrpmorris commented 2 years ago

What do you mean by "other source", JavaScript calling into Blazor?

If so, are you wrapping your called method code in InvokeAsync?

Rhywden commented 2 years ago

Well, I have a SignalR hub which uses Dispatch() to announce changes when it receives data.

Rhywden commented 2 years ago

I'll detail what the page itself and the SignalR client of the Blazor WASM application are looking like:

The page:

@using AnliegenWASM.Shared.HubData
@using Fluxor

@implements IDisposable

@foreach(raum as RaumState.Value.Räume) {
   ...
}

@code {
    [Inject]
    private IState<RaumState> RaumState { get; set; }
protected override void OnInitialized()
    {
        RaumState.StateChanged += StateChange;
    }

    private async void StateChange(object? source, System.EventArgs e)
    {
        await InvokeAsync(StateHasChanged);
    }

    public void Dispose()
    {
        RaumState.StateChanged -= StateChange;
    }

This version is working and does pick up on any changes the SignalR client dispatches upon receiving data. However, if I use @inherits Fluxor.Blazor.Web.Components.FluxorComponent instead of subscribing to the StateChanged event, nothing happens. Reading the documentation, I got the impression that inheriting would get rid of the requirement for this subscription?

The SignalR client lives on the MainLayout.razor (for now) and basically does this:

@using AnliegenWASM.Shared.Hub
@using AnliegenWASM.Shared.HubData
@using Fluxor

<Layoutstuff>
@body somewhere
</Layoutstuff>

@code {
    [Inject]
    public IDispatcher Dispatcher { get; set; }
    [Inject]
    private IState<RaumState> RaumState { get; set; }

   protected override async Task OnInitializedAsync() {
      //some other async tasks
     SignalRService.RegisterOnRaum((raum, method) =>
        {
            if (method == HubMethod.Create)
            {
                Dispatcher.Dispatch(new AddOneRaumAction(NeuerRaum: raum));
            } else if(method == HubMethod.Delete)
            {
                Dispatcher.Dispatch(new DeleteOneRaumAction(ZuLöschenderRaum: raum));
            } else if(method == HubMethod.Update)
            {
                Dispatcher.Dispatch(new UpdateOneRaumAction(ZuÄndernderRaum: raum));
            }
        });
}

Basically, that's it. Unless you need the Action and Reducer definitions as well?

mrpmorris commented 2 years ago

As an experiment, try

InvokeAsync(() => 
{
            if (method == HubMethod.Create)
            {
                Dispatcher.Dispatch(new AddOneRaumAction(NeuerRaum: raum));
            } else if(method == HubMethod.Delete)
            {
                Dispatcher.Dispatch(new DeleteOneRaumAction(ZuLöschenderRaum: raum));
            } else if(method == HubMethod.Update)
            {
                Dispatcher.Dispatch(new UpdateOneRaumAction(ZuÄndernderRaum: raum));
            }
});
Rhywden commented 2 years ago

That did the trick. Might be worthwhile to add that to the docs?

Anyways, thanks for your help!

mrpmorris commented 2 years ago

It's a Blazor thing that you have to InvokeAsync any code executed from outside of Blazor, to ensure you only ever have a single thread running on your code.

I would have expected Fluxor to deal with this successfully, but it's good that you now know :)

Rhywden commented 2 years ago

Indeed.