Vue在提交表单时不渲染UI更改。

huangapple go评论61阅读模式
英文:

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

&lt;template&gt;
  &lt;div class=&quot;product-list&quot;&gt;
    &lt;NewItemForm&gt;&lt;/NewItemForm&gt;
    &lt;ul&gt;
      &lt;ProductListItem
        v-for=&quot;product in productsList&quot;
        v-bind:key=&quot;product.product.id&quot;
        :title=&quot;product.product.title&quot;
        :price=&quot;+product.product.price&quot;
        :id=&quot;product.product.id&quot;
      /&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import ProductListItem from &quot;./ProductListItem.vue&quot;;
import NewItemForm from &quot;./NewItemForm.vue&quot;;
import { mapActions, mapGetters } from &quot;vuex&quot;;

export default {
  name: &quot;ProductList&quot;,
  components: {
    ProductListItem,
    NewItemForm,
  },

  methods: {
    ...mapActions([&quot;getProducts&quot;]),
  },

  computed: { ...mapGetters([&quot;productsList&quot;]) },

  created() {
    this.getProducts();
  },
};
&lt;/script&gt;

store.js

import Vue from &quot;vue&quot;;
import Vuex from &quot;vuex&quot;;
import axios from &quot;axios&quot;;

Vue.use(Vuex);

export const store = new Vuex.Store({
  state: {
    products: [],
  },

  mutations: {
    addNewProduct: (state, product) =&gt; {
      product.id = product.name;
      state.products.unshift(product);
    },
    setProducts: (state, products) =&gt; {
      for (const name in products) {
        products[name].product.id = name;
        state.products = [...state.products, products[name]];
      }
    },
  },

  getters: {
    productsList: (state) =&gt; state.products,
  },

  actions: {
    async addNewProduct({ commit }, product) {
      const response = await axios.post(
        &quot;https://vue-s-261e8-default-rtdb.firebaseio.com/products.json&quot;,
        product
      );
      commit(&quot;addNewProduct&quot;, response.data);
    },

    async getProducts({ commit }) {
      try {
        const response = await axios.get(
          &quot;https://vue-s-261e8-default-rtdb.firebaseio.com/products.json&quot;
        );
        commit(&quot;setProducts&quot;, response.data);
      } catch (err) {
        console.log(err);
      }
    },
  },
});

NewItemForm.vue

&lt;template&gt;
  &lt;div&gt;
    &lt;form class=&quot;form&quot;&gt;
      &lt;label for=&quot;name&quot;&gt;Product name&lt;/label&gt;
      &lt;input type=&quot;text&quot; name=&quot;name&quot; v-model=&quot;product.title&quot; /&gt;
      &lt;label for=&quot;description&quot;&gt;Product description&lt;/label&gt;
      &lt;input type=&quot;text&quot; name=&quot;description&quot; v-model=&quot;product.description&quot; /&gt;
      &lt;label for=&quot;price&quot;&gt;Product price&lt;/label&gt;
      &lt;input type=&quot;text&quot; name=&quot;price&quot; v-model=&quot;product.price&quot; /&gt;
    &lt;/form&gt;
    &lt;button class=&quot;button&quot; type=&quot;submit&quot; v-on:click.prevent=&quot;onSubmit&quot;&gt;
      Add new item
    &lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import { mapActions } from &quot;vuex&quot;;
export default {
  name: &quot;NewItemForm&quot;,

  data() {
    return {
      product: {
        title: &quot;&quot;,
        description: &quot;&quot;,
        price: &quot;&quot;,
      },
    };
  },

  methods: {
    ...mapActions([&quot;addNewProduct&quot;]),
    onSubmit() {
      this.addNewProduct({
        product: this.product,
      });
    },
  },
};
&lt;/script&gt;

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) =&gt; {
    product.id = product.name;
    // 可能不需要这个特定更改
    // 可以尝试不加这行
    state.products = [...state.products, product]
},

最后将 addNewProduct action 更改为以下内容:

async addNewProduct({ commit }, product) {
    await axios.post(
      &quot;https://vue-s-261e8-default-rtdb.firebaseio.com/products.json&quot;,
       product
    );
    commit(&quot;addNewProduct&quot;, product);
}

这应该解决你的响应性问题并正确更新你的数组。希望这有所帮助 Vue在提交表单时不渲染UI更改。

英文:

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) =&gt; {
    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(
      &quot;https://vue-s-261e8-default-rtdb.firebaseio.com/products.json&quot;,
       product
    );
    commit(&quot;addNewProduct&quot;, product);
}

This should fix your reactivity issues and correctly update your array. Hope this helped Vue在提交表单时不渲染UI更改。

huangapple
  • 本文由 发表于 2023年6月11日 23:29:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76451182.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定