Blazor Tailwind w/ Cascading Parameter

Hi @mythz

I’m trying to implement the CascadingAppState into your tailwind balzor templates and I’m running into an issue if it being null and the OnAfterRenderAsync() lifecycle event in the CascadingAppState.razor.cs never fires.

Basically, I’ve copied the five files from the AppState project into your template and adjusted namespaces.

  • AppState.cs
  • IAppState.cs
  • CascadingAppState.razor
  • CascadingAppState.razor.cs
  • StatePropertyChangedArgs.cs

I then added the CascadingAppState to the routes.razor page like so:

<CascadingAppState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)">
                <NotAuthorized>
                    <RedirectToLogin/>
                </NotAuthorized>
            </AuthorizeRouteView>
            <FocusOnNavigate RouteData="@routeData" Selector="h1"/>
        </Found>
    </Router>
</CascadingAppState>

and added AppState to the Counter.razar page like so:

@page "/counter"
@rendermode RenderMode.InteractiveServer

<PageTitle>Counter</PageTitle>

<Heading1>Counter</Heading1>

<!-- I had to add the ?. otherwise the null here breaks the page --!>
<p class="my-4">Current count: @AppState?.Count</p>

<PrimaryButton @onclick="IncrementCount">Click me</PrimaryButton>

@code {
    
    [CascadingParameter]
    public CascadingAppState AppState { get; set; }
    
    private int currentCount = 0;

    private void IncrementCount()
    {
        AppState.Count++; // This is null when I hit here
    }
}

While I can get this to work in other projects, for some reason with your template it does not work as expected. I’ve tried the SSR and the WASM templates and both experience the same behavior.

Observations:

I do see lifecycle events firing and if I refresh and watch closely, I can see that it does have a value for a quick second, before it goes null.

image

By time I click the button and hit the breakpoint on the AppState.Count++, AppState is null.

image

The CascadingAppState example just works, and if I start a new project, it seems to work no problem.
What am I missing here?

Our Blazor Templates are just modified versions of Microsoft’s Blazor templates.

We typically don’t support 3rd Party components, but if you can put a stand-alone repro on GitHub we can have a quick look to see if we can find anything.

Here’s an example.

If you are sitting on the /counter page and hit refresh you can see it has a value before it doesn’t.

You forgot to turn off prerendering:

1 Like

I’ve created a PR with your project working with a few changes here → Change interactive mode to be set on `Route` component. by Layoric · Pull Request #1 · VagyokC4/broken-cascading-parameter · GitHub

1 Like

Thank you very much.

One side effect now is that the login screens no longer work. I get what looks like an infinite redirect loop whenever navigating to a restricted page, or the signup/login page. I’m hoping that too is a simple fix.

I’m not sure it is unfortunately. It seems the Identity setup (which the code is straight from the default ASP.NET templates) requires no interactive render mode. There is a comment to this in the code itself which is what is forcing the refresh.

However, it seems the CascadingAppState approach of doing things requires the whole app to be running in interactive render mode for all pages, presumably so the sharing of state across pages/whole application actually works.

Is there another way to save state on the client side like this, to use in conjunction with making client api calls back into the server, or the preferred way is to just make api calls?

LocalStorage would be one way to save state on the client/browser that persists across full page loads, but otherwise, yeah I would fetch the data from an API when needed.

Have a look at some of the state-management docs documentation (or persist component state) options if you haven’t already for some alternate approaches like injected StateContainer.