Reputation: 165
I have following code
<div class="gameContainer">
<span
v-for="(tile, index) in shuffledTiles"
:key="`${tile}_${index}`"
:data-key="`${tile}_${index}`"
:class="['tile-data px-2', tile, getClass(tile + index, tile)]"
@click="clickHandler(tile + index, tile)"
>
<img :src="`icons/${tile}.svg`" :alt="tile" />
</span>
</div>
When the above code is rendered, img src and alt values are completely different. I tried console.log inside shuffledTiles
and got values in browser console. one by Nuxt SSR
and one from my code. both are completely different order.
If you look at the dom tree, data-key is different and image src is different.
you can see the code here https://github.com/stefanre1/game/blob/master/components/Game.vue
I am not sure whats going on. any hint would be helpful. This is my first project.
Upvotes: 0
Views: 100
Reputation: 8040
This is because you are shuffling tiles twice. Once during SSR and one on the client side.
Do it only once. An easy solution can be to render the game component only on the client side by wrapping it up in client-only component
<client-only>
<game>
</client-only>
Or, may be better one is to create a prop for the game component, called tiles
. And, compute that within asyncData hook of the index page. And pass that as prop to game component.
In your index.vue
, you add
data: () => ({
tiles: null
}),
asyncData() {
const tilesData = [
'apple',
'orange',
'tomato',
'strawberry',
'tree',
'lemon'
]
const tiles = [...tilesData, ...tilesData]
for (let i = tiles.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1))
;[tiles[i], tiles[j]] = [tiles[j], tiles[i]]
}
return { tiles }
}
And, pass that as prop to game component
<game :tiles="tiles" />
And, in your game.vue component, you define tiles
as prop and use it.
props: {
tiles: {
type: Array,
required: true
}
},
Loop over tiles
instead of shuffledTiles
<span
v-for="(tile, index) in tiles"
:key="`${tile}_${index}`"
:data-key="`${tile}_${index}`"
:class="['tile-data px-2', tile, getClass(tile + index, tile)]"
@click="clickHandler(tile + index, tile)"
>
<img :src="`icons/${tile}.svg`" :alt="tile" />
</span>
The reason this works is because, asyncData
is executed only on the server side when the page loads. And whatever is returned from the asyncData is merged into the data of the page component. And, passed along to the browser. So when on the browser, the app is constructed again, it uses the same data instead of constructing a new one.
PS. Seems like a fun game. Good luck finishing it. :)
Upvotes: 2