0

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!

Jono20201
  • 3,215
  • 3
  • 20
  • 33
KunhoLee
  • 25
  • 4

2 Answers2

0

I am not sure ... is this what you want to achieve?

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) => {
      var val = !state.todolist[payload.index].done
      state.todolist[payload.index] = Object.assign(state.todolist[payload.index], {done: {value: val}})
    },
    ...
  }
})
0

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;
tony19
  • 125,647
  • 18
  • 229
  • 307
PatrickSteele
  • 14,489
  • 2
  • 51
  • 54
  • Thanks for your answer! It is because I don't want to see 'no-param-assign' alert by eslint :) I know the reason now. Have a nice coding! – KunhoLee Nov 15 '17 at 01:26