What Causes This Warning?
This warning occurs when you use v-for with a range (number) that isn’t a valid integer. Vue’s v-for range feature expects a whole number to determine how many times to iterate.
The Problem
<!-- ❌ Using non-integer values -->
<template>
<div v-for="n in 5.5" :key="n">{{ n }}</div>
<div v-for="n in NaN" :key="n">{{ n }}</div>
<div v-for="n in '3'" :key="n">{{ n }}</div>
</template>
The Fix
Use Integer Values
<template>
<!-- ✅ Integer literal -->
<div v-for="n in 5" :key="n">{{ n }}</div>
<!-- ✅ Integer from ref -->
<div v-for="n in count" :key="n">{{ n }}</div>
</template>
<script setup>
const count = ref(5) // Integer value
</script>
Convert to Integer
<script setup>
const rawValue = ref(5.7)
// ✅ Use Math.floor, Math.ceil, or Math.round
const count = computed(() => Math.floor(rawValue.value))
</script>
<template>
<div v-for="n in count" :key="n">{{ n }}</div>
</template>
Common Scenarios
Pagination
<script setup>
const totalItems = ref(47)
const itemsPerPage = ref(10)
// ❌ Division might not be integer
// const totalPages = totalItems.value / itemsPerPage.value // 4.7
// ✅ Round up for pagination
const totalPages = computed(() =>
Math.ceil(totalItems.value / itemsPerPage.value) // 5
)
</script>
<template>
<button v-for="page in totalPages" :key="page">
{{ page }}
</button>
</template>
Star Rating
<script setup>
const rating = ref(3.5)
// ✅ Separate full and partial stars
const fullStars = computed(() => Math.floor(rating.value))
const hasHalfStar = computed(() => rating.value % 1 >= 0.5)
</script>
<template>
<span v-for="n in fullStars" :key="n">★</span>
<span v-if="hasHalfStar">☆</span>
</template>
Dynamic Count from API
<script setup>
const apiResponse = ref(null)
// ✅ Ensure integer with fallback
const itemCount = computed(() => {
const count = apiResponse.value?.count
return Number.isInteger(count) ? count : 0
})
</script>
<template>
<div v-for="n in itemCount" :key="n">Item {{ n }}</div>
</template>
User Input
<script setup>
const inputValue = ref('')
// ✅ Parse and validate user input
const repeatCount = computed(() => {
const parsed = parseInt(inputValue.value, 10)
if (isNaN(parsed) || parsed < 0) return 0
return Math.min(parsed, 100) // Cap at 100
})
</script>
<template>
<input v-model="inputValue" type="number" min="0" max="100" />
<div v-for="n in repeatCount" :key="n">Repeated {{ n }}</div>
</template>
Calculated Grid
<script setup>
const gridSize = ref(4.2) // Might be non-integer
// ✅ Ensure integer for grid
const rows = computed(() => Math.round(gridSize.value))
const cols = computed(() => Math.round(gridSize.value))
</script>
<template>
<div class="grid">
<div v-for="row in rows" :key="row" class="row">
<div v-for="col in cols" :key="col" class="cell">
{{ row }}-{{ col }}
</div>
</div>
</div>
</template>
Using Array Instead
If you need more control, create an array:
<script setup>
const count = ref(5.5)
// ✅ Create array with exact length
const items = computed(() =>
Array.from({ length: Math.floor(count.value) }, (_, i) => i + 1)
)
</script>
<template>
<div v-for="item in items" :key="item">{{ item }}</div>
</template>
Type Safety with TypeScript
const count = ref<number>(5)
// TypeScript helps catch this at compile time
const safeCount = computed((): number => {
const value = count.value
if (!Number.isInteger(value)) {
console.warn('Count should be an integer')
return Math.floor(value)
}
return value
})
Quick Checklist
- Ensure v-for range values are integers
- Use
Math.floor(),Math.ceil(), orMath.round()for calculations - Validate user input before using in v-for
- Handle API responses that might return floats
- Use
Number.isInteger()for validation - Consider using arrays instead for complex cases