• 赚钱入口【需求资源】限时招募流量主、渠道主,站长合作;【合作模式】CPS长期分成,一次推广永久有收益。主动打款,不扣量;

[Vue warn]: Error in callback for watcher “function () { return this._data.$$state }”: “Error: [vuex] do not mutate vuex store state outside mutation handlers.”

Vue cps12345 7个月前 (09-07) 506次浏览 0个评论

点击按钮 NewContract 或者 编辑Contact会调用 EditorCreate.vue中的 onSave 函数

**MyParent  Contracts.vue**
<template>
    <div class="container">
        <Create-Or-Edit-Contract
            :is-open.sync="dialog"
            :selectedObject.sync="selectedItem"
            :arrContracts.sync="contracts"
        />

        <div id="app">
            <v-app id="inspire">
                <v-data-table
                    :headers="headers"
                    :items="contracts"
                    sort-by="createdAt"
                    class="elevation-1"
                >
                    <template v-slot:top>
                        <v-toolbar flat color="white">
                            <v-toolbar-title>CONTRACTS</v-toolbar-title>
                            <v-divider class="mx-4" inset vertical></v-divider>
                            <v-spacer></v-spacer>
                            <v-btn
                                color="primary"
                                dark
                                class="mb-2"
                                @click="onOpenCreateOrUpdateDialog()"
                            >New Contract</v-btn>
                        </v-toolbar>
                    </template>

                    <template v-slot:item.actions="{ item }">
                        <v-icon small class="mr-2" @click="editItem(item)">mdi-pencil</v-icon>
                        <v-icon small @click="showDeleteDialog(item)">mdi-delete</v-icon>
                        <!-- <v-icon middle @click="goToRouteLeaves(item)">play_arrow</v-icon> -->
                    </template>
                </v-data-table>

                <v-dialog v-model="isDialogDeleteVisible" max-width="500px">
                    <v-card>
                        <v-card-title>Remove</v-card-title>
                        <v-card-text>Are you sure to delete?</v-card-text>
                        <v-card-actions >
                            <v-btn color="primary" text @click="isDialogDeleteVisible = false">Close</v-btn>
                            <v-btn color="primary" text @click="onDeleteItem">Delete</v-btn>
                        </v-card-actions>
                    </v-card>
                </v-dialog>
            </v-app>
        </div>
    </div>
</template>

<script>
import CreateOrEditContract from './CreateOrEditContract';
import UserContractsService from '../services/UserContractsService';
import { mapActions } from 'vuex';

export default {
    name: 'Admin',

    components: {
        CreateOrEditContract
    },

    data() {
        return {
            selectedItem: {
                startDate: ''
            },
            serverErrors: {
                startDate: ''
            },
            errorMessage: '',
            error: null,
            contracts: [],
            dialog: false,

            isDialogDeleteVisible: false,
            headers: [
                { text: 'Start', value: 'startDate' },
                { text: 'Duration', value: 'duration' },
                { text: 'Leave', value: 'leave' },
                { text: 'Actions', value: 'actions', sortable: false }
            ],
            defaultItem: {
                startDate: '',
                duration: '',
                leave: ''
            }
        };
    },

    created() {
        this.selectedItem = { ...this.defaultItem };
    },

    async mounted() {
        try {
             const { userId } = this.$route.params;
             const { data } = await UserContractsService.index(userId);
             this.contracts = data;
             this.contracts =  await this.getContracts(userId)
        } catch (error) {
            this.errorMessage =
                (error.response && error.response.data ? error.response.data : null) ||
                error.message ||
                error.toString();
        }
    },

    watch: {
        dialog(val) {
            val || this.close();
        }
    },

    methods: {
        editItem(item) {
            this.selectedItem = { ...item };
            this.dialog = true;
        },

        ...mapActions({ 
            removeContract: 'removeContract',
            getContracts: 'getContracts'           
            
            
            }),
        onDeleteItem() {
            //console.log(this.selectedItemlete)
            // this.removeContract({ contracts: this.contracts, selectedItemlete: this.selectedItemlete });
            this.removeContract(this.selectedItemlete)
            this.isDialogDeleteVisible = false;
        },

        showDeleteDialog(item) {
            this.selectedItemlete = item;
            this.isDialogDeleteVisible = !this.isDialogDeleteVisible;
        },

        close() {
            this.dialog = false;
            this.selectedItem = { ...this.defaultItem };
        },

        onOpenCreateOrUpdateDialog(item = {}) {
            this.dialog = true;

            if (item.id) {
                this.selectedItem = item;
            }
        },

        goToRouteLeaves(item) {
            this.$router.push(`/leaves/${item.id}`);
        },

        // getContracts(data){
        //     this.$store.commit('setContract', data)

        // }
    }
};
</script>

<style scoped>
v-btn {
    position: absolute;
}
</style>

Mychildren EditorCreate.vue

<template v-slot:top>
    <v-toolbar flat color="white">
        <v-dialog v-model="open" max-width="500px">
            <v-card>
                <v-card-title>
                    <span class="headline">{{ formTitle }}</span>
                </v-card-title>

                <v-card-text>
                    <v-container>
                        <v-row>
                            <v-col cols="12" sm="6" md="4">
                                <v-text-field
                                    v-model="selectedItem.startDate"
                                    label="Start Contract"
                                    name="name"
                                    prepend-icon="person"
                                    placeholder="YYYY-MM-DD"
                                    type="text"
                                    required
                                    :rules="nameErrors"
                                    @input="$v.selectedItem.startDate.$touch()"
                                    @blur="$v.selectedItem.startDate.$touch()"
                                    @keyup="clearServerErrors('name')"
                                />
                            </v-col>

                            <v-col cols="12" sm="6">
                                <v-select
                                    v-model="selectedItem.duration"
                                    :items="[1, 2, 3, 6, 12]"
                                    label="Duration Contract."
                                    required
                                />
                            </v-col>

                            <v-col cols="12" sm="6" md="4">
                                <v-select
                                    v-model="selectedItem.leave"
                                    :items="[20, 26]"
                                    label="Days off"
                                />
                            </v-col>
                        </v-row>
                    </v-container>
                </v-card-text>

                <v-card-actions>
                    <v-spacer></v-spacer>
                    <v-btn color="blue darken-1" text @click="close">Cancel</v-btn>
                    <v-btn color="blue darken-1" text @click="onSave" :disabled="!isValid">Save</v-btn>
                </v-card-actions>
            </v-card>
        </v-dialog>
    </v-toolbar>
</template>


<script>
import { validationMixin } from 'vuelidate';
import { required } from 'vuelidate/lib/validators';
import ContractService from '../services/ContractService';

import moment from 'moment';

export default {
    mixins: [validationMixin],

    props: {
        isOpen: Boolean,
        selectedObject: {
            Object,
            default: () => ({})
        },
        arrContracts: Array
    },

    validations: {
        selectedItem: {
            startDate: {
                required,
                isStartDate(value) {
                    return this.isStartDate(value);
                }
            }
        }
    },

    data() {
        return {
            serverErrors: {
                name: [],
                surname: [],
                email: [],
                birthdate: '',
                password: []
            },
            errorMessage: '',
            error: null,
            validationError: false,

            birthdateButton: false,
            isCreateOrUpdateDialogVisible: false
        };
    },
    computed: {
        open: {
            get() {
                return this.isOpen;
            },

            set(newValue) {
                this.$emit('update:isOpen', newValue);
            }
        },

        selectedItem: {
            get() {
                return this.selectedObject;
            },

            set(newValue) {
                this.$emit('update:selectedObject', newValue);
            }
        },

        contracts: {
            get() {
                return this.arrContracts;
            },

            set(newValue) {
                this.$emit('update:arrContracts', newValue);
            }
        },

        formTitle() {
            return this.selectedItem.id ? 'Edit Contract' : 'New Contract';
        },

        nameErrors() {
            const errors = [];

            if (!this.$v.selectedItem.startDate.$dirty) return errors;
            !this.$v.selectedItem.startDate.required && errors.push('Date is required');
            !this.$v.selectedItem.startDate.isStartDate && errors.push('Enter valid date');

            return errors;
        },

        isValid() {
            return !this.$v.$invalid;
        }
    },

    methods: {
        close() {
            this.open = false;
            this.selectedItem = { ...this.defaultItem };
            this.$v.$reset();
        },

        async onSave() {
            if (this.selectedItem.id) {
                const index = this.contracts.findIndex((contract) => contract.id === this.selectedItem.id);

                await ContractService.save(this.selectedItem);

                this.$set(this.contracts, index, this.selectedItem);
            } else {
                this.selectedItem.userId = this.$route.params.userId;

                const { data } = await ContractService.save(this.selectedItem);

                this.contracts.push(data);
            }

            this.close();
        },

        clearServerErrors(type) {
            this.serverErrors[type] = [];
        },

        isStartDate(value) {
            return moment(value, 'YYYY-MM-DD', true).isValid();
        }
    }
};
</script>

And My store.js:

import Vuex from 'vuex';
import { router } from '../router';
import ContractService from '@/services/ContractService';
import UserService from '@/services/UserService.js';
import UserContractsService from '../services/UserContractsService';

Vue.use(Vuex);

export default new Vuex.Store({
    strict: true,
    state: {
        token: null,
        user: [],
        index: null,
        roles: [],
        contracts: [],
        userId: null,
        selectedItem: null
    },
    getters: {
        isAuthenticated(state) {
            return state.token !== null;
        },
        isAdmin(state) {
            return !!state.roles.find((r) => r.name === 'admin');
        },
        isUser(state) {
            return !!state.roles.find((r) => r.name === 'user');
        },
        getUser(state) {
            return state.user;
        },
        getRoles(state) {
            return state.roles;
        }
    },
    mutations: {
        setToken(state, token) {
            state.token = token;
            localStorage.setItem('token', token);
        },
        setUser(state, user) {
            state.user = user;
            localStorage.setItem('user', JSON.stringify(user));
        },
        setRoles(state, roles) {
            state.roles = roles;
            localStorage.setItem('roles', JSON.stringify(roles));
        },
        clearAuthData(state) {
            state.token = null;
            state.user = null;
            state.roles = [];
            localStorage.removeItem('expirationDate');
            localStorage.removeItem('token');
            localStorage.removeItem('user');
            localStorage.removeItem('roles');
        },
        setContract(state, contracts) {
            state.contracts = contracts;
        },

        setUsers(state, payload) {
            state.user = payload.user;
        },

        DELETE_CONTRACT(state, contractId) {
            const index = state.contracts.findIndex((contract) => contract.id === contractId);

            state.contracts.splice(index, 1);
        },

        setUserId(state, userId) {
            state.userId = userId;
        }
    },

    actions: {
        async login({ commit, dispatch }, data) {
            try {
                const now = new Date();
                const expirationDate = new Date(now.getTime() + 600 * 1000); //take from backend

                localStorage.setItem('expirationDate', expirationDate);

                commit('setUser', data.user);
                commit('setToken', data.token);
                commit('setRoles', data.user.roles);

                dispatch('setLogoutTimer', 6000);
            } catch (error) {
                console.error(error);
            }
        },

        setLogoutTimer({ commit }, expirationTime) {
            setTimeout(() => {
                commit('clearAuthData');
                localStorage.removeItem('expirationDate');
                localStorage.removeItem('token');
                router.push('/login');
            }, expirationTime * 6000);
        },

        tryAutoLogin({ commit, dispatch }) {
            const token = localStorage.getItem('token');

            if (!token) {
                return;
            }

            const expirationDate = localStorage.getItem('expirationDate');
            const now = new Date();

            if (now >= expirationDate) {
                return;
            }
            dispatch('setLogoutTimer', 6000);
            const user = JSON.parse(localStorage.getItem('user'));
            const roles = JSON.parse(localStorage.getItem('roles'));

            commit('setToken', token);
            commit('setUser', user);
            commit('setRoles', roles);
            router.push('/user');
        },

        logout({ commit }) {
            commit('clearAuthData');
        },

        async removeContract({ commit }, contractId) {
            //     const index = payload.contracts.findIndex((contract) => contract.id === payload.selectedItemlete.id);
            //     payload.contracts.splice(index, 1);

            await ContractService.delete(contractId.id);
            commit('DELETE_CONTRACT', contractId.id);
        },

        async removeUser({ commit }, payload) {
            commit('setUsers', payload.users);

            const index = payload.users.findIndex((user) => user.id === payload.selectedItem.id);
            payload.users.splice(index, 1);

            await UserService.delete(payload.selectedItem.id);
        },

        async getContracts({ commit }, userId) {
            const { data } = await UserContractsService.index(userId);

            commit('setUserId', userId);
            commit('setContract', data);

            return data;
        }
    }
});

解决

It is because you are mutating vuex state outise a mutation in your store either move the mutating part in a mutation or change

export default new Vuex.Store({ strict: true, to

export default new Vuex.Store({ strict: false,

https://vuex.vuejs.org/guide/strict.html#strict-mode

喜欢 (0)

您必须 登录 才能发表评论!