question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Better support for Vuex strict mode

See original GitHub issue

Hi,

I have a vue component, essentially like the below, allowing user to edit myCopy with v-model fields, then commit or reject the changes.

<template>
    <div v-if="myCopy">
        <input v-model="myCopy.title" type="text">
        <input v-model="myCopy.text" type="text">
        <button @click.prevent="commitCopy()">Save</button>
    </div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
  computed: {
    ...mapGetters("someService", {
      myCopy: "getCopy"
    })
  },
  methods: {
    commitCopy() {
      // Commit Copy stuff
    },
  }
};
</script>

This works great until i start to edit one of the input fields, and I get this error:

[vuex] Do not mutate vuex store state outside mutation handlers.

I can prevent the issue, by changing my store.js file like this solution:

https://github.com/nuxt/nuxt.js/issues/1917#issuecomment-338471402

I don’t feel like that is the right answer, and was just wondering if the getCopy getter should support a Two-way Computed Property like so:

https://vuex.vuejs.org/en/forms.html

Many thanks

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
FossPrimecommented, Aug 6, 2019

My issue was that some parent scope data was being changed outside the async block. The solution is to define anything you modify in the same block.

Bad when you have more than 1 page:

 fullFind: async function ({ commit, dispatch, getters, state }, args) {
      const sm = { p: { limit: 0, skip: 0, total: 1 } }
      const myArgs = args ? Object.assign({query: {}}, args) : {query: {}}
      myArgs.query = Object.assign({}, myArgs.query)
      
      while (sm.p.total > (sm.p.limit+sm.p.skip)) {
        myArgs.query.$skip = sm.p.skip + sm.p.limit // BAD
        sm.p = await dispatch('find', myArgs)
      }
     
      return getters.find(args)
    }

Good always:

fullFind: async function ({ commit, dispatch, getters, state }, args) {
      const sm = { p: { limit: 0, skip: 0, total: 1 } }
      
      while (sm.p.total > (sm.p.limit+sm.p.skip)) {
        const myArgs = args ? Object.assign({query: {}}, args) : {query: {}}
        myArgs.query = Object.assign({}, myArgs.query)
        myArgs.query.$skip = sm.p.skip + sm.p.limit
        sm.p = await dispatch('find', myArgs)
      }
     
      return getters.find(args)
    }

In this example sm.p doesn’t trigger the error because i’m not modifying it’s values, only a reference.

1reaction
marshallswaincommented, Mar 27, 2018

I’m really glad you opened this issue because it got me thinking more about strict mode. I thought that adhering to strict mode would definitely be a problem for the relational stuff that I’m working on. I just tested it out and it seems that, thankfully, all of my efforts will not be in vain!

So here’s a preview of what’s coming: Suppose you had an API that returns /todos data in the following format, where the todo record has an itemId and the item is populated as part of the response:

{
  id: 'todo-1',
  description: 'todo description',
  itemId: 'item-2',
  item: {
    id: 'item-2',
    test: true
  }
}

I’ve got it currently setup so that when this todo is inserted in the store, feathers-vuex will store the todo in the todos store, as you’d expect, but it will first automatically create the item in the items service store. When the todo instance is stored, it contains a reference to the item in the items store. I thought that due to the way strict mode is setup, it would have a fit with this, even if you used a mutation to make the changes. The good news is that it works without errors as long as you use a mutation!

Here’s a mostly-full example:

// Setting up the store
this.store = new Vuex.Store({
  strict: true,
  plugins: [
    service('todos', {
      instanceDefaults: {
        id: null,
        description: '',
        isComplete: false,
        itemId: '',
        item: 'Item' // This sets up the relationship
      }
    }),
    service('items', {
      instanceDefaults: {
        test: false
      },
      mutations: {
        // Here's our custom mutation for updating the `test` boolean
        toggleTestBoolean (state, item) {
          item.test = !item.test
        }
      }
    })
  ]
})

// Now, assume the below code is in a component
const { Todo, Item } = this.$FeathersVuex

// When you create instances that already have an `id`, they get added to the store, automatically
const todo = new Todo({
  id: 'todo-1',
  description: 'todo description',
  itemId: 'item-2',
  // Because we setup the relationship, this gets added to the `items` store, since it also has an `id`
  item: {
    id: 'item-2',
    test: true
  }
})

const storedTodo = store.state.todos.keyedById['todo-1']
const storedItem = store.state.items.keyedById['item-2']

// Calling the mutation to change a record's property works fine in strict mode
store.commit('items/toggleTestBoolean', storedItem)

// Changing the property directly will throw errors in strict mode
todo.item.test = false

assert.equal(todo.item.test, false, 'the nested todo.item.test should be false')
assert.equal(storedTodo.item.test, false, 'the stored todo.item.test should be false')
assert.equal(storedItem.test, false, 'the stored item.test should be false')

So, if everything works out, this will all work in strict mode. It works in the tests, but I have to still test it out in a production app.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Strict Mode | Vuex
In strict mode, whenever Vuex state is mutated outside of mutation handlers, an error will be thrown. This ensures that all state mutations ......
Read more >
VueX Strict Mode - Write better forms while keeping ... - YouTube
VueX Strict Mode - Write better forms while keeping all VueX State changes inside mutation ; https://www.vuescreencasts.com/course... ; 0:00 Start ...
Read more >
Enabling strict mode while developing - Vuex Quick ... - O'Reilly
When Vuex is in strict mode, it will throw an error if the single state tree is mutated outside mutation handlers. This is...
Read more >
VueX Strict Mode - Write better forms while keeping ... - Reddit
VueX Strict Mode - Write better forms while keeping all VueX State changes inside mutations (fixed) ... I posted a version of this...
Read more >
Form Handling in Vuex Strict Mode | Ji ZHANG's Blog
Vue's computed property supports getter and setter, we can use it as a bridge between Vuex store and component. One limitation is computed ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found