0Pricing
C# Academy · Lección

Gestión de estado en Blazor

Gestione el estado compartido con singletons de servicio, Fluxor o AppState en cascada para mantener la interfaz coherente entre componentes.

Gestión de estado en Blazor es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.

Desafíos de la gestión del estado en Blazor

Al crecer las aplicaciones Blazor, gestionar el estado que debe compartirse entre muchos componentes no relacionados se vuelve complejo. Pasar props manualmente por la jerarquía deja de ser viable; necesita un almacén de estado centralizado y reactivo.

Estado sencillo con un servicio con ámbito

La forma más sencilla de gestionar el estado en Blazor es un servicio con ámbito que contiene el estado y expone un evento al que los componentes pueden suscribirse para recibir cambios.

public class CartState
{
    private readonly List<CartItem> _items = new();
    public IReadOnlyList<CartItem> Items => _items;
    public int Count => _items.Sum(i => i.Quantity);

    public event Action? OnChanged;

    public void Add(Product p)
    {
        var existing = _items.FirstOrDefault(i => i.ProductId == p.Id);
        if (existing is not null) existing.Quantity++;
        else _items.Add(new CartItem { ProductId = p.Id, Name = p.Name, Price = p.Price });
        OnChanged?.Invoke();
    }
}

Suscripción a los cambios de estado

Los componentes se suscriben al evento OnChanged del servicio de estado y llaman a StateHasChanged para volver a renderizarse. Recuerde cancelar la suscripción en Dispose.

@inject CartState Cart
@implements IDisposable

<p>Cart: @Cart.Count items</p>

@code {
    protected override void OnInitialized()
    {
        Cart.OnChanged += OnCartChanged;
    }

    private void OnCartChanged()
    {
        InvokeAsync(StateHasChanged);
    }

    public void Dispose() =>
        Cart.OnChanged -= OnCartChanged;
}

CascadingValue como contenedor de estado

Envuelva el layout raíz en un CascadingValue con su servicio de estado. Todos los descendientes pueden acceder a él sin pasar props explícitamente por la jerarquía.

@* MainLayout.razor *@
@inject CartState Cart

<CascadingValue Value="Cart">
    @Body
</CascadingValue>

@* Any nested component: *@
@code {
    [CascadingParameter]
    public CartState Cart { get; set; } = default!;

    private void Buy(Product p) => Cart.Add(p);
}

Fluxor: patrón Flux para Blazor

Fluxor incorpora un flujo de datos unidireccional al estilo de Redux en Blazor: State → Component → Action → Reducer → State. Es ideal para aplicaciones complejas.

// dotnet add package Fluxor.Blazor.Web

// State record
[FeatureState]
public record CounterState(int Count = 0);

// Actions
public record IncrementAction(int Amount = 1);

// Reducers
public static class CounterReducers
{
    [ReducerMethod]
    public static CounterState Reduce(CounterState state, IncrementAction action)
        => state with { Count = state.Count + action.Amount };
}

// Registration:
builder.Services.AddFluxor(opt =>
    opt.ScanAssemblies(typeof(Program).Assembly));

Uso de Fluxor en un componente

Inyecte IState<T> para leer el estado y IDispatcher para despachar acciones. InheritsFrom<FluxorComponent> (o el mixin) se suscribe automáticamente a los cambios de estado.

@inherits FluxorComponent
@inject IState<CounterState> CounterState
@inject IDispatcher Dispatcher

<p>Count: @CounterState.Value.Count</p>
<button @onclick="Increment">+1</button>
<button @onclick="() => Dispatcher.Dispatch(new IncrementAction(5))">+5</button>

@code {
    private void Increment()
        => Dispatcher.Dispatch(new IncrementAction(1));
}

Persistencia en localStorage

Conserve el estado entre actualizaciones de página usando localStorage del navegador mediante interoperabilidad con JavaScript. Restáurelo al iniciar la aplicación.

@inject IJSRuntime JS

@code {
    private async Task SaveStateAsync()
    {
        var json = JsonSerializer.Serialize(_state);
        await JS.InvokeVoidAsync("localStorage.setItem", "appState", json);
    }

    protected override async Task OnInitializedAsync()
    {
        var json = await JS.InvokeAsync<string?>("localStorage.getItem", "appState");
        if (json is not null)
            _state = JsonSerializer.Deserialize<AppState>(json) ?? new();
    }

    private AppState _state = new();
}

Paquete Blazored.LocalStorage

El paquete Blazored.LocalStorage proporciona una API limpia y tipada sobre el localStorage del navegador sin tener que escribir manualmente llamadas de interoperabilidad con JavaScript.

// dotnet add package Blazored.LocalStorage
builder.Services.AddBlazoredLocalStorage();

@inject ILocalStorageService LocalStorage

@code {
    protected override async Task OnInitializedAsync()
    {
        _cart = await LocalStorage.GetItemAsync<List<CartItem>>("cart") ?? new();
    }

    private async Task SaveCartAsync()
    {
        await LocalStorage.SetItemAsync("cart", _cart);
    }

    private List<CartItem> _cart = new();
}

Estado en la URL con NavigationManager

Use parámetros de consulta para almacenar el estado que deba sobrevivir a una actualización de página y poder incluirse en marcadores. Léalos y escríbalos mediante NavigationManager y el generador de URI.

@inject NavigationManager Nav
@page "/products"

@code {
    [SupplyParameterFromQuery] public string? Search { get; set; }
    [SupplyParameterFromQuery] public int Page { get; set; } = 1;

    private void UpdateSearch(string s)
    {
        Nav.NavigateTo(
            Nav.GetUriWithQueryParameters(
                new Dictionary<string, object?>
                {
                    [nameof(Search)] = s,
                    [nameof(Page)]   = 1
                }));
    }
}

Caso real: estado del carrito de compras

Un patrón completo: un servicio CartState con ámbito y eventos, persistido en localStorage cuando cambia y restaurado al cargarse.

public class CartState
{
    private readonly ILocalStorageService _storage;
    private List<CartItem> _items = new();
    public event Action? OnChanged;

    public CartState(ILocalStorageService storage) => _storage = storage;

    public async Task InitAsync()
    {
        _items = await _storage.GetItemAsync<List<CartItem>>("cart") ?? new();
    }

    public async Task AddAsync(Product p)
    {
        var item = _items.FirstOrDefault(i => i.ProductId == p.Id);
        if (item is not null) item.Quantity++;
        else _items.Add(new CartItem { ProductId = p.Id, Name = p.Name });
        await _storage.SetItemAsync("cart", _items);
        OnChanged?.Invoke();
    }
}

Comprobación rápida

¿Qué enfoque de gestión del estado es mejor para una aplicación Blazor sencilla con un estado compartido limitado?

Resumen: gestión del estado en Blazor

Conclusiones clave:

  • Servicio con ámbito + evento Action: estado compartido más sencillo, adecuado para la mayoría de las aplicaciones
  • Un CascadingValue que envuelve la raíz proporciona acceso en toda la aplicación sin pasar props manualmente
  • Fluxor: flujo unidireccional al estilo Redux para lógica de estado compleja
  • Conserve el estado en localStorage con IJSRuntime o Blazored.LocalStorage
  • Estado en la URL (SupplyParameterFromQuery) para un estado de UI que se pueda guardar en marcadores y compartir
  • Anule siempre la suscripción a los eventos en Dispose para evitar fugas de memoria

Preguntas frecuentes

¿La lección «Gestión de estado en Blazor» es gratis?

Sí — el texto completo de «Gestión de estado en Blazor» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Gestión de estado en Blazor»?

Gestione el estado compartido con singletons de servicio, Fluxor o AppState en cascada para mantener la interfaz coherente entre componentes. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Gestión de estado en Blazor»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Modelo de componentes de Blazor
  2. Enlace de datos y gestión de eventos
  3. Comunicación entre componentes e DI
  4. Gestión de estado en Blazor
← Volver a C# Academy