[Validation] Analyzer diagnostics for unnecessary StateHasChanged calls
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 281
Description
**Scenario contact:** @ilonatommy
## Scenario
Developers add `StateHasChanged` defensively, in places where `ComponentBase` already schedules a render. The calls are harmless but misleading, and they hide the few places a render really does need requesting. This validates that the build points them out, that the offered fix is safe to apply, and that genuinely necessary calls are left alone.
## Minimum build
.NET 11 Preview 7 or later.
## Configurations to cover
* Blazor Web App
* [ ] Static SSR
* [x] Interactive Server
* [ ] Interactive WebAssembly
* [ ] Interactive Auto
* [ ] Standalone WebAssembly
* [ ] Hybrid (MAUI)
These diagnostics are produced by the compiler, so they do not vary by render mode. The configuration below is the one needed to reproduce the runtime behavior the warning predicts, not a matrix to work through.
## Also exercise
* [ ] Published output
* [ ] An existing .NET 10 app upgraded to .NET 11
* [ ] Trimming or ahead-of-time compilation
* [ ] More than one server instance, or a proxy in front
* [ ] Hot Reload
* [x] An IDE as well as the command line
* [ ] Container
## Setup
| Id | Title | Code fix |
|---|---|---|
| `BL0012` | Unnecessary `StateHasChanged` call | Yes |
The diagnostic covers synchronous lifecycle methods and event handlers, and in asynchronous ones the calls before the first `await` and after the final `await`.
## What to build
A component that calls `StateHasChanged` in each of the places the diagnostic describes:
* At the end of a synchronous event handler.
* In `OnInitialized`, the synchronous lifecycle method.
* In `OnInitializedAsync`, before the first `await`.
* In `OnParametersSetAsync`, after the final `await`.
Alongside them, include the case that genuinely needs it: a call between two `await`s in an async method, where the first `await` does not complete synchronously and the UI must update before the second finishes. Also add one from a timer or other callback that `ComponentBase` knows nothing about.
## Things to try
* Building at the command line and in an IDE, and comparing what each reports.
* Applying the offered fix and rebuilding.
* Running the app afterwards to confirm the UI still updates everywhere it did before.
* Moving a call from between two `await`s to after the last one, to see the warning appear.
* Adding a second `await` to a method that had one, to see the warning disappear where the call becomes necessary.
## Expected behavior
Only the unnecessary calls are flagged, and removing them changes nothing the user can see.
### Must hold
* Each unnecessary call produces a `BL0012` warning naming the method it is in, in all four places above.
* The call between two `await`s, and the one from an external callback, produce no warning.
* Applying the fix removes only the flagged call and leaves code that compiles.
* After applying every fix, the UI still updates everywhere it did before.
* The warnings appear both at the command line and in the IDE, at the same lines.
### Expected differences between configurations
* None. The warning is produced at compile time and is identical in every configuration.
## Documentation to use
* [ASP.NET Core Razor component rendering](https://learn.microsoft.com/aspnet/core/blazor/components/rendering?view=aspnetcore-11.0)
## What to report
Report results using the format described in the [validation testing manual](https://github.com/dotnet/aspnetcore/issues/68479). Include link to a repository with the test app.
Contributor guide
Assessment
This issue has not been assessed yet.