programing

v-model이 구성 요소의 로컬 데이터 대신 Vuex 상태를 변환하는 이유는 무엇입니까?

firstcheck 2022. 7. 16. 08:38
반응형

v-model이 구성 요소의 로컬 데이터 대신 Vuex 상태를 변환하는 이유는 무엇입니까?

첫 번째 Vue 프로젝트를 만들었는데, 모든 것이 괜찮았습니다.그래서 Vuex를 추가했습니다(앞으로 불필요한 것은 없고, 흥미를 위해서 시도했습니다).그리고, 엄밀한 모드를 유효하게 하기 전까지는, 모든 것이 정상이었습니다.컴포넌트가 외부 변환의 스토리지 상태를 변환하는 것으로 나타났습니다만, 저는 그것을 원하지 않고 컴포넌트에 nessessary 객체의 로컬 복사를 만들었습니다.data().

제 의도는 부모 컴포넌트에 로컬 객체를 만들고 그 속성을 자식 컴포넌트에 전달하는 것이었습니다.v-model(알고 있습니다. 이벤트 주도의 통사당입니다.v-bind그리고.v-on:input로컬 오브젝트가 갱신되었을 때(에 의해 자녀에게 영향을 줍니다).v-model). 부모 컴포넌트가 액션을 디스패치하여 저장하는 방법입니다.대신 외부 변환으로 인해 오류 메시지가 표시되며, 두 번째 이후의 입력 이벤트에서만 발생합니다.

또, ProdutRow 컴포넌트 워쳐로 다음의 행을 치환하면 동작합니다.

item: {
                handler(value) {
                    this.$store.dispatch('updateProduct', {
                        product: value,
                        index: this.index,
                    });
                },
                deep: true,
            }

포함:product: {...value},또는Object.assign({}, value)그러나 스토어 액션에 있는 동일한 코드는 동일 오류를 발생시키지 않습니다.

하지 않다data()지정된 소품 복사본을 생성하시겠습니까?그렇다면 Object.assign이 스토어에서 작동하지 않는 이유는 무엇입니까?

코드:

store.displaces를 설정합니다.

    import Vue from 'vue';
    import Vuex from 'vuex';
    import {ADD_PRODUCT, UPDATE_PRODUCT, DELETE_PRODUCT, UPDATE_FORM, UPDATE_PREPAYMENT_IN_PERCENT} from './mutation-types';
    import _ from 'lodash';

    Vue.use(Vuex);

    let id = 1;
    const product = {
        order: id++,
        name: '',
        size: '',
        content: '',
        price: 0,
        number: 1,
        discount: '',
        guarantee: 0,
        promotion: 0,
        location: '',
        sum: 0,
    };
    export default new Vuex.Store({
        strict: true,
        state: {
            products: [
                Object.assign({}, product),
            ],
            form: {
                prepaymentInPercent: 100,
            }

        },
        getters: {
            total(state) {
                return state.products.reduce(function (acc, cur, index, array) {
                    return array.length > 1 ? acc + cur.sum : cur.sum;
                }, 0);
            },
            rest(state, getters) {
                return getters.total - getters.prepaymentInRub;
            },
            prepaymentInRub(state, getters) {
                return getters.total * state.form.prepaymentInPercent / 100;
            }
        },
        mutations: {
            [ADD_PRODUCT](state, product) {
                state.products.push(product);
            },
            [UPDATE_PRODUCT](state, {product, index}) {
                state.products.splice(index, 1, product);
            },
            [DELETE_PRODUCT](state, index) {
                state.products.splice(index, 1);
            },
            [UPDATE_FORM](state, form) {
                state.form = form;
            },
            [UPDATE_PREPAYMENT_IN_PERCENT](state, percent) {
                state.form.prepaymentInPercent = percent;
            }

        },
        actions: {
            addProduct({commit}) {
                let newProduct = Object.assign({}, product);
                newProduct.order = id++;
                commit(ADD_PRODUCT, newProduct);
            },
            updateProduct: _.debounce(function ({commit}, product) {
                commit(UPDATE_PRODUCT, product);
            }, 1),
            deleteProduct({commit, state}, index) {
                state.products.length > 1 && commit(DELETE_PRODUCT, index)
            },
            updatePrepaymentInPercentByRub({commit, getters}, rubles) {
                let percent = Math.round(rubles / getters.total * 100);
                commit(UPDATE_PREPAYMENT_IN_PERCENT, percent);
            }
        },
    });

제품 테이블표시하다

    <template>
      <table border="0">
        <thead>
        <tr>
          <th class="pointer" @click="addProduct">+</th>
          <th>Номер</th>
          <th>Название</th>
          <th>Размер</th>
          <th>Наполнение</th>
          <th>Цена</th>
          <th>Количество</th>
          <th>Скидка</th>
          <th>Акция</th>
          <th>Сумма</th>
          <th>Гарантия</th>
          <th>Заказ</th>
          <th class="pointer" @click="toJSON">JSON</th>
        </tr>
        </thead>
        <tbody>
        <template v-for="(product, index) in products">
          <ProductRow
                  :initialItem="product"
                  :key="product.order"
                  :index="index"
          />
        </template>
        <tr>
          <td colspan="12">{{total}}</td>
          <td>{{json}}</td>
        </tr>
        </tbody>
      </table>
    </template>

    <script>
      import ProductRow from './ProductRow';
      import {mapGetters, mapActions, mapState} from 'vuex';

      export default {
        components: {
          ProductRow,
        },
        name: 'ProductTable',
        data() {
          return {
            json: '',
          };
        },
        computed: {
          ...mapState(['products']),
          ...mapGetters(['total']),
        },
        methods: {
          ...mapActions(['addProduct']),
          toJSON() {
            this.json = JSON.stringify({
              products: this.products,
              total: this.total,
            }, null, '\t');
          },
        },
      };
    </script>

ProductRow

<template>
    <tr>
        <td colspan="2" class="id">{{indexFrom1}}</td>
        <Editable v-model="item.name"/>
        <Editable v-model="item.size"/>
        <Editable v-model="item.content"/>
        <Editable v-model.number="item.price"/>
        <Editable v-model.number="item.number"/>
        <Editable v-model="item.discount"/>
        <td>
            <select v-model="item.promotion">
                <option selected="" value="0">Нет</option>
                <optgroup label="Новоселы">
                    <option data-text="Нов." value="5">Новоселы -5%</option>
                    <option data-text="Нов." value="10">Новоселы -10%</option>
                    <option data-text="Нов." value="15">Новоселы -15%</option>
                </optgroup>
            </select>
        </td>
        <td>{{sum}}</td>
        <Editable v-model.number="item.guarantee"/>
        <td>
            <select v-model="item.location">
                <option selected value="">Услуги</option>
                <option value="СКЛАД">Склад</option>
                <option value="ЗАКАЗ">Заказ</option>
            </select>
        </td>
        <td>
            <span class="table-remove" @click="removeProduct(index)">Удалить</span>
        </td>
    </tr>
</template>

<script>
    import Editable from './EditableCell';

    export default {
        components: {
            Editable,
        },
        name: 'ProductRow',
        props: {`enter code here`
            initialItem: Object,
            index: Number,
        },
        data() {
            return {
            item: this.initialItem
        };

        },
        computed: {
            sum() {
                let prod = this.item.price * this.item.number;
                let discounted = this.isDiscountInPercent(this.item.discount) ?
                    prod * this.getCoeffFromPercent(this.item.discount) :
                    prod - this.item.discount;
                let result = Math.round(discounted * this.getCoeffFromPercent(this.item.promotion));
                return result > 0 ? result : 0;
            },
            indexFrom1() {
                return this.index + 1;
            },
        },
        methods: {
            getCoeffFromPercent(percent) {
                return 1 - parseInt(percent) / 100;
            },
            isDiscountInPercent(discount) {
                return ~discount.indexOf('%') ? true : false;
            },
            removeProduct(index) {
                // console.log(arguments);
                this.$store.dispatch('deleteProduct', index)

            }
        },
        watch: {
            sum() {
                this.item.sum = this.sum;
            },
            item: {
                handler(value) {
                    this.$store.dispatch('updateProduct', {
                        product: value,
                        index: this.index,
                    });
                },
                deep: true,

            },
        },
    };
</script>

아니요.data()는 아이템 오브젝트의 복사본을 생성하지 않으므로 이 코드에서는 오브젝트를 참조로 전달합니다.

data() {
   return {
        item: this.initialItem
    };
}

즉, 스토어의 제품 개체가 다음 개체와 정확히 일치합니다.this.itemProductRow 컴포넌트에 있습니다.이 때문에, 접속할 때v-model매장 내 제품 오브젝트를 직접 변경할 수 있습니다.

다음을 사용하여 제품 개체 복제Object.assign()사용할 수 없습니다.ProductRow 구성 요소에서 복제를 수행해야 합니다.

data() {
   return {
      item: Object.assign({}, this.initialItem)
   };
}

이렇게 하면 카피가 생성되어 스토어에서 제품을 직접 수정하지 않게 됩니다.

언급URL : https://stackoverflow.com/questions/50717471/why-does-v-model-mutate-vuex-state-instead-of-componetss-local-data

반응형