Home > Blockchain >  [Vue warn]: Duplicate keys found during update: Make sure keys are unique
[Vue warn]: Duplicate keys found during update: Make sure keys are unique

Time:03-02

I'm building a tic tac toe game in Vue and I'm getting this error when the I try to reset the board.

"[Vue warn]: Duplicate keys found during update: " Make sure keys are unique."

The board starts to distort visually. I get extra squares appearing on the screen.

What am I missing? Is my state set up correctly?

<template>
  <h2>{{ msg }}</h2>
  <h2 v-if="winner" >Winner: {{ winner }}</h2>
  <h2 v-else>Player Move: {{ turn }}</h2>
  <div id="board">
    <div  v-for="(square, index) in squares" :key="square" @click="takeTurn(index)">
      {{ square }}
    </div>
  </div>
  <button @click="reset">
    Reset
  </button>
</template>

<script>
import { ref, computed } from 'vue'

export default {
  name: 'MainBoard',
  props: {
    msg: String // Vue has prop typechecking by default
  },
  setup () {
    const turn = ref('X') // player first turn
    const squares = ref([])
    for (let i = 0; i <= 8; i  ) squares.value.push('') // make a blank board}
    console.log('squares value: '   squares.value)
    const winner = computed(() => checkForWinner(squares.value.flat())) // check 4 winner everytime board changes
    console.log('computed:'   squares.value.flat())
    function checkForWinner (value) {
      console.log('check4Winner: '   value)
      // NOTE: in this version we have a
      const lines = [
        [0, 1, 2],
        [3, 4, 5],
        [6, 7, 8], // horizontal wins
        [0, 3, 6],
        [1, 4, 7],
        [2, 5, 8], // vertical wins
        [0, 4, 8],
        [2, 4, 6] // cross wins
      ]
      for (let i = 0; i < lines.length; i  ) {
        const [a, b, c] = lines[i]
        if (
          value[a] &&
          value[a] === value[b] &&
          value[a] === value[c]
        ) {
          console.log('value[a]: '   value[a])
          return value[a]
        }
      }
      return null
    }
    function checkForTieGame () {
      // make it a boolean
      // let isTie = true
      // check each space on the board
      squares.value.forEach((s) => {
        // if a space is available
        // if (s === null) isTie = false
      })
      // if tie is true, end the game
      // if (isTie === true) gameOver.value = true
    }
    function takeTurn (n) {
      console.log('takeTurn value: '   n)
      if (winner.value) return
      squares.value[n] = turn.value
      checkForTieGame()
      turn.value = turn.value === 'X' ? 'O' : 'X'
      console.log('player: '   turn.value)
    }
    function reset () {
      turn.value = 'O'
      console.log(squares.value.length)
      squares.value = squares.value.map((square) => '')
      // for (let i = 0; i <= 8; i  ) squares.value.push('') // make a blank board
    }
    return { squares, turn, winner, checkForWinner, takeTurn, reset }
  }
}
</script>

<style scoped>
button{
  margin-top: 40px;
}
#board {
  border: 1px solid darkred;
  height: 400px;
  width: 400px;
  margin:0 auto;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}
.square {
  background: #fff;
  border: 1px solid #999;
  /*float: left;*/
  font-size: 70px;
  font-weight: bold;
  line-height: 34px;
  height: 100px;
  width: 100px;
  margin-right: -1px;
  margin-top: -1px;
  padding: 0;
  text-align: center;
}
</style>

Thank you for your time

CodePudding user response:

Set key in your v-for loop to be unique(index) , so replace :key="square" with :key="index"

const { ref, computed } = Vue

const app = Vue.createApp({
  props: {
    msg: String // Vue has prop typechecking by default
  },
  setup () {
    const turn = ref('X') // player first turn
    const squares = ref([])
    for (let i = 0; i <= 8; i  ) squares.value.push('') // make a blank board}
    console.log('squares value: '   squares.value)
    const winner = computed(() => checkForWinner(squares.value.flat())) // check 4 winner everytime board changes
    console.log('computed:'   squares.value.flat())
    function checkForWinner (value) {
      console.log('check4Winner: '   value)
      // NOTE: in this version we have a
      const lines = [
        [0, 1, 2],
        [3, 4, 5],
        [6, 7, 8], // horizontal wins
        [0, 3, 6],
        [1, 4, 7],
        [2, 5, 8], // vertical wins
        [0, 4, 8],
        [2, 4, 6] // cross wins
      ]
      for (let i = 0; i < lines.length; i  ) {
        const [a, b, c] = lines[i]
        if (
          value[a] &&
          value[a] === value[b] &&
          value[a] === value[c]
        ) {
          console.log('value[a]: '   value[a])
          return value[a]
        }
      }
      return null
    }
    function checkForTieGame () {
      // make it a boolean
      // let isTie = true
      // check each space on the board
      squares.value.forEach((s) => {
        // if a space is available
        // if (s === null) isTie = false
      })
      // if tie is true, end the game
      // if (isTie === true) gameOver.value = true
    }
    function takeTurn (n) {
      console.log('takeTurn value: '   n)
      if (winner.value) return
      squares.value[n] = turn.value
      checkForTieGame()
      turn.value = turn.value === 'X' ? 'O' : 'X'
      console.log('player: '   turn.value)
    }
    function reset () {
      turn.value = 'O'
      squares.value = Array(9).fill('');  
    }
    return { squares, turn, winner, checkForWinner, takeTurn, reset }
  }
})
app.mount('#demo')
button{
  margin-top: 40px;
}
#board {
  border: 1px solid darkred;
  height: 200px;
  width: 200px;
  margin:0 auto;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}
.square {
  background: #fff;
  border: 1px solid #999;
  /*float: left;*/
  font-size: 70px;
  font-weight: bold;
  line-height: 34px;
  height: 50px;
  width: 50px;
  margin-right: -1px;
  margin-top: -1px;
  padding: 0;
  text-align: center;
}
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<div id="demo">
  <h2>{{ msg }}</h2>
  <h2 v-if="winner" >Winner: {{ winner }}</h2>
  <h2 v-else>Player Move: {{ turn }}</h2>
  <div id="board">
                                                             <!--            
  • Related