изменение v-модели при вводе сильно влияет на производительность

#javascript #vue.js #vuetify.js

#javascript #vue.js #vuetify.js

Вопрос:

Итак, у меня есть страница, отображающая v-список на основе массива, подобного этому :

 <v-list-tile v-for="item in array">
{{item}}
</v-list-tile>
  

и диалоговое окно с v-текстовым полем :

 <v-dialog>
    <v-text-field v-model="myInput">
    </v-text-field>
</v-dialog>
  

На данный момент это довольно нормально.
Но с помощью теста производительности я увидел, что для каждого события, вызванного изменением в модели myInput (например, нажатием клавиши), v-for также запускается для повторного отображения списка, когда они фактически не связаны.

В моем огромном массиве это серьезная проблема и делает пользовательский интерфейс действительно отстающим. Я думаю, что это нормальное поведение для приложения vuejs, но мне было интересно, могу ли я точно указать элементу желания проверить повторный рендеринг.

Я пробовал некоторые операторы v-if, но это не помогло.

Я надеюсь, что на это есть ответ, я думаю, я что-то упускаю.

Если вы хотите протестировать то, о чем я говорю здесь, это готовый к работе HTML-файл, пожалуйста, отладьте его с помощью своей консоли отладки, вы увидите [vue warn] сообщение о дублированном ключе, подтверждающее тот факт, что v-for действительно вызывается при каждом нажатии клавиши.

Представьте теперь, что массив (здесь элементы) намного больше этого и упакован в сложные компоненты, выполнение этого вызова слишком сильно влияет на производительность, когда мы просто стремимся изменить значение «myInput».

 
<html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        {{data}}
        <ul>
            <li v-for="item in items" :key="item">
                {{ item.message }}
            </li>
        </ul>
        <input v-model="data"></input>
    </div>
</body>

<script>
    new Vue({
        el: '#app',
        data: () => ({
            data: '',
            items: [{
                    message: 'Foo'
                },
                {
                    message: 'Bar'
                }
            ]
        })
    })
</script>

</html>
  

Комментарии:

1. находится ли диалоговое окно внутри списка?

2. @dandavis Это не так.

3. возможно, попробуйте использовать v-bind вместо v-model. Для v-bind вы можете указать, какой тип события вы хотите обновить в поле

4. Для меня работает нормально, как вы улучшаете «производительность»?

Ответ №1:

Вот codepen, показывающий внутренний цикл в его собственном компоненте

Codepen.io

Я добавил элементы списка Date.now() после items[x].message , чтобы они отображались при повторном отображении списка.

В случае, если codepen когда-либо выйдет из строя:

 <html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        Main vue: {{data}}
        <loop-component :data="loopdata"></loop-component>
        <input v-model="data"></input>
        <input v-model="loopdata"></input>
    </div>
<script>
Vue.component('loop-component', {
    props: ['data'],
    data() {
        return {
            items: [
                {message: 'Foo'},
                {message: 'Bar'}
            ]
        }
    },
    template: `
<div>
Loop component: {{ data }}
<ul>
  <li v-for="(item, index) in items" :key="index">
    {{ item.message   ' Date.now(): '   Date.now() }}
  </li>
</ul>
</div>
`
});

let app = new Vue({
    el: '#app',
    data: () => ({
        data: '',
        'loopdata': '',
        items: [
            {message: 'Foo'},
            {message: 'Bar'},
        ]
    }),
});
</script>
</body>
</html>
  

Ответ №2:

Попробуйте использовать.отложенный модификатор для синхронизации после событий изменения.


<input v-model.lazy="data"></input>

https://v2.vuejs.org/v2/guide/forms.html#lazy

Редактировать

@IVO GELOV прав, когда изменяется компонент, это повторный рендеринг. Решение состоит в разделении вашего компонента на несколько дочерних компонентов.

https://v2.vuejs.org/v2/guide/reactivity.html

Это код, использующий слоты, чтобы сделать его похожим на ваш пример.

HTML

     <div id="app">
   <new-component>
     <ul>
       <li v-for="item in items" :key="item">
         {{ item.message }}
       </li>       
     </ul>    
   </new-component>
</div>
  

Javascript

     Vue.component('new-component', {
  data: () => {
    return {
      data: ''
    }
  },
  template: `
    <div>
      <div>{{ data }}</div>
      <slot></slot>
      <input v-model="data"></input>
    </div>`
})

new Vue({
        el: '#app',
        data: () => ({            
            items: [{
                    message: 'Foo'
                },
                {
                    message: 'Bar'
                }
            ]
        })
    })
  

Комментарии:

1. Я не знаю, заметил ли кто-нибудь это, но количество предупреждений соответствует формуле. warning_errors = array.length (array.length - 1) Я найду наиболее удовлетворительный ответ.

Ответ №3:

Начиная с Vue 2.0 , всякий раз, когда обнаруживается изменение, весь компонент повторно отображается. Если вы хотите избежать этого — разделите свой компонент на несколько дочерних компонентов.

Ваш пример не доказывает вашу точку зрения — тот факт, что внутри есть предупреждение о дублирующихся ключах, v-for не означает, что v-for это пересчитывается при каждом нажатии клавиши. Чтобы подтвердить мое утверждение — просто измените свой код следующим образом:

 <li v-for="(item,idx) in items" :key="idx">
  

Теперь предупреждения нет.

Комментарии:

1. Это не решает проблему. Скрывает ошибку, но не решает проблему с производительностью. Дело не в предупреждении…

2. Итак, ваш пример не имеет отношения к вашему вопросу / жалобе. И вы, кажется, игнорируете мой совет разделить компонент на дочерние компоненты — например, один компонент для ввода и другой компонент для v-list .