prism icon indicating copy to clipboard operation
prism copied to clipboard

Reassignment after rendering conditional element / array item rendered twice

Open kaleidawave opened this issue 3 years ago • 0 comments

Given the following template:

<template>
    <div #if="someString !== 'x'">
        {someString}
    </div>
</template>

Let someString equal 'x' initially.

If someString is reassigned to "abc" then at runtime:

  1. someString !== 'x' is now truthy so the div is rendered with the state (this.data equal to) {someString: "abc"} and swapped in for a placeholder element
  2. someString value has changed so it tries to set the first text node of the div (if it exists) content to "abc"

The problem is when the render of the div occurs it will render in with the updated state so it will have "abc" as its text content. Therefore the second call is redundant for this update. However a second assign to someString of "xyz" requires the second statement, as the update would not be reflected on the view as the render of the div and swap would not occur.

This isn't a big deal here, no bad effects only additional calls with no effect which could be a perf problem.

However for:

<template>
    <div #if="someArr.length > 3">
        <ul #for="const x of someArr">
             <li>{x}</li>
        </ul>
    </div>
</template>

.pushing to someArr while someArr.length === 3 will cause the argument of push to be in the ul list twice. Once from initial render when someArr.length > 3 becomes truthy and second when the push call means assigning to a index outside of current length causing a new li to be rendered.

There are some mitigations such as maintaining a separate prop for the condition as not to clash with variables used inside and controlling that prop manually.

But there is definitely some ways the compiler could see this problem occurring and generate code for mitigations.

kaleidawave avatar Oct 10 '20 20:10 kaleidawave