跪拜 Guibai
← Back to the summary

How a v-for Assignment White-Screened a Vue App — and the Two Safe Fixes

"Bang! The page went blank, and the console didn't even throw an error - all because I added a temporary variable in v-for." When I was debugging this issue last week, I stared at the screen for a full ten seconds. As a veteran of 3 years with Vue, this trap was so sneaky that I had to open the source code to fully understand it.

1. Scene recreation: a "simple" list render

The requirement was utterly ordinary: render a product list, where each product shows a different label based on price range. I casually wrote this code:

<template>
  <div v-for="item in list" :key="item.id">
    <!-- Temporary variable priceRange for conditional judgment -->
    <span v-if="(priceRange = getPriceRange(item.price)) === 'high'">
      High-end product
    </span>
  </div>
</template>

The data volume was small (around 200 items), and local development worked fine. But once it hit the pre-production environment, the page went white directly, without even a Vue warning.

2. Root cause: the "hidden rule" of template compilation

Open Vue's compiled render function, and the truth comes out:

// Compiled render function fragment
function render(_ctx) {
  return (_ctx.list || []).map((item) => {
    priceRange = _ctx.getPriceRange(item.price) // Here!
    return _createVNode("div", { key: item.id }, [
      priceRange === 'high' 
        ? _createVNode("span", null, "High-end product")
        : null
    ])
  })
}

The key point: Assignment expressions in Vue templates are compiled into the top-level scope of the render function. In my example, priceRange became a global variable (in non-strict mode), and when the render function executes multiple times, this variable gets repeatedly overwritten, eventually causing a call stack overflow.

  1. Vue's template compiler keeps the original expression structure as much as possible.
  2. Assignment operations inside v-for pollute the render function scope.
  3. In SSR scenarios, this kind of problem surfaces earlier (Node environment defaults to strict mode).

3. Correct approaches: two safe solutions

Solution 1: Switch to a computed property (recommended)

<template>
  <div v-for="item in processedList" :key="item.id">
    <span v-if="item.priceRange === 'high'">
      High-end product
    </span>
  </div>
</template>

<script>
export default {
  computed: {
    processedList() {
      return this.list.map(item => ({
        ...item,
        priceRange: this.getPriceRange(item.price)
      }))
    }
  }
}

Solution 2: Use a method call (suitable for simple logic)

<template>
  <div v-for="item in list" :key="item.id">
    <span v-if="getPriceRange(item.price) === 'high'">
      High-end product
    </span>
  </div>
</template>

Performance comparison (average over 1000 renders):

Option Time (ms) Memory usage (MB)
Wrong approach crashes -
Computed property 42 16.8
Method call 38 16.2

4. Pitfall guide: these operations in v-for are also dangerous

  1. Avoid side-effect operations:

    <!-- Wrong case: modifying external state -->
    <div v-for="item in list" @click="results.push(item.id)"></div>
    
  2. Use destructuring with caution:

    <!-- May cause reactiveness loss -->
    <div v-for="{ id, ...rest } in deepList"></div>
    
  3. Beware of async calls:

    <!-- May cause render order confusion -->
    <div v-for="item in list" v-show="await checkItem(item)"></div>
    

5. Why doesn't the console report an error?

This is the most headache-inducing part: JavaScript's non-strict mode silently allows global variable assignment. To locate such issues:

  1. Enable ESLint's no-undef rule
  2. Force strict mode in Vue configuration
  3. Inject checking logic when using import.meta.env.MODE === 'development'

Conclusion

v-for is not JavaScript's for loop; it's a trigger for the Vue reactive system. Remember: templates only handle display, logic goes to the data layer. What other template patterns that look harmless but are actually fatal have you run into in your projects? Feel free to share your war stories.

Comments

Top 1 from juejin.cn, machine-translated. The original thread is authoritative.

卷土的土

Computed properties are suitable for centralized derived data.