Search code examples
javascriptvue.jsvuejs2vuexdefineproperty

Vue/Vuex > Cannot track state changed when I use Object.defineProperty() method


I use Vue.js and Vuex.

I make a simple todolist app.

I make a done toggle button with Vuex using Object.defineProperty() method.

When I click done toggle button, Vue and Vuex cannot trace change immediately.

It only trace change when I just reassign property's value.

For example

This works:

Vuex.Store({
    state: {
        todolist: [
            { todo: 'test1', done: false },
            { todo: 'test2', done: true },
            { todo: 'test3', done: false },
            { todo: 'test4', done: false }
        ]
    },
    mutations: {
        ...
        [Constant.DONE_TOGGLE]: (state, payload) => {
            const changeState = state;
            changeState.todolist[payload.index].done = !state.todolist[payload.index].done;
        },
        ...
    }
});

But this does NOT work!

Vuex.Store({
    state: {
        todolist: [
            { todo: 'test1', done: false },
            { todo: 'test2', done: true },
            { todo: 'test3', done: false },
            { todo: 'test4', done: false }
        ]
    },
    mutations: {
        ...
        [Constant.DONE_TOGGLE]: (state, payload) => {
            Object.defineProperty(state.todolist[payload.index], 'done', { value: !state.todolist[payload.index].done });
        },
        ...
    }
});

below code trace changes of done toggle only OTHER mutations change state.

Why it does?

Here is my github repository link.

My app is in /EX11/todolistapp.

My Vuex file is in /EX11/todolistapp/src/store/index.js

Thanks for reading my question. Sorry for not good at English. Have a nice day!


Solution

  • This is due to a Javascript limitation -- Vue cannot detect changes to an element of an array when done via an index.

    But why not just grab the todo item and change it's done property directly?

    var item = state.todolist[payload.index];
    item.done = !item.done;