Vuex fails to respond appropriately to intricate data structures

I've recently implemented Vuex to replace the EventBus in my application as the data complexity increased.

Within my context, I have a question entity with multiple answers. When a user adds a new answer, I want to display the latest one. However, despite updating the state.answers through mutation after receiving a successful response from the server, the computed property fails to react and display the new answer:

Here is an overview of my data structure:

"answers": {
  "118": {
    "id": 118,
    "description": "objective",
    "created_at": "2019-11-12T19:12:36.015Z",
    "dojo_process_id": 1,
    "question_id": 1,
    "user_id": 10
  }
  "127": {
    "id": 127,
    "description": "asdddd",
    "created_at": "2019-11-12T19:38:19.233Z",
    "dojo_process_id": 1,
    "question_id": 1,
    "user_id": 10
  },
  "128": {
    "id": 128,
    "description": "asddddasddd",
    "created_at": "2019-11-12T20:00:17.572Z",
    "dojo_process_id": 1,
    "question_id": 1,
    "user_id": 10
  }
},

This is the code snippet for my store:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);     

export const store = new Vuex.Store({
  state: {
    ...
    answers: {},
    ...
  },

  getters: {

    findBy: state=> filter => {
      let result= Object.values(state[filter.model]).
      filter(data => data[filter.field] === filter.criteria);
      return result;
    }
  },
  mutations: {

    setAnswers(state, answers) {
      state.answers = answers;
    },
    setAnswer(state, answer) {
      state.answers[answer.id] = answer;
    },

  },
  actions: {
    replaceCompleteProcess(context, data) {
      ...
      context.commit('setAnswers',data.answers);
      ...

    },
    cleanCompleteProcess(context) {
      ...
      context.commit('setAnswers',{});      
      ...
    },
    saveAnswer(context, answer) {
      context.commit('setAnswer', answer);
    }
  }
});

And here's how the script in my component is structured:

export default {
name: "show-question",
computed: {
  question: function () {
    return this.$store.getters.question(this.questionId)
  },
  answers: function () {
    return this.$store.getters.findBy({
      model: 'answers',
      field: 'question_id',
      criteria: this.questionId,
      sort: true
    });
  },
  answer: function () {
    if (this.answers && this.answers.length > 0) {
      return this.answers[0].description;
    } else {
      return '';
    }
  }
},
props: {
  questionId: {
    type: [Number],
    default: 0
  }
},
data() {
  return {
    sending: false,
    answerData: this.answer
  }
},
methods: {
  sendAnswer () {
    this.sending = true;
    questionConnector.answerQuestion(this,this.question.id,this.dojoProcessId, this.answerData)
  },

 // This method is called by AXIOS
  answerWasOK(answer) {
    this.sending = false;
    this.$store.dispatch('saveAnswer', answer);
    this.answerData = '';
  }
}

}

Despite understanding how Vuex should work, when I trigger this.$store.dispatch('saveAnswer', answer), the state updates but the computed property 'answers' does not reflect these changes in the component. It seems to be unresponsive.

I've extensively researched Vuex and its compatibility issues with complex data structures. I attempted to normalize my data, but encountered the same issue. Additionally, using vuex-orm presented challenges with one-many relationships that I struggled to resolve.

EDIT: Solution

After testing some suggestions provided in the responses, I found a solution that works:

setAnswer(state, answer) {
    let newAnswers = state.answers;
    state.answers = {};
    newAnswers[answer.id] = answer;
    state.answers = newAnswers;
}

Answer №1

When dealing with Objects, it is important to follow this pattern:

updateObject(state, newObj) {
    Vue.set(state.objects, newObj.id, newObj);
},

This instruction can be found in the official documentation.

If you need to add new properties to an Object, you have two options:
  • Use Vue.set(obj, 'newProp', 123), or
  • Replace the entire Object with a new one. For instance, you can leverage the object spread syntax like so:
    state.obj = { ...state.obj, newProp: 123 }

Answer №2

Within your code, you have a collection of answers stored in an object. This approach is perfectly fine if you are comfortable working with it. However, it's important to note that Vue.js observers do not automatically monitor new object attributes. In this case, by adding new attributes to the object instead of modifying an existing list/array, Vue.js may not detect these changes.

One recommendation could be to convert this object into an array for easier reactivity handling. If this conversion is not feasible due to constraints such as ORM requirements or project standards, exploring Vue.js' Reactivity features would be beneficial. A quick solution might involve utilizing a watcher:

https://v2.vuejs.org/v2/api/#watch


For further insights on Vue.js reactivity, consider checking out these resources:

An In-Depth Look at Reactivity

https://v2.vuejs.org/v2/guide/reactivity.html

How to Monitor Changes in Object Properties?

https://forum.vuejs.org/t/how-to-actively-track-an-object-property-change/34402/1

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

Exploring touch interactions using D3.js and TUIO

I'm currently facing a challenge with implementing multi-touch functionality and the d3.slider in my D3 Map. You can see the current state of my project in this video. With the d3 slider, I can spawn points and navigate around the map using touch even ...

The perplexity regarding asynchronous functions and return statements

I'm attempting to send a request to a Web API and then return true from a function if the input is valid, or false if it's not. I need the request to be asynchronous so that the function doesn't return before the request is verified. While t ...

The Shell Application is not refreshing React HtmlElement Micro Front end

I am currently facing an issue when trying to inject the following React MFE into another Angular shell application. The MFE loads successfully the first time, but if it is hidden or removed from the DOM and then reloaded, it fails to load. Could you plea ...

How can I add an image to a canvas using a button?

Having trouble with my studies and looking to create a custom shirt website. Posted below is the beginner code I have: If anyone knows how to upload an image onto a shirt canvas using a button, as well as change the shirt color with another button, please ...

Is your Drag and Drop feature in HTML5 acting up?

I am currently exploring the drag and drop functionality in HTML5. I have successfully managed to make an element draggable and ensure that the designated target accepts the dragged element. However, I am facing issues with getting the ondrag, ondragenter ...

Switching Vue.js from the standalone build to the runtime-only build midway through a project?

Opted for the runtime-only version of Vue.js for a new project. I came across in the documentation that to switch to the standalone version, one must include an alias in webpack like this: resolve: { alias: { 'vue$': 'vue/dist/vue.js& ...

Within Angular2 NGmodule, I aim to dynamically load two distinct sets of route modules depending on certain conditions

In Angular2, I am looking to load two different sets of route modules - one for jobseekers and the other for employers. Both sets will have the same URLs but will contain different modules for jobseekers and employers. Therefore, I need a way to dynamicall ...

The variable remains unchanged after the API call, despite using useState

Despite my efforts to find a solution, I still find myself puzzled by this question that has seemingly been answered before. The issue lies in the synchronization of my code when making a request to the what3words API. The data retrieved is assigned to a ...

What is the process for setting up a vertical carousel in Bootstrap 5 with a stationary previous image?

Looking for assistance with my vertical carousel project. Is there a way to create a vertical carousel in bootstrap 5 with the previous image fixed? I found a slider on this website: zara.com/jp/en/ I want to maintain the previous image in a fixed posit ...

Strange occurrences of radio buttons in AngularJS

When working with radio buttons, I noticed a strange behavior that I wanted to share. My goal was to have Radio Button 1 selected if the array is undefined, and Radio Button 2 selected when the array is defined. In the initial state, the array is indeed ...

Tips on displaying data in pie chart legend using react-chartjs-2

I am currently using a pie chart from react-Chartjs-2 for my dashboard. The requirement is to display both the label and data in the legend. I have implemented the following component in my application: import React, { Component } from "react"; ...

Get the username from Parse instead of using the ObjectID

When using angular and Parse for JavaScript, I have implemented a search field where an admin can input the objectid of a user to display their details. However, I would like to modify this functionality so that the admin can enter the username instead of ...

Accessing elements from an array and performing addition on those that are numerical

I am trying to figure out how to extract the values from an array created by some code and then combine them into a single variable: var selector = 'input[name^="Textbook"]'; $(selector).on('click', function() { ...

Steps to open a URL link within a div without navigating away from the current page

I want to create an interactive icon that, when clicked, expands like a browser window. Inside this expanded div, I would like to display a URL that I provide. How can I accomplish loading a new URL within my original index.html without leaving the page or ...

There was an unexpected error: Unable to access the 'icon' property of null

Whenever I try to edit a tab using the form, an issue arises. If I open the dialog box by clicking the edit icon and then hit save without altering the icon field, I receive an error message stating Uncaught TypeError: Cannot read property 'icon' ...

Building multi-dimensional array checkboxes in AngularJS - a step-by-step guide

I am working with a multi-dimensional array and I need to display all the data using checkboxes. The array below contains dietary requirements, and I want to create checkboxes for each entry where the value is true. How can I use ng-repeat to iterate over ...

What could be the reason behind receiving a "Failed to load resource" error when attempting to mount a component in Vue.js?

I am facing two errors in my Vue components related to mounting the component. The console log is showing 404 errors as follows: 1) [Error] Failed to load resource: the server responded with a status of 404 (Not Found) localhot8000/movies/getComments 2) [ ...

The AXIOS method in Express.js is designed to return a Promise object that may contain an

I am currently learning ExpressJS and Axios I have created a folder named utils and placed the axios.js file const axios = require('axios'); loadDataPesan=async function(opts){ axios.get('localhost/getData', { params ...

Blocking of Node.js Promises

I am currently new to Node/JS and am working on developing a password recovery page for an existing IT portal. The page involves searching through AD (ldap) and a DB where users have registered. The goal is to present users with options to authenticate and ...

Displaying components according to ternary conditional operator

I'm currently working on a piece of code that I only want to render when the correct or incorrect answer is given. Initially, I want to display only the question and the possible answers. In React, when the answer is "false", the message "you are wron ...