The Usual Suspects
When a Blazor app feels sluggish, developers usually start with the obvious culprits. Is there a massive list that needs virtualization? Are we forgetting to use `shouldRender`? Maybe we’re not lazy-loading
modules properly. These are all valid and important optimizations, and for many scenarios, they’re the right fix. But there’s a more insidious issue that often goes unnoticed, one that doesn’t live in your UI markup but in the code-behind logic of your components. It’s a problem that stems from a fundamental misunderstanding of Blazor's component lifecycle, and it can turn a snappy application into a frustrating, laggy mess by triggering an avalanche of unnecessary work.
The Real Culprit: The OnParametersSet Trap
The performance trap lies in a seductive but dangerous lifecycle method: `OnParametersSet` or its async counterpart, `OnParametersSetAsync`. On the surface, its purpose seems clear: it runs whenever a component’s parameters are set. This makes it feel like the perfect place to fetch data or perform logic based on those parameters. For example, if your component takes an `[Parameter] int ProductId`, it’s tempting to put your data-fetching call right inside `OnParametersSetAsync`. The problem is that “whenever a component’s parameters are set” is far more frequent than most developers initially assume. It’s not just called once when the component is first created with its initial parameters. It's called *any time* the parent component re-renders, even if the values of the parameters passed to your child component haven't actually changed. This means your component might be re-fetching the exact same data from your API over and over again, completely without your knowledge.
A Lifecycle Deep Dive
Think of it like this: `OnInitializedAsync` is the welcome party. It happens once when the component first joins the DOM. It's great for one-time setup. `OnParametersSetAsync`, on the other hand, is like a notification that someone *might* have new information for you. Blazor’s rendering system is efficient but conservative; when a parent component renders, it tells all its children, “Hey, your parameters might have been updated, so I’m setting them again.” It doesn’t check if the values are new. It just re-sets them. If you have a data-fetching call directly in `OnParametersSetAsync`, you're effectively telling your component to go on a round trip to the server every single time its parent even twitches. If that parent component re-renders due to a simple button click or a state change unrelated to your child component's parameters, you're still triggering that expensive data call. This creates a cascade of unnecessary network requests, database queries, and UI re-renders that can bring your application's performance to its knees.
The Simple, Elegant Solution
The fix is surprisingly simple: treat `OnParametersSetAsync` as a potential event, not a guaranteed one. Before doing any expensive work, you must check if the relevant parameter values have actually changed. Instead of just blindly fetching data, you need to store the previous state of the parameter and compare it to the new state. If, and only if, the value is different, do you proceed with the expensive operation. The pattern looks something like this: First, you’ll need a private field to track the old parameter value. Then, inside `OnParametersSetAsync`, you compare the current parameter value to your tracked value. If they’re different, you perform your work (like fetching data) and then update the tracked value to the new one. This simple guard clause ensures your component is efficient and respects the rendering cycle. It stops the flood of redundant calls and only acts when a meaningful change has occurred. Microsoft has even provided an override `SetParametersAsync` for more advanced scenarios, but for most cases, this manual check inside `OnParametersSetAsync` is the most straightforward and effective solution.
Beyond Data Fetching
This trap isn't limited to just API calls. Any computationally expensive operation placed unguarded in `OnParametersSetAsync` is a potential bottleneck. This could be complex calculations, heavy object manipulations, or any logic that takes more than a few milliseconds to execute. The principle remains the same: the component lifecycle is designed for frequent, lightweight updates. Anything heavy needs a guard to ensure it only runs when absolutely necessary. By being mindful of this behavior, you can build components that are not only functional but also robust and performant. You transform `OnParametersSetAsync` from a potential footgun into a powerful tool for creating responsive and efficient user experiences.






