Can the state of the Counter in the example Blazor project be preserved between page switches?

前端 未结 4 933
情书的邮戳
情书的邮戳 2021-01-15 21:37

In the default example project for both server-side Blazor and WebAssembly Blazor projects, the Counter example resets to 0 every time you move between the pages. However, o

相关标签:
4条回答
  • 2021-01-15 22:09

    For server side Blazor if you want the counter value to be persisted/updated on all tabs/clients you could simply store it in a static variable and rerender if the value changes.

    @page "/counter"
    
    <h1>Static Counter</h1>
    
    <p>Current static count: <span style="font-size:42px">@currentCount</span></p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        public static int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
    
            StaticCount.FireUpdate();
        }
    
        protected override void OnInitialized()
        {
            base.OnInitialized();
    
            StaticCount.NewCounterValue += OnNewCounterValue;
        }
    
        void OnNewCounterValue(object sender, EventArgs e)
        {
            InvokeAsync(() =>
            {
                StateHasChanged();
            });
        }
    
        public void Dispose()
        {
            StaticCount.NewCounterValue -= OnNewCounterValue;
        }
    
    }
    
    @code{
        public static class StaticCount
        {
            public static event EventHandler NewCounterValue;
    
            public static void FireUpdate()
            {
                NewCounterValue?.Invoke(null, new EventArgs());
            }
        }
    }
    

    You could also do this with a (singleton) service and even persist the value in a database if you want to keep the value between server restarts.

    0 讨论(0)
  • 2021-01-15 22:15

    I cover this in my article (works for server side Blazor as well as client side (WebAssembly) Blazor): Implementing State Management In Blazor

    Add a class called CounterState.cs using the following code:

        public class CounterState
        {
            public int CurrentCount { get; set; }
        }
    

    Register this class, using Dependency Injection, in the the Startup.cs:

    services.AddScoped<CounterState>();
    

    Add the following code to the top of the .razor code page:

    @inject CounterState CounterState
    

    Change the following code:

    <p>Current count: @currentCount</p>
    

    To:

    <p>Current count: @CounterState.CurrentCount</p>
    

    Finally, change the code section to the following:

    @code {
        void IncrementCount()
        {
            // ** SESSION STATE
            int CurrentCount = CounterState.CurrentCount;
            CurrentCount++;
            // Set Current count on the Session State object
            CounterState.CurrentCount = CurrentCount;
        }
    }
    
    0 讨论(0)
  • 2021-01-15 22:23

    It looks like this exact scenario is discussed in https://docs.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-3.0#client-side-in-the-browser

    Seems Blazor just doesn't handle it out-of-the-box, but you just need to use localStorage or sessionStorage.

    Using the Blazor.Extensions.Storage NuGet package (https://github.com/BlazorExtensions/Storage):

    @page "/counter"
    
    @inject ISessionStorage SessionStorage
    @using Blazor.Extensions.Storage.Interfaces
    
    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        protected override async Task OnInitializedAsync()
        {
            currentCount = await SessionStorage.GetItem<int>("counter");
        }
    
        private async void IncrementCount()
        {
            currentCount++;
            await SessionStorage.SetItem<int>("counter", currentCount);
        }
    }
    
    0 讨论(0)
  • 2021-01-15 22:32

    I wrote an answer about Blazor state management that looks into this here:

    https://stackoverflow.com/a/65609519/3850405

    My recommendation would be an in-memory state container service.

    Example:

    StateContainer.cs

    public class StateContainer
    {
        public string Property { get; set; } = "Initial value from StateContainer";
    
        public event Action OnChange;
    
        public void SetProperty(string value)
        {
            Property = value;
            NotifyStateChanged();
        }
    
        private void NotifyStateChanged() => OnChange?.Invoke();
    }
    

    Program.Main (Blazor WebAssembly):

    builder.Services.AddSingleton<StateContainer>();
    

    Startup.ConfigureServices (Blazor Server):

    services.AddSingleton<StateContainer>();
    

    Pages/Component1.razor

    @page "/Component1"
    @inject StateContainer StateContainer
    @implements IDisposable
    
    <h1>Component 1</h1>
    
    <p>Component 1 Property: <b>@StateContainer.Property</b></p>
    
    <p>
        <button @onclick="ChangePropertyValue">Change Property from Component 1</button>
    </p>
    
    <Component2 />
    
    @code {
        protected override void OnInitialized()
        {
            StateContainer.OnChange += StateHasChanged;
        }
    
        private void ChangePropertyValue()
        {
            StateContainer.SetProperty($"New value set in Component 1 {DateTime.Now}");
        }
    
        public void Dispose()
        {
            StateContainer.OnChange -= StateHasChanged;
        }
    }
    

    Shared/Component2.razor

    @inject StateContainer StateContainer
    @implements IDisposable
    
    <h2>Component 2</h2>
    
    <p>Component 2 Property: <b>@StateContainer.Property</b></p>
    
    <p>
        <button @onclick="ChangePropertyValue">Change Property from Component 2</button>
    </p>
    
    @code {
        protected override void OnInitialized()
        {
            StateContainer.OnChange += StateHasChanged;
        }
    
        private void ChangePropertyValue()
        {
            StateContainer.SetProperty($"New value set in Component 2 {DateTime.Now}");
        }
    
        public void Dispose()
        {
            StateContainer.OnChange -= StateHasChanged;
        }
    }
    

    https://docs.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-5.0&pivots=webassembly#in-memory-state-container-service-wasm

    0 讨论(0)
提交回复
热议问题