VueJS Prevent child components from updating when parent updates

Viewed 314

Stack: Vue 2.6.11 Vuex 3.6.0

Problem: We have a lot of nested components, which are then again wrapped by a hover component. (We used vuetify initally but then created our own hover component for further debugging. As you will see the only data change occurs within the hover component. A boolean is changed. But the update events are triggered for all children. Ofcourse we still want actual updates to be reactive for all children. They are by no means static components. But we would also like for components to only be updated when actual updates on that component occur. In our live app we have up to 2000-3000 of the <D> ... </D> components and an ever deeper nested structure.

Our hover component:

<template>
  <div @mouseenter="hover = true" @mouseleave="hover = false">
    <slot :hover="hover"/>
  </div>
</template>
<script>
  export default {
    data: () => ({
      hover: false,
    }),
  }
</script>

The nested components, using the vue slot system as well as getters from vuex:

<A :a="getA(1)">
  <template #bs="{a}">
    <hoverOwn v-for="(b_id, b_index) in a.bs" :key="b_index">
      <template #default="hover_b">
        <B :b="getB(b_id)" :style="hover_b.hover?'background-color: green':''">
          <template #cs="{b}">
            <hoverOwn v-for="(c_id, c_index) in b.cs" :key="c_index">
              <template #default="c_hover">
                <C :c="getC(c_id)" :style="c_hover.hover?'background-color: blue':''">
                  <template #ds="{c}">
                    <hoverOwn v-for="(d_id, d_index) in c.ds" :key="d_index">
                      <template #default="d_hover">
                        <D @click.native="getD(d_id).value = !getD(d_id).value" :d="getD(d_id)" :style="d_hover.hover?'background-color: red':''">
                          <template #d>
                            <div v-if="d_hover.hover">t</div>
                          </template>
                        </D>
                      </template>
                    </hoverOwn>
                  </template>
                </C>
              </template>
            </hoverOwn>
          </template>
        </B>
      </template>
    </hoverOwn>
  </template>
</A>

This is how it looks rendered: Example page rendered as HTML

Each component prints to the console when being updated by the vue js update hook:

updated() {
   console.log('D updated');
}

When hovering the A area the console prints the following:

D updated
D updated
D updated
D updated
C updated
D updated
D updated
D updated
D updated
C updated
D updated
D updated
D updated
D updated
C updated
D updated
D updated
D updated
D updated
C updated
D updated
D updated
D updated
D updated
C updated
B updated

The example data:

{
as: {
    1: {bs: [1,2]}
  },
  bs: {
    1: {cs: [1,2,3,4,5]},
    2: {cs: [6,7,8,9,10]},
  },
  cs: {
    1: {ds: [1,2,3,4]},
    2: {ds: [5,6,7,8]},
    3: {ds: [9,10,11,12]},
    4: {ds: [13,14,15,16]},
    5: {ds: [17,18,19,20]},
    6: {ds: [21,22,23,24]},
    7: {ds: [25,26,27,28]},
    8: {ds: [29,30,31,32]},
    9: {ds: [33,34,35,36]},
    10: {ds: [37,38,39,40]},
  },
  ds: {
    1: {id: 1, value: false},
    2: {id: 2, value: false},
    3: {id: 3, value: false},
    4: {id: 4, value: false},
    5: {id: 5, value: false},
    6: {id: 6, value: false},
    7: {id: 7, value: false},
    8: {id: 8, value: false},
    9: {id: 9, value: false},
    10: {id: 10, value: false},
    11: {id: 11, value: false},
    12: {id: 12, value: false},
    13: {id: 13, value: false},
    14: {id: 14, value: false},
    15: {id: 15, value: false},
    16: {id: 16, value: false},
    17: {id: 17, value: false},
    18: {id: 18, value: false},
    19: {id: 19, value: false},
    20: {id: 20, value: false},
    21: {id: 21, value: false},
    22: {id: 22, value: false},
    23: {id: 23, value: false},
    24: {id: 24, value: false},
    25: {id: 25, value: false},
    26: {id: 26, value: false},
    27: {id: 27, value: false},
    28: {id: 28, value: false},
    29: {id: 29, value: false},
    30: {id: 30, value: false},
    31: {id: 31, value: false},
    32: {id: 32, value: false},
    33: {id: 33, value: false},
    34: {id: 34, value: false},
    35: {id: 35, value: false},
    36: {id: 36, value: false},
    37: {id: 37, value: false},
    38: {id: 38, value: false},
    39: {id: 39, value: false},
    40: {id: 40, value: false},
  }
}

Tried Solutions:

  1. We hoped vue 3 would solve this issue, but sadly this is not the case. We created this sample project in both vue 2 and vue 3 and both show the same results.

  2. We're going to try and create a pure css based hover solution. But since we also like to have that information as a variable it is not really a good solution.

  3. We tried multiple different ways of managing the data within vuex and loading it to the components in different ways. But we found that the issue always occurs with the vue component updates and the different vuex solutions don't change that.

Thank you for your help.

Cheers

Raphael

0 Answers
Related