英文:
How can I prevent a method called by a Vue component from running every time the v-model changes?
问题
我有一个表单,从一个API中填充了多个下拉列表,所以我创建了一个从该API获取列表的方法(getList()
)。下拉列表使用Vuetify的v-autocomplete
组件构建,它使用items
属性来填充列表,我从该属性中调用getList()
。
我的问题是,所有问题共享一个v-model
对象来存储响应,每当v-model
更改时,所有自动完成都会再次调用getList()
方法来重新填充列表。由于我有多个问题,每个问题都会多次调用API,所以这个表单运行得相当慢。
以下是这个问题的示例:
<template>
<v-app>
<v-container>
<v-text-field label="文本问题" v-model="responses.text"></v-text-field>
<v-autocomplete
label="随机问题"
:items="getList()"
v-model="responses.autocomplete"
></v-autocomplete>
<p>文本 v-model: {{ responses.text }}</p>
<p>自动完成 v-model: {{ responses.autocomplete }}</p>
</v-container>
</v-app>
</template>
<script>
export default {
data() {
return {
responses: {},
};
},
methods: {
getList() {
console.log('获取列表');
return ['value1', 'value2', 'value3'];
},
},
};
</script>
请注意,每当您向文本字段添加新字符时,都会调用getList()
方法(请查看控制台)。
我的问题是,有没有办法阻止每次v-model
更改时都调用getList()
方法?
我尝试过的方法:
- 为每个问题分配自己的
v-model
,以便它们不会相互影响。不幸的是,这并不起作用。似乎每当数据发生更改时,getList()
方法都会被调用。请查看另一个示例:
<template>
<v-app>
<v-container>
<v-text-field label="文本问题" v-model="text"></v-text-field>
<v-autocomplete
label="随机问题"
:items="getList()"
v-model="autocomplete"
></v-autocomplete>
<p>文本 v-model: {{ text }}</p>
<p>自动完成 v-model: {{ autocomplete }}</p>
</v-container>
</v-app>
</template>
<script>
export default {
data() {
return {
responses: {},
text: '',
autocomplete: '',
};
},
methods: {
getList() {
console.log('获取列表');
return ['value1', 'value2', 'value3'];
},
},
};
</script>
- 在
mounted
钩子中获取列表。虽然这解决了这个问题,但在我的情况下,我不能使用它,因为一些问题的下拉列表依赖于其他问题。例如,如果问题1的响应是A,问题2将获得列表[x,y,z],但如果响应是B,它将获得列表[q,r,s]。因此,我确实需要问题2对问题1做出反应,但我不需要它对问题3做出反应。
所以,您有没有关于通过仅在实际需要时调用getList
来提高此组件性能的提示?
英文:
I have a form that populates a number dropdown lists from an API, so I created a method that gets the list (getList()
) from that API. The dropdowns are built using the Vuetify v-autocomplete component, which populate the list using the items
prop and I am calling getList()
from this prop.
My problem is that all of the questions share a v-model object to store the responses and every time the v-model changes, all of the autocompletes call the getList()
method again to repopulate the lists. Since I have multiple questions and each is making an API call multiple times, this form is running quite slowly.
Here's an example of this:
<template>
<v-app>
<v-container>
<v-text-field label="text question" v-model="responses.text"></v-text-field>
<v-autocomplete
label="random question"
:items="getList()"
v-model="responses.autocomplete"
></v-autocomplete>
<p>Text v-model: {{ responses.text }}</p>
<p>Autocomplete v-model: {{responses.autocomplete}}</p>
</v-container>
</v-app>
</template>
<script>
export default {
data() {
return {
responses: {},
}
},
methods: {
getList() {
console.log('Getting list')
return ['value1', 'value2', 'value3']
},
},
}
</script>
Note that every time you add a new character to the text field, the getList()
method is called (check the console).
My question is, is there a way to prevent the getList()
method from getting called every time the v-model changes?
What I've tried:
- Giving each question its own v-model so they don't affect each other. Unfortunately this doesn't work. It looks like any time any of the data changes, the
getList()
method is called. See this other example:
<template>
<v-app>
<v-container>
<v-text-field label="text question" v-model="text"></v-text-field>
<v-autocomplete
label="random question"
:items="getList()"
v-model="autocomplete"
></v-autocomplete>
<p>Text v-model: {{ text }}</p>
<p>Autocomplete v-model: {{autocomplete}}</p>
</v-container>
</v-app>
</template>
<script>
export default {
data() {
return {
responses: {},
text: '',
autocomplete: '',
}
},
methods: {
getList() {
console.log('Getting list')
return ['value1', 'value2', 'value3']
},
},
}
</script>
- Getting the lists in the
mounted
hook. While this solves this problem, I cannot use it in my case because the dropdown list of some questions are dependent on other questions. For example, if Question 1 gets a response of A, Question 2 will get list [x, y, z], but if the response is B, it will get list [q, r, s]. So I do need Question 2 to react to Qestion 1, but I don't need it to react to Question 3.
So yes, any tips on improving the performance of this component by calling getList
only when it's actually needed?
答案1
得分: 1
将当前的列表项存储在数据中,但不要在mounted
中设置它,而是通过watcher
进行更新。
watch: {
'responses.text': {
handler(current, old) {
if (!this.needsReload(current, old)){
return
}
this.listItems = this.getList(current)
},
immediate: true,
},
},
设置immediate:true
标志将在设置watcher
时触发初始加载。
在你的示例中,你可以使用computed
,因为getList()
是同步的,但当你调用API时,应该坚持使用watcher
,因为computed应该没有副作用。
这是更新后的示例,根据文本输入中的第一个字母填充列表。
英文:
As you already did, store the current list items in data, but instead of setting it in mounted, updated it through a watcher.
watch: {
'responses.text': {
handler(current, old) {
if (!this.needsReload(current, old)){
return
}
this.listItems = this.getList(current)
},
immediate: true,
},
},
Setting the immediate:true
flag will trigger an initial load when the watcher is set up.
In your example, you could use a computed, since getList()
is synchronous, but when you call an API, you should stick to a watcher since computeds should be free of side-effects.
Here is the updated playground, where the list is filled according to the first letter in the text input.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论