title: Nuxt / Vuex / Vue Reactivity Issue Increment
body: <p>Hi everyone I am I having some difficulty when working with Nuxt and Vuex.</p>
  
  <p>I am trying to run through the example Vuex / Nuxt Classic Mode. 
  <a href="https://nuxtjs.org/guide/vuex-store/" rel="nofollow noreferrer">https://nuxtjs.org/guide/vuex-store/</a></p>
  
  <p>After clicking my increment button I dont see the number go up. My page just stays at 0, I can see within the console that the state knows the number is no longer 0 but not on the screen, as if it doesnt know to be reactive.</p>
  
  <p>My assumption is that I have miss configured something somewhere and my 0 is not the actual state, but I created some copy of it somehow. </p>
  
  <p>Here is my button within my template.</p>
  
  <pre><code>&lt;button @click="inc"&gt;{{ counter }}&lt;/button&gt;
  </code></pre>
  
  <p>Here is my inc function within my methods.</p>
  
  <pre><code>inc () {
    this.$store.commit('increment')
  },
  </code></pre>
  
  <p>Here is my computed</p>
  
  <pre><code>computed: {
    counter () {
      return this.$store.getters.counter
    }
  }
  </code></pre>
  
  <p>Here is my Vuex/index.js file contained within the store folder.</p>
  
  <pre><code>import Vue from 'vue'
  import Vuex from 'vuex'
  Vue.use(Vuex)
  
  const createStore = () =&gt; {
    return new Vuex.Store({
      state: () =&gt; ({
        counter: 0
      }),
      getters: {
         counter: state =&gt; state.counter
      },
      mutations: {
        increment (state) {
          state.counter++
        }
      }
    })
  }
  
  export default createStore
  </code></pre>
  
  <p><img src="https://i.imgur.com/i0lSevI.jpg" alt="Commercial Photography"></p>
  
  <p><strong>Update:</strong> Included more code snippets, and replied to existing comments.</p>
  
  <p>@Boussadjra Brahim @xaviert, thank you both for weighing in, I appreciate the assistance.</p>
  
  <p>@Boussadjra Brahim - Yes, I had tried using an action that called the mutation, that didnt seem to get me there either. I also tried adjusting the state via the action alone, and wasnt able to make any changes, however that seems correct, as I am under the impression that actions call mutations to make state changes and do not themselves do so, please correct me if you know more. I am 100% open to the idea that I did not attempt it correctly. Below is that action that didnt do anything and the one that called the mutation</p>
  
  <pre><code>actions: {
    increment (state) {
      state.counter++
    }
  },   
  </code></pre>
  
  <p>And here is the version with the action calling the mutation.</p>
  
  <pre><code>actions: {
    incrementCounterUp () {
      this.commit('increment')
    }
  },
  </code></pre>
  
  <p>@xaviert - I have tried starting the server over, and have also tried to see if an nuxt build followed by a firebase serve, to see if maybe that helped. It did not. My normal server start is 'npm run dev'. In hopes that you/anyone else may be able to find my mistake below is my full _id.vue component and also my nuxt.config.js file as maybe that's it. Its still pretty raw and could use a lot of refactoring so hope you can sort through it well enough.</p>
  
  <p><strong>_.id.vue</strong></p>
  
  <pre><code>&lt;template&gt;
    &lt;div class="product"&gt;
      &lt;div class="product-image"&gt;
        &lt;div class="product-image-img"&gt;
          &lt;img v-bind:src="product.image_file" width="450px;"/&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="product-details-wrapper"&gt;
        &lt;div class="product-details"&gt;
          &lt;h1&gt;
            &lt;div v-if="this.$route.query.editPage"&gt;
              &lt;textarea @input="updateTextArea" ref="textarea2" v-model="product.item_name" type="text" /&gt;
            &lt;/div&gt;
            &lt;div v-else&gt;{{product.item_name}}&lt;/div&gt;
          &lt;/h1&gt;
          &lt;div class="product-description"&gt;
            &lt;div class="product-description-text" v-if="this.$route.query.editPage"&gt;
              &lt;textarea @input="updateTextArea" ref="textarea" v-model="product.description" type="text" /&gt;
            &lt;/div&gt;
            &lt;div class="product-description-text" v-else v-html="product.description"&gt;&lt;/div&gt;
          &lt;/div&gt;
          &lt;p class="product-brand"&gt;&lt;strong&gt;Brand - &lt;/strong&gt; {{product.brand_name}}&lt;/p&gt;
          &lt;hr /&gt;
          &lt;div class="product-price"&gt;
            &lt;div v-if="this.$route.query.editPage"&gt;
              &lt;strong&gt;Original Price - &lt;/strong&gt;
              &lt;input v-model="product.msrp" type="text" /&gt;
            &lt;/div&gt;
            &lt;div v-else class="product-msrp"&gt;
              &lt;strong&gt;Original Price - &lt;/strong&gt;
              &lt;span class="strike"&gt;${{product.msrp}}&lt;/span&gt;
            &lt;/div&gt;
            &lt;div v-if="this.$route.query.editPage"&gt;
              &lt;strong&gt;Sale Price - &lt;/strong&gt;
              &lt;input v-model="product.price" type="text" /&gt;
            &lt;/div&gt;
            &lt;div v-else class="product-sale-price"&gt;
              &lt;strong&gt;Sale Price - &lt;/strong&gt;
              &lt;span class=""&gt;${{product.price}}&lt;/span&gt;
            &lt;/div&gt;
            &lt;div class="product-price"&gt;
              Quantity x
              &lt;input @input="updateQuantity" v-model="quantity" min="1" class="" type="number" value="1" /&gt;
            &lt;/div&gt;
            &lt;button @click="inc"&gt;{{ counter }}&lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div v-if="this.$route.query.editPage" class="update-product"&gt;       &lt;button @click="updateProduct(product)"&gt;Update&lt;/button&gt;&lt;/div&gt;
      &lt;div class="footer"&gt;
        &lt;router-link to="/privacy-policy" target="_blank"&gt;Privacy&lt;/router-link&gt; |
        &lt;router-link to="/terms" target="_blank"&gt;Terms&lt;/router-link&gt;
      &lt;/div&gt;
  
    &lt;/div&gt;
  &lt;/template&gt;
  
  &lt;script&gt;
  // @ is an alias to /src
  
  import firebase from '@/services/fireinit'
  import foo from '@/components/foo'
  const db = firebase.firestore()
  export default {
    name: 'ProductPage',
    head () {
      return {
        title: this.product.item_name
      }
    },
    components: {
      foo
    },
    data: function () {
      return {
        product: {},
        image: '',
        name: 'Checkout',
        description: '',
        currency: 'USD',
        amount: '',
        msrp: '',
        quantity: 1
      }
    },
    methods: {
      inc () {
        this.$store.dispatch('incrementCounterUp', true)
      },
      updateProduct: function (product) {
        db.collection('products').doc(product.item_id).set(product)
          .then(function () {
            console.log('Document successfully written!')
          })
          .catch(function (error) {
            console.error('Error writing document: ', error)
          })
      },
      updateQuantity () {
        this.product.msrp = (this.quantity * this.product.orgMsrp)
        this.product.msrp = Math.round(100 * this.product.msrp) / 100
        this.product.price = this.quantity * this.product.orgPrice
        this.product.price = Math.round(100 * this.product.price) / 100
      },
      updateTextArea () {
        this.$refs.textarea.style.minHeight = this.$refs.textarea.scrollHeight + 'px'
        this.$refs.textarea2.style.minHeight = this.$refs.textarea2.scrollHeight + 'px'
      }
    },
    async asyncData({app, params, error}) {
      const ref = db.collection("products").doc(params.id)
      let snap
      let thisProduct = {}
      try {
        snap = await ref.get()
        thisProduct = snap.data()
        thisProduct.orgMsrp =  thisProduct.msrp
        thisProduct.orgPrice =  thisProduct.price
      } catch (e) {
        // TODO: error handling
        console.error(e)
      }
      return {
        product: thisProduct
      }
    },
    mounted () {
      if(this.$refs.textarea) {
        this.$refs.textarea.style.minHeight = this.$refs.textarea.scrollHeight + 'px'
        this.$refs.textarea2.style.minHeight = this.$refs.textarea2.scrollHeight + 'px'
      }
    },
    computed: {
      counter () {
        return this.$store.getters.counter
      }
    }
  }
  &lt;/script&gt;
  
  
  &lt;style lang="less"&gt;
  body {
    font-family: 'Avenir', Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    color: #2c3e50;
    margin: 0
  }
  p{
    margin-top: 1em;
    margin-bottom: 1em;
  }
  html, body, #__nuxt, #__layout, .default,  .product{
    height: 100%;
  }
  .product {
    justify-content: center;
    display: flex;
    max-width: 1150px;
    margin: 0 auto;
    flex-wrap: wrap;
    align-items: center;
    padding: 0 24px;
    &amp;-price{
      input {
        border: 1px solid;
        padding: 0 .3em;
        text-align: center;
        width: 50px;
      }
    }
  }
    .product-details{
      width: 100%;
      textarea {
        width: 100%;
        font-size: inherit;
        color: inherit;
        font-family: inherit;
        font-weight: inherit;
        height: initial;
        resize: none;
        background-color: transparent;
        border: none;
      }
      h1{
        font-size: 1.9rem;
        margin: 15px 0 20px;
      }
      hr{
        width: 50%;
        margin: .5rem 0px;
      }
      p{
  
      }
    }
    .product-description-text{
      margin: 10px 0;
    }
    .product-image, .product-details-wrapper{
      align-items: center;
      display: flex;
      justify-content: center;
    }
    .product-details-wrapper{
      flex: 0 1 535px;
    }
    .product-image{
      flex: 0 1 535px;
      img{
        width: 100%;
      }
    }
    .product-price{
      .strike{
        text-decoration: line-through;
      }
      button{
        display: flex;
        width: 150px;
        height: 50px;
        border-radius: 5px;
        justify-content: center;
        font-size: 24px;
        margin-top: 20px;
        &amp;:hover{
          cursor: pointer;
          background-color: #f1f1f1;
          box-shadow: 3px 3px 11px -1px rgba(0, 0, 0, 0.48);
        }
      }
    }
    .product-sale-price{
      color: #f30000;
    }
    .footer {
      flex: 1 1 100%;
      text-align: center;
      color: #ccc;
      margin-top: 25px;
      padding: 15px;
      a {
        color: #ccc;
        text-decoration: none;
        &amp;:hover{
          text-decoration: underline;
        }
      }
    }
    .update-product{
      position: absolute;
      top: 0;
      text-align: center;
    }
  
  &lt;/style&gt;
  </code></pre>
  
  <p><strong>nuxt.confgs.js</strong></p>
  
  <pre><code>const pkg = require('./package')
  const { STRIPE_TOKEN } = process.env;
  
  module.exports = {
    vue: {
      config: {
        productionTip: false,
        devtools: true
      }
    },
    buildDir: './functions/nuxt',
    mode: 'universal',
  
    /*
    ** Headers of the page
    */
    head: {
      title: pkg.name,
      meta: [
        { charset: 'utf-8' },
        { name: 'viewport', content: 'width=device-width, initial-scale=1' },
        { hid: 'description', name: 'description', content: pkg.description }
      ],
      link: [
        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
      ]
    },
  
    /*
    ** Customize the progress-bar color
    */
    loading: { color: '#fff' },
  
    /*
    ** Global CSS
    */
    css: [
    ],
  
    /*
    ** Plugins to load before mounting the App
    */
  
    /*
    ** Nuxt.js modules
    */
    modules: [
      // Doc: https://github.com/nuxt-community/axios-module#usage
      '@nuxtjs/axios',
      'nuxt-stripe-module'
    ],
    stripe: {
      version: 'v3',
      publishableKey: 'pk_test_XXX',
    },
    /*
    ** Axios module configuration
    */
    axios: {
      // See https://github.com/nuxt-community/axios-module#options
    },
  
    /*
    ** Build configuration
    */
    build: {
      /*
      ** You can extend webpack config here
      */
      publicPath: '/public/',
      vendor: [],
      extractCSS: true,
      bable: {
        presets: [
          'es2015',
          'stage-8'
        ],
        plugins: [
          ['transform-runtime', {
            'polyfill': true,
            'regenerator': true
          }]
        ]
      },
      extend (config, { isDev }) {
        if (isDev &amp;&amp; process.client) {
          config.module.rules.push({
            enforce: 'pre',
            test: /\.(js|vue)$/,
            loader: 'eslint-loader',
            exclude: /(node_modules)/
          })
        }
      },
      router: {
        middleware: 'router-auth'
      }
    },
    plugins: [
      { src: '~/plugins/fireauth', ssr: true }
    ]
  }
  </code></pre>
  
  <p><strong>store/index.js</strong></p>
  
  <pre><code>import Vue from 'vue'
  import Vuex from 'vuex'
  Vue.use(Vuex)
  
  const createStore = () =&gt; {
    return new Vuex.Store({
      state: () =&gt; ({
        counter: 0
      }),
      actions: {
        incrementCounterUp () {
          this.commit('increment')
        }
      },
      getters: {
        counter: state =&gt; state.counter
      },
      mutations: {
        increment (state) {
          state.counter++
        }
      }
    })
  }
  
  export default createStore
  </code></pre>