Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Nielson's avatar
Level 14

Unwanted rerendering of Vue component

Hello!

To get to the point right of the bat.

I have two Vue components, a parent and a child. I also use Pinia for storing the state used in other components.

When I click on a layer, it selects that layer and put it in the Pinia store. If I click on another layer, it selects this layer and add it to the Pinia store, right after it clears the state in the Pinia store (this.data = []).

If I want to get the selected state of the Layer component within that component from my Pinia store with:

layers.selected(layer.id)

this forces to rerender the layer component everytime theres a change in the Pinia store. I mean, ofc the state should change so I can change the class of the layer component based on its selected state, but i'm also using a library to move these layers around and their changed position gets reverted when I deselect the layer after moving it.

It only happens if I render the state from the Pinia store within the component. I might have forgotten about how to tackle the rendering of components in Vue, but my mind is mushy after severalt tries with computed properties and so forth that I just can see a solution right now.

Here's my code (i left out a lot of other things that I use to move around the layers and such to keep it simple):

Parent (Canvas.vue):

<template>
<div class="flex items-center justify-center w-full h-full overflow-scroll">
	<layer 
		v-for="layer in project.layers" 
		:key="layer.id" 
		:layer="layer"     
		@mousedown.exact.stop="layers.select(layer.id)"
		/>
</div>
</template>

<script setup>
import Layout from '@/Layouts/AppLayout.vue'
import Layer from '@/Components/Layer.vue'
import { useLayersStore } from '@/stores/LayersStore';

defineOptions({ layout: Layout })
const props = defineProps(['project'])
const layers = useLayersStore();
</script>

Child (Layer.vue):

<template>
<div :data-id="layer.id" :data-x="layer.x" :data-y="layer.y" :style="layerStyle" :class="layerClass">
    <img src="/man.png" class="h-32 w-32 mb-3">
    {{ layer.text }}
</div>
</template>

<script setup>
const props = defineProps(['layer'])
import { computed } from 'vue'
import { useLayersStore } from '@/stores/LayersStore';
const layers = useLayersStore();

const layerStyle = computed(() => ({
  width: `${props.layer.width}px`,
  height: `${props.layer.height}px`,
  transform: `translate(${props.layer.x}px, ${props.layer.y}px)`,
}));

const layerClass = computed(() => [
  'drag-resize absolute select-none flex flex-col items-center justfiy-center h-12 w-12 border border-neutral-300 hover:border-blue-500 p-2 bg-white',
  layers.selected(props.layer.id) ? 'ring-2 ring-offset-2 ring-blue-500' : '',
]);
</script>

Pinia store:

import { defineStore } from 'pinia';

export let useLayersStore = defineStore('selected', {
    state(){
        return {
            data: []
        };
    },

    actions: {
        selected(id){
            return this.data.includes(id);
        },

        select(id){
            if(this.data.includes(id)){
                return
            }

            this.data = [],

            this.data.push(id);
        },

        clear(){
            this.data = [];
        }
    },
});
0 likes
1 reply
Nielson's avatar
Nielson
OP
Best Answer
Level 14

I think I might know what the problem is. When moving the layer i'm only updating the data-x, data-y and the style on the layer, but i'm not updating the layers data and when it re-renders because of changes, it reverts back to the initial data that is being passed to the component, which hasn't changed at all.

I should probably have caught that a bit earlier...

Please or to participate in this conversation.