Using Vuex getter to copy a JSON object

Encountering an unusual issue with JSON in a Vuex getter: it appears to be causing a pass-by-reference problem. To provide some context - I'm currently working on a music application that consists of various "scenes", each containing collections of "tracks" (similar to Ableton Live).

Here is the getter code:

  newTrack: state => {
    let newTrack = JSON.parse(JSON.stringify(state.newTrackDefaults))
    return newTrack
  },

This is the object being referenced:

  newTrackDefaults: {
    tune: [],
    // other properties here
  },

And it's used in this action:

  setUpNewScene: context => {
    let newScene = JSON.parse(JSON.stringify(context.state.newSceneDefaults))
    let newTrack = context.getters.newTrack  
    console.log(newTrack) // revealing the issue lies with the getter 
    newScene.tracks.push(newTrack)
    context.commit('addNewScene', newScene)
 }

The problem arises when adding items to a track in the initial scene, then creating a new scene where the new scene automatically inherits the same track as the first scene. This discrepancy is visible not only in the rendering but also in the Vuex state (as per DevTool observations). Additionally, any updates made to tracks in the first scene are reflected in the tracks of the new scene, suggesting a pass-by-reference error.

After several console.log tests, it was discovered that the getter was returning the "filled" track. The issue was resolved by bypassing the getter and modifying the action as follows:

  setUpNewScene: context => {
    let newScene = JSON.parse(JSON.stringify(context.state.newSceneDefaults))
    let newTrack =  JSON.parse(JSON.stringify(context.state.newTrackDefaults))
    console.log(newTrack) // now functioning correctly
    newScene.tracks.push(newTrack)
    context.commit('addNewScene', newScene)
 }

Although a solution has been implemented, there remains confusion surrounding the original behavior. Could the getter somehow interfere with the JSON functions? What could potentially be causing this unexpected outcome?

Answer №1

Vuex getters are designed to be cached for optimized performance.

Learn more about Vuex getters here

Similar to computed properties, getters cache their results based on dependencies and only re-evaluate when those dependencies change.

If the dependencies remain unchanged, getters will keep returning the last value without updating. This can lead to unexpected behavior if the getter is not properly managed, causing repeated objects to be returned instead of unique ones.

To avoid this issue, creating a function to generate default values is recommended. By calling this function whenever needed, you can ensure consistency without worrying about caching problems.

function newTrackDefaults() {
    return {
        tune:[],
        // add other properties here
    }
}


setUpNewScene: context => {
    let newScene = JSON.parse(JSON.stringify(context.state.newSceneDefaults))
    let newTrack = newTrackDefaults() 
    newScene.tracks.push(newTrack)
    context.commit('addNewScene', newScene)
 }

It's worth noting that getters can also return functions, providing another way to address caching issues.

newTrack: state => () => {
    let newTrack = JSON.parse(JSON.stringify(state.newTrackDefaults))
    return newTrack
  },

Remember to call the getter as a function now that it returns one.

let newTrack = context.getters.newTrack()

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

Is it possible for node.js to execute promises without needing to await their fulfillment?

When I visit the Discord tag, I enjoy solving questions that come my way. While I am quite proficient in Python, my skills in Javascript are just about average. However, I do try my hand at it from time to time. The Discord.py library consists of several ...

ERROR: The value property is undefined and cannot be read in a ReactJS component

Can someone help me with the error I'm encountering in the handleChange function? I'm not sure what the issue could be. const [testState, setTestState] = useState({ activeStep:0, firstName: '', lastName: '&apos ...

The Jquery ajax call encountered an error due to a SyntaxError when trying to parse the JSON data, specifically finding an unexpected character at

I've developed a web application that utilizes just four scripts for dynamic functionality. Overview: Init.php = Database, index.php = webpage, api.php = fetches data from server/posts data to server, drive.js = retrieves information from api.php a ...

Managing incoming HTTP requests on LoopBack can be easily done by following these steps

I am currently working with loopback to create a login page. The client-side files contain the code for the login page $(document).ready(function(){ $('#login').click(function(){ var username = $('#usr').val(); var password = ...

Encountering difficulties in running bootstrap on nodejs

As a beginner in node.js and bootstrap, I am eager to create my own personal website, so I found some tutorials to help me get started. After downloading bootstrap 2.0.2 and unzipping it, I organized the files by placing bootstrap and bootstrap-responsive ...

Retrieve information from a PHP file using AJAX when the output is just a single line

I never thought I would find myself in this situation, but here I am, stuck. I just need a single result from this PHP file, so is using an array really necessary? Despite my efforts to console.log(result) multiple times, all I get back is "null". What c ...

The "results per page" ajax dropdown in Yii stops working after other ajax content is loaded on the page

One of the views in Yii framework is the "Patients" view, which contains several CGridViews and other elements that are loaded via ajax after the initial view has loaded. Some of these elements are nested within multiple levels of ajax-loaded divs. Within ...

Troubleshooting script error: Dealing with Ineffective Redirects

I am currently using a JavaScript code that allows users to jump to a directory by typing its name. Here is how it functions: If the input field is left empty, the user will be directed to a page called "error.html" which displays the message "This field ...

Enhancing TypeScript Types with a custom method within an Angular 2 context

I am working on an Angular 2 project using the CLI. Currently, I am trying to add a custom method to the String type as shown below. interface String { customMethod(): number; } String.prototype.customMethod = function() { return 0; } Despite my ...

How can I dictate the placement of a nested Material UI select within a popper in the DOM?

Having trouble placing a select menu in a Popper. The issue is that the nested select menu wants to mount the popup as a sibling on the body rather than a child of the popper, causing the clickaway event to fire unexpectedly. Here's the code snippet f ...

What methods can be used to broaden configuration variables within VSCode using an extension?

I attempted to develop an extension for vscode that requires reading the pasteImage.parth variable from the ./vscode/settings.json file { "pasteImage.path": "${workspaceRoot}/assets/images" } In my attempt to retrieve the variable us ...

Issues with HTML5 video playback in Apple machines using the Firefox browser

On a website I'm developing, I've included an HTML5 video that works perfectly except for one specific issue - it won't play on Firefox in Apple devices. Surprisingly, it functions well on all other browsers and even on Firefox in Windows an ...

What is the process to retrieve a function from a router javascript file using node.js?

Dealing with a web application that is not my own, I now have the task of sending out one hundred emails. Unfortunately, the code is poorly documented and written, which means I need to test it to figure out what I can and cannot do. However, I'm uns ...

Adjust the form action and text input name according to the selected radio input

Seeking assistance with the following code, can someone help? $(document).ready(function() { $('#searchform').submit(function() { var action = ''; if($('.action_url').val() == 'l_catalog') { ...

Dealing with images in Laravel Mix

Recently, I made the switch from Vue-CLI to laravel-mix and encountered an issue with my images in HTML not displaying. Previously, I was using the following syntax: <img src="@assets/images/logo.png" alt="Logo"> (Where @assets a ...

ReactJS Chatkit has not been initialized

I made some progress on a tutorial for creating an Instant Messenger application using React and Chatkit. The tutorial can be found in the link below: https://www.youtube.com/watch?v=6vcIW0CO07k However, I hit a roadblock around the 19-minute mark. In t ...

AngularJS - Showcase a dynamic list of information according to the value chosen

Seeking assistance from anyone willing. I have data in JSON format structured like this { state1: [ member1, member2], state2: [ member3,member4...], ... } There is a dropdown that displays the states listed in the JSON data. When a state is selected, I ...

Trouble with bootstrap 5 nested accordions: panels won't collapse as expected

I've structured my page content using nested bootstrap accordions within Bootstrap 5. The primary accordion is organized by continents, with each panel containing a secondary accordion for individual countries. While the main accordion functions cor ...

A pop-up window for selecting a file within an <a> tag

Is there a way to create an Open File dialog box on a link within my webpage? I attempted <input name="uploadedfile" type="file"> However, it only functions as a button and does not allow for the selection of multiple files. I would like somethin ...

Displaying an already existing HTMLElement within a vue3 template

Suppose I have a pre-existing htmlElement: const myElement = document.createElement('DIV');, and I am interested in rendering this instance within a vue3 template. When using the composition API, the code would resemble something like this: < ...