Gerenciamento de estado no Blazor
Gerencie o estado compartilhado com singletons de serviço, Fluxor ou AppState em cascata para manter a interface consistente entre os componentes.
Gerenciamento de estado no Blazor é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.
Desafios do gerenciamento de estado no Blazor
À medida que os aplicativos Blazor crescem, gerenciar o estado que precisa ser compartilhado por muitos componentes não relacionados se torna complexo. O encadeamento simples de propriedades deixa de ser suficiente; é necessário um armazenamento de estado centralizado e reativo.
Estado simples com um serviço com escopo
A forma mais simples de gerenciar o estado no Blazor: um serviço com escopo que mantém o estado e expõe um evento para que os componentes possam se inscrever nas alterações.
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();
}
}Inscrevendo-se nas alterações de estado
Os componentes se inscrevem no evento OnChanged do serviço de estado e chamam StateHasChanged para renderizar novamente. Lembre-se de cancelar a inscrição em 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 contêiner de estado
Envolva o layout raiz em um CascadingValue com seu serviço de estado. Todos os descendentes podem acessá-lo sem o encaminhamento explícito de propriedades.
@* 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: padrão Flux para Blazor
O Fluxor traz para o Blazor um fluxo de dados unidirecional no estilo Redux: Estado → Componente → Ação → Redutor → Estado. É excelente para aplicativos complexos.
// 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));Usando Fluxor em um componente
Injete IState<T> para ler o estado e IDispatcher para despachar ações. InheritsFrom<FluxorComponent> (ou o mixin) inscreve-se automaticamente nas alterações 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));
}Persistência no LocalStorage
Persista o estado entre atualizações da página usando o localStorage do navegador por meio da interoperabilidade com JavaScript. Restaure-o na inicialização do aplicativo.
@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();
}Pacote Blazored.LocalStorage
O pacote Blazored.LocalStorage fornece uma API tipada e simples sobre o localStorage do navegador, sem a necessidade de escrever manualmente chamadas de interoperabilidade com JS.
// 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 da URL com NavigationManager
Use parâmetros de consulta para manter um estado que deve sobreviver a uma atualização da página e poder ser incluído nos favoritos. Leia-os e escreva-os por meio do NavigationManager e do construtor 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
}));
}
}Na prática: estado do carrinho de compras
Um padrão completo: serviço CartState com escopo e eventos, persistido no localStorage a cada alteração e restaurado durante o carregamento.
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();
}
}Verificação rápida
Qual abordagem de gerenciamento de estado é melhor para um aplicativo Blazor simples com estado compartilhado limitado?
Recapitulação: gerenciamento de estado no Blazor
Principais conclusões:
- Serviço com escopo + evento de ação: estado compartilhado mais simples, adequado para a maioria dos aplicativos
- CascadingValue envolvendo a raiz fornece acesso em todo o aplicativo sem o encadeamento de propriedades
- Fluxor: fluxo unidirecional no estilo Redux para lógica de estado complexa
- Persista o estado no localStorage com IJSRuntime ou Blazored.LocalStorage
- Estado na URL (SupplyParameterFromQuery) para um estado da interface que pode ser incluído nos favoritos e compartilhado
- Cancele sempre a inscrição em eventos em Dispose para evitar vazamentos de memória
Perguntas Frequentes
A aula “Gerenciamento de estado no Blazor” é grátis?
Sim — o texto completo de “Gerenciamento de estado no Blazor” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.
O que vou aprender em “Gerenciamento de estado no Blazor”?
Gerencie o estado compartilhado com singletons de serviço, Fluxor ou AppState em cascata para manter a interface consistente entre os componentes. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C# Academy?
Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.
Quanto tempo leva a aula “Gerenciamento de estado no Blazor”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C# Academy?
Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Modelo de componentes do Blazor
- Vinculação de dados e tratamento de eventos
- Comunicação entre componentes e DI
- Gerenciamento de estado no Blazor