英文:
Vue not rendering UI changes when submitting a form
问题
这可能是一个愚蠢的问题,但每当我提交一个表单以将新产品发布到productsList
时,UI不会立即渲染它,只有在我重新加载页面后才会显示。我正在将数据发布到Firebase并从中获取数据。
ProductList.vue
<template>
<div class="product-list">
<NewItemForm></NewItemForm>
<ul>
<ProductListItem
v-for="product in productsList"
:key="product.product.id"
:title="product.product.title"
:price="+product.product.price"
:id="product.product.id"
/>
</ul>
</div>
</template>
<script>
import ProductListItem from "./ProductListItem.vue";
import NewItemForm from "./NewItemForm.vue";
import { mapActions, mapGetters } from "vuex";
export default {
name: "ProductList",
components: {
ProductListItem,
NewItemForm,
},
methods: {
...mapActions(["getProducts"]),
},
computed: { ...mapGetters(["productsList"]) },
created() {
this.getProducts();
},
};
</script>
store.js
import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
products: [],
},
mutations: {
addNewProduct: (state, product) => {
product.id = product.name;
state.products.unshift(product);
},
setProducts: (state, products) => {
for (const name in products) {
products[name].product.id = name;
state.products = [...state.products, products[name]];
}
},
},
getters: {
productsList: (state) => state.products,
},
actions: {
async addNewProduct({ commit }, product) {
const response = await axios.post(
"https://vue-s-261e8-default-rtdb.firebaseio.com/products.json",
product
);
commit("addNewProduct", response.data);
},
async getProducts({ commit }) {
try {
const response = await axios.get(
"https://vue-s-261e8-default-rtdb.firebaseio.com/products.json"
);
commit("setProducts", response.data);
} catch (err) {
console.log(err);
}
},
},
});
NewItemForm.vue
<template>
<div>
<form class="form">
<label for="name">产品名称</label>
<input type="text" name="name" v-model="product.title" />
<label for="description">产品描述</label>
<input type="text" name="description" v-model="product.description" />
<label for="price">产品价格</label>
<input type="text" name="price" v-model="product.price" />
</form>
<button class="button" type="submit" @click.prevent="onSubmit">
添加新项目
</button>
</div>
</template>
<script>
import { mapActions } from "vuex";
export default {
name: "NewItemForm",
data() {
return {
product: {
title: "",
description: "",
price: "",
},
};
},
methods: {
...mapActions(["addNewProduct"]),
onSubmit() {
this.addNewProduct({
product: this.product,
});
},
},
};
</script>
我尝试设置了一个观察器,但这只引入了一个无限循环。
英文:
This is probably a dumb question, but whenever I submit a form to post a new product to the productsList
the UI does not render it immediately, only after I reload the page. I'm posting the data and fetching it from firebase
ProductList.vue
<template>
<div class="product-list">
<NewItemForm></NewItemForm>
<ul>
<ProductListItem
v-for="product in productsList"
v-bind:key="product.product.id"
:title="product.product.title"
:price="+product.product.price"
:id="product.product.id"
/>
</ul>
</div>
</template>
<script>
import ProductListItem from "./ProductListItem.vue";
import NewItemForm from "./NewItemForm.vue";
import { mapActions, mapGetters } from "vuex";
export default {
name: "ProductList",
components: {
ProductListItem,
NewItemForm,
},
methods: {
...mapActions(["getProducts"]),
},
computed: { ...mapGetters(["productsList"]) },
created() {
this.getProducts();
},
};
</script>
store.js
import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
products: [],
},
mutations: {
addNewProduct: (state, product) => {
product.id = product.name;
state.products.unshift(product);
},
setProducts: (state, products) => {
for (const name in products) {
products[name].product.id = name;
state.products = [...state.products, products[name]];
}
},
},
getters: {
productsList: (state) => state.products,
},
actions: {
async addNewProduct({ commit }, product) {
const response = await axios.post(
"https://vue-s-261e8-default-rtdb.firebaseio.com/products.json",
product
);
commit("addNewProduct", response.data);
},
async getProducts({ commit }) {
try {
const response = await axios.get(
"https://vue-s-261e8-default-rtdb.firebaseio.com/products.json"
);
commit("setProducts", response.data);
} catch (err) {
console.log(err);
}
},
},
});
NewItemForm.vue
<template>
<div>
<form class="form">
<label for="name">Product name</label>
<input type="text" name="name" v-model="product.title" />
<label for="description">Product description</label>
<input type="text" name="description" v-model="product.description" />
<label for="price">Product price</label>
<input type="text" name="price" v-model="product.price" />
</form>
<button class="button" type="submit" v-on:click.prevent="onSubmit">
Add new item
</button>
</div>
</template>
<script>
import { mapActions } from "vuex";
export default {
name: "NewItemForm",
data() {
return {
product: {
title: "",
description: "",
price: "",
},
};
},
methods: {
...mapActions(["addNewProduct"]),
onSubmit() {
this.addNewProduct({
product: this.product,
});
},
},
};
</script>
I have tried to setup a watcher, but that only introduced an infinite loop.
答案1
得分: 0
Vue 2 在处理状态时存在一些古怪的行为,特别是在处理数组时。我认为在这种情况下,你需要使用 Vue.set
,你可以在下面的链接中找到更多详细信息,那里也可以找到关于 Vue 2 中响应性的更多文档。
https://v2.vuejs.org/v2/guide/reactivity.html
你的示例中还似乎缺少一个组件(ProductListItem.vue)。
我建议升级到 Vue 3 并利用 Pinia,因为它现在是 VueX 的替代品。
如果你能上传一个包含完整问题的存储库,我将很乐意查看。
编辑:
在查看了存储库后,这似乎是修复方法:
将 addNewProduct
mutation 更改为以下内容:
addNewProduct: (state, product) => {
product.id = product.name;
// 可能不需要这个特定更改
// 可以尝试不加这行
state.products = [...state.products, product]
},
最后将 addNewProduct
action 更改为以下内容:
async addNewProduct({ commit }, product) {
await axios.post(
"https://vue-s-261e8-default-rtdb.firebaseio.com/products.json",
product
);
commit("addNewProduct", product);
}
这应该解决你的响应性问题并正确更新你的数组。希望这有所帮助
英文:
Vue 2 has some quirky behaviour with state, specifically when dealing with arrays. I believe in this case you'd need to use Vue.set
, which you can find more details about from the below link, there you can also find more documentation about reactivity in Vue 2.
https://v2.vuejs.org/v2/guide/reactivity.html
You also appear to be missing a component from your example (ProductListItem.vue)
I'd recommend upgrading to Vue 3 and take advantage of Pinia, as that is now the replacement for VueX.
If you could upload a repository with the problem in full, I'd happily take a look.
Edit:
After reviewing the repository, this looks like the fix:
change the addNewProduct
mutation to the following:
addNewProduct: (state, product) => {
product.id = product.name;
// this particular change might not be required
// feel free to try without
state.products = [...state.products, product]
},
and finally change the addNewProduct
action to the following:
async addNewProduct({ commit }, product) {
await axios.post(
"https://vue-s-261e8-default-rtdb.firebaseio.com/products.json",
product
);
commit("addNewProduct", product);
}
This should fix your reactivity issues and correctly update your array. Hope this helped
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论