-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Blazor should throw when there are duplicate @key values in components #11908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Can you clarify what catastrophic consequences you anticipate?
This means that we may produce a suboptimal diff (e.g., re-rendering more descendants than you'd expect), but it's rare that it would result in an observable difference to the end user. The design intent was to handle key clashes gracefully, because there may be cases where developers find them hard to avoid, or worse, don't encounter them during development but do in production. In the latter case, producing a suboptimal diff is much better than outright crashing the application. |
Thank you for your feedback. /cc @rynowak, in case you have any thoughts, please comment. |
Sorry, but I don't agree. We can have plenty of bugs in our programs like division by zero or access to null reference and in my opinion it is good that we see an exception in all these cases. In ASP.NET Core source we can find hundreds of places where you are checking for null at the beginning of a method and throw exception. You don't silently ignore the problem. I perceive @key attribute as an unique key in a database. It has to be unique or you will get an error. In the doc we can read:
These suggestions are perfect. People who cannot guarantee uniqueness should not use
Observable (or worse hidden) difference can result from the fact that components can have some internal state. This internal state can be set initially when the object is created and then eventually changed as a result of some external events, for example @page "/counter"
<h1>Dish: @DishName</h1>
<p>Ordered quantity: @currentCount</p>
<button class="btn btn-primary" @onclick="@IncrementCount">Order more</button>
@if (currentCount > 1)
{
<button class="btn btn-primary" @onclick="@DecrementCount">Order less</button>
} @code
{
// internal state initialized when object is created
int currentCount = 1;
[Parameter] protected string DishName { get; set; }
void IncrementCount()
{
currentCount++;
}
void DecrementCount()
{
currentCount--;
}
} And here is a modified @page "/"
<div>
@for (int i = 0; i < NumberOfDishes; i++)
{
if (!hiddenDishes[i])
{
<Counter DishName="@dishes[i]" />
}
}
</div>
<div>
<br />
@for (int i = 0; i < NumberOfDishes; i++)
{
int x = i;
<button class="btn btn-primary" @onclick="@(() => Hide(x))">@(hiddenDishes[x] ? "Add" : "Remove") @dishes[x]</button>
}
</div> @code
{
const int NumberOfDishes = 3;
bool[] hiddenDishes = new bool[NumberOfDishes];
string[] dishes = { "Pizza", "Hamburger", "Chips" };
void Hide(int counterNumber)
{
hiddenDishes[counterNumber] = !hiddenDishes[counterNumber];
}
} Take into account that source code is written this way to demonstrate the problem and it is not a recommended design pattern for anybody. Here is a screenshot after a few Now after As you can see I originally ordered 3 hamburgers and now I have only 2. The same problem is with chips. After I have 2 pizzas (should be 1) and I have 1 chips only (originally was 4). I intentionally don't use Each time you encounter a duplicate key value you should throw an exception. It is much better than silently ignore a bug. I vote to change the behaviour now (before 3.0 release) because it is a breaking change. |
@mkArtakMSFT please reopen because it is in my opinion serious bug. I have just added a new comment with clarification - read and decide. |
Reopening to discuss this in our next triage. |
I have yet another example. It will not kill people but it can kill performance of your application. You can have some expensive calculations or database calls in your component each time value of the parameter changes. When you have duplicate key values wrong components are created/destroyed and all other components unintentionally receive new parameter values. This bug (or unfortunate design) is similar to original design of Entity Framework Core where some LINQ queries where not executed on the server but on the client. This led to unacceptable drops in performance at unpredictable moments. Fortunately it is now fixed in 3.0 and every time LINQ query cannot be correctly transformed to server only SQL query exception will be thrown. |
Thanks for this suggestion, @Andrzej-W! We were convinced by your reasoning, and implemented this change in #12187. |
Describe the bug
Currently it is possible to create components with duplicate @key values. It is even documented:
Expected behavior
Blazor should throw exception, because it is potentially serious bug with catastrophic consequences.
Additional context
People who use @key expect that it works. If it doesn't some serious bugs are possible, usually related to unexpected lifecycle methods calls.
The text was updated successfully, but these errors were encountered: