简体   繁体   中英

VueJS computed property vs v-if, performance

I have a data array, and each item in the array has a state property that contains one of these values, allowed , pending , rejected . I want to display data in separate sections based on their state . Each data card has two buttons on it that can be used to change item state .

I'm using three computed properties to separate data like so:

computed: {
    pendingData() {
        return this.data.filter(x => x.state === 'pending')
    },
    allowedData() {
        return this.data.filter(x => x.state === 'allowed')
    },
    rejectedData() {
        return this.data.filter(x => x.state === 'rejected')
    }
}

and I display them in their own section using v-for .

Changing state occurs through an API call, so I need to send the id of item and new state to setState function:

<div class="state-change-buttons">
    <button @click="setState(item.id, 'allowed')">
        <span uk-icon="icon: check; ratio: 1.4"></span>
    </button>
    <button @click="setState(item.id, 'pending')">
        <span uk-icon="icon: future; ratio: 1.4"></span>
    </button>
</div>

and this is setState function:

setState(id, state) {
    const index = this.data.findIndex(x => x.id === id)
    this.$axios.post(`/api/${id}`, {state})
        .then(res => {
            this.data.splice(index, 1, res.data)
        })
        .catch(err => {
            this.$notify(err, 'danger')
        })
}

As you can see, to update my data array in realtime I have to find the index of selected item using findIndex .

Vue style guide suggests not to use v-if on the same element as v-for . But should I still avoid it, even if it decreases my app, time complexity?

current scenario:
3 computed property (O(3n)) + findIndex (O(n)) + 3 v-for (O(p + r + q))

conditional v-for :
3 conditional v-for (O(3n)) (no findIndex, this way I can pass index to setState directly)

conditional v-for code:

<div v-for="(item, index) in data" v-if="item.state === 'pending'" :key="item.id">
    <!-- data card body (including buttons) -->
</div>

<div v-for="(item, index) in data" v-if="item.state === 'allowed'" :key="item.id">
    <!-- data card body (including buttons) -->
</div>

<div v-for="(item, index) in data" v-if="item.state === 'rejected'" :key="item.id">
    <!-- data card body (including buttons) -->
</div>

It's unclear whether v-if is related to the parent or the child. You can use a template to resolve this issue:

<template v-for="(item, index) in data">
  <div v-if="item.state === 'rejected'" :key="item.id">
    <!-- data card body (including buttons) -->
  </div>
</template>

As the comment to your question says I can't understand either your computation without seeing the 2 proposed templates. Nevertheless, this is my personal preference when facing this kind of lists.

Have the data as an object. This way finding the value will be O(1). and will increase readability. Also have the array as a computed property.

export default {
  name: 'list',
  data: () => ({
    data: {
      'id1': {id: 'id1', state: 'pending'},
      'id2': {id: 'id2', state: 'allowed'},
      'id3': {id: 'id3', state: 'rejected'},
    },
  }),
  computed: {
    dataList() {
      return Object.values(this.data)
    },
    pendingData() {
        return this.dataList.filter(x => x.state === 'pending')
    },
    allowedData() {
        return this.dataList.filter(x => x.state === 'allowed')
    },
    rejectedData() {
        return this.dataList.filter(x => x.state === 'rejected')
    },
  },
  methods: {
    setState(id, state) {
    this.$axios.post(`/api/${id}`, {state})
      .then(res => {
          Object.assign(this.data[id], res.data);
      })
      .catch(err => {
          this.$notify(err, 'danger')
      })
    }
  }
};

Then you just use in the template like so:

<div v-for="item of pendingData" :key="item.id">
    <!-- data card body (including buttons) -->
</div>

<div v-for="item of  allowedData" :key="item.id">
    <!-- data card body (including buttons) -->
</div>

<div v-for="item of rejectedData" :key="item.id">
    <!-- data card body (including buttons) -->
</div>

NOTE: Code changed after author's comment to my response. so this way you avoid v-if because you are already iterating over different lists.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM