Vue's computed property failing to compute

I have developed an ecommerce application using Vue.js, and here is a snippet of the store configuration:

state: {
    cart: [],
    totalItems: {
      count: 0
    }
},
getters: {
    totalItems(){
      if(window.localStorage.totalItems){
        return JSON.parse(window.localStorage.totalItems)
      }
      else{
        let totalItems = { count: 0}
        return totalItems
      }
    }
},
mutations: {
    setCart(state, cart){
      state.cart = cart
      window.localStorage.cart = JSON.stringify(cart)
    },
    setTotalItems(state, totalItems){
      state.totalItems = totalItems
      window.localStorage.totalItems = JSON.stringify(totalItems)
    }
},
actions: {
    addToCart({ commit, getters }, productId){
      let cart = getters.cart
      let totalItems = getters.totalItems
      if(cart.length == 0){
        cart.push({id: productId, quantity: 1})
        totalItems.count++
      }
      else if(cart.find(({ id }) => id == productId)){
        let item = cart.find(({ id }) => id == productId)
        item.quantity++
        totalItems.count++
      }
      else{
        cart.push({id: productId, quantity: 1})
        totalItems.count++
       }
       commit('setCart', cart)
       commit('setTotalItems', totalItems)
    },
    setTotalItems({ commit }, totalItems){
      commit('setTotalItems', totalItems)
    }
}

The App.vue file includes the following template:

<template>
  <v-app>
    <v-app-bar
      app
      color="red"
      dark
    >
      <v-btn text to="/">Vue Shop</v-btn>

      <v-spacer></v-spacer>

      <v-btn text to="/cart">
        <v-badge v-if="totalItems.count" :content="totalItems.count"><v-icon>mdi-cart</v-icon></v-badge>
      </v-btn>

    </v-app-bar>

    <v-main>
      <router-view></router-view>
    </v-main>
  </v-app>
</template>

<script>


export default {
  name: 'App',
  components: {
  },
  computed: {
    totalItems(){
      return this.$store.getters.totalItems
    }
  }
};
</script>

Upon loading the site, I notice that the computed property is being calculated properly. However, upon clicking the 'Add to' button on the Home.vue file mentioned below:

  1. It should call the addToCart method.
  2. This method dispatches the addToCart action from the store.
  3. Where I calculate the totalItems and update the value using the setTotalItems mutation.

The problem I'm encountering is that when I click the 'Add to' button, I see the totalItems value updating in localStorage but it does not reflect in the v-app-bar component immediately. It only updates if I navigate to a different page and then return to the main page.

Initially, I stored the value in the state instead of localStorage, and it reflected correctly without needing to navigate to another page.

Is there a way to achieve this while still utilizing localStorage instead of the store?

<template>
      <v-container>
        <v-row>
          <v-col v-for="product in products" :key="product.id">
            <v-card width="300" height="300">
              <v-img :src=product.imgUrl width="300" height="200"></v-img>
              <v-card-title>
                {{ product.name }}
              </v-card-title>
              <v-card-text>
                ${{ product.price }}
                <v-btn small class="ml-16 primary" @click="addToCart(product.id)">Add to <v-icon>mdi-cart</v-icon></v-btn>
              </v-card-text>
            </v-card>
          </v-col>
        </v-row>
      </v-container>
    </template>
    
    <script>
    
    
    export default {
      name: 'Home',
      components: {
      },
      computed: {
        products(){
          return this.$store.getters.products
        },
        cart(){
          return this.$store.getters.cart
        }
      },
      methods: {
        addToCart(id){
          this.$store.dispatch('addToCart', id)
        }
      }
    }
    </script>

Answer №1

Issue The reactivity of Local Storage means that your getter will not be reevaluated.


Resolution One way to address this is by modifying your getter so it only fetches the value from local storage if the state has not been initialized yet. After the initial call, subsequent calls should directly access the state. This change in mutators triggers a reevaluation of the getter and, consequently, your computed property:

getters: {
    totalItems(state){
      if(state.totalItems.count < 0){
        return JSON.parse(window.localStorage.totalItems || '{count: 0}')
      }

      return state.totalItems;
    }
},

You can set an initial count value of -1 to ensure the getter looks into local storage on the first evaluation.

By using the totalItems property within the getter, Vue automatically knows to reevaluate the getter whenever this property changes.

The drawback here is that the getter and the state may not be synchronized until the count is changed for the first time.


Another approach could involve initializing the state with a localStorage call and removing it from the getter logic.

state: {
   totalItems: {
      count: JSON.parse(window.localStorage.totalItems || '{count: 0}')
   }
},
getters: {
    totalItems(state){
      return state.totalItems;
    }
},

Advantage: Ensures that the state and getter remain in sync, but this setup makes the getter somewhat redundant.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing Nuxt 3 server as a passthrough API along with FormData for concealing external endpoints

I'm currently grappling with understanding the Nuxt/server API and am struggling to figure out how to properly send a POST request with form-data (specifically files) to the Nuxt server in order to forward it to an external service: Within my pages.v ...

What is the best way to display these images correctly within a slider?

My goal is to display 4 images/company logos per slide, but they all end up clustered on one slide. Despite my efforts to adjust the CSS, nothing seems to work. This is what my code currently renders: https://i.sstatic.net/ThaOK.png Here are the react co ...

Troubleshooting a misformatted JSON string that lacks proper double quotes in Java Script

{ DataError: { user_id: [ [Object] ] } } I want to transform this string into JSON structure like below: { "DataError": { "user_id": [ [Object] ] } } Is there a potential method to achieve this outcome from incorrectly formatted JSON string? ...

What is the most efficient way to use the $slice operator on a highly nested array in mongoose

I am currently working on slicing a deeply nested array. To illustrate, consider the following structure. I aim to slice this array for pagination purposes. {messages: [{ message: { members: [ {example: object, blah: blah}, {example2: object2, blah2: blah ...

Sauce Labs encountering issues when running JavaScript code

Currently, I am using Selenium WebdriverJs along with Mocha to conduct tests on Sauce Labs via Travis CI. After isolating the issue without any project dependencies, I am seeking help. The interesting observation is that defining an additional object with ...

Bypassing 403 error in redux and react application

It appears that Redux or express is failing to handle an error scenario where a user updates their password using a reset password link token. https://i.sstatic.net/uo7ho.png https://i.sstatic.net/WGHdt.png An error message should be displayed as follow ...

Ajax received a response from http 409 and is now parsing it

Hey there! I've been working on parsing out the message object using Ajax, and I'm having a bit of trouble getting a reference to messages.msg. It's strange because it displays perfectly fine in Postman, but for some reason, I can't see ...

Is there a way to showcase an epub format book using only HTML5, CSS, and jQuery?

Can ePub format books be displayed in a web browser using only HTML5, CSS, and jQuery? I would appreciate any suggestions on how to accomplish this. Additionally, it needs to be responsive so that it can work on iPad. While I am aware of this requirement, ...

Error encountered while attempting to invoke endpoint function

Recently, I was handed a Node.js API documented with swagger for debugging purposes. My task also involves implementing some new features, however, I've encountered some difficulty when it comes to calling the functions that are executed upon hitting ...

Upon receiving the ajax request, the entire code page is called back

I'm having trouble saving data using a button in Laravel. When I use console.log, the entire code appears in the console and I don't understand why this is happening. Here is my input field and button: <form action="{{ url('sendcom& ...

Issue: It is necessary to utilize the `@babel/plugin-transform-runtime` plugin if you have set `babelHelpers` to "runtime" when using npm link

My situation involves having two interconnected React libraries: project-ui and propert-utils. project-ui relies on propert-utils, and the latter is installed within the former. "devDependencies": { "@company/project-utils": "gi ...

Node.js utilized for conducting anti-virus scans on server-bound files prior to uploading

Is there a way for me to scan files that are submitted as request payloads to check if they contain potential viruses? For example, if someone tries to upload a txt file with the EICAR virus signature, I want to be able to scan it and reject it if it is in ...

Coordinates of HTML elements corners after rotation

Seeking to obtain the XY coordinates of an HTML element in order to accurately calculate the physical distance, in pixels, from the corners of a rotated element relative to another element. In this code snippet, I am attempting to determine the distance f ...

Difficulty encountered when consolidating intricate data attributes into a single array

I have a task to tackle in the code snippet below. My goal is to collect all the data in the age attributes and store them in a single array, formatting it as shown here: output = [48, 14, 139, 49, 15, 135, 51, 15, 140, 49, 15, 135, 51, 15, 140, 52, 16, ...

challenges with managing memory during express file uploads

I'm experiencing memory problems with file uploads while hosting my site on NodeJitsu. When I try to upload files, my app crashes with this error message: { [Error: spawn ENOMEM] code: 'ENOMEM', errno: 'ENOMEM', syscall: 'spa ...

What steps can be taken when troubleshooting a select menu that was not chosen?

I am encountering an issue with a select menu in my code. The code snippet for the v-select component looks like this: <v-select dense outlined item-text="name" item-value="id" :items="frequencies" v-model=" ...

issues with firebase dependencies no longer functioning

My Vuejs app has been running smoothly with Firebase Authentication, but today I encountered an issue. Upon starting the app (npm run serve), I am now facing the following error: These dependencies were not found: * firebase/app in ./src/helpers/firebase. ...

What is the best approach to dealing with "Cannot <METHOD> <ROUTE>" errors in Express?

Here is a simple example to illustrate the issue: var express = require('express'); var bodyparser = require('body-parser'); var app = express(); app.use(bodyparser.json()); app.use(errorhandler); function errorhandler(err, req, res, ...

Navigating through the additional plugins in WebDriver

After installing a plugin in Chrome, the next step is to access it through webdriver. Here's how you can do it: File addonpath = new File("path of .crx file"); ChromeOptions chrome = new ChromeOptions(); chrome.addExtensions(addonpath); WebDriver dri ...

Tips for concealing Bootstrap 5 modal exclusively after successful completion

Utilizing the power of Bootstrap 5 I have successfully implemented a modal that shows up when #truck_modal is clicked, thanks to the following JavaScript code: (this snippet is located at the beginning of my js file) document.addEventListener('DOMCo ...