Avoid the situation where the prop overrides the existing data

I am facing a challenge with vue.js as a beginner. I have an array filled with objects that I send through props to my router-view.

Within one of my router-view components, I am using this array in multiple functions by referencing it with 'this.data' and storing it in a new variable within the functions to avoid overwriting the original prop data.

However, the functions end up overwriting the original prop data and modifying the data of the prop itself.

Here is a simplified example illustrating my question:

App.vue

<template>
  <div>
    <router-view :data='data'></router-view>
  </div>
</template>

<script>
export default {
  data: function() {
    return {
      data: [],
    };
  },

  created: function() {
    this.getData();
  },

  methods: {
    getData: function() {
      this.data = // array of objects
    },
  }

Route component:

<script>
export default {

  props: {
    data: Array,
  },

  data: function() {
    return {
      newData1 = [],
      newData2 = [],
    }
  }

  created: function() {
    this.useData1();
    this.useData2();
  },

  methods: {
    useData1: function() {
      let localData = this.data;
      // manipulate 'localData'
      this.newData1 = localData;
    }

    useData2: function() {
      let localData = this.data;
      // manipulate 'localData'
      this.newData2 = localData;
    }
  }
}
</script>

The 'localData' in useData2 gets altered due to changes in useData1, leading to unintentional modification of the data prop. How can I prevent this from happening?

Answer №1

The issue you're facing stems from copying this.data by reference instead of value.

To solve this problem, a common technique known as cloning can be used. Arrays can usually be cloned using either the spread syntax or Array.from().

Below is a practical example demonstrating how to clone data:

// Methods.
methods: {

  // Using Data 1.
  useData1: function() {
    this.newData1 = [...this.data]
  },

  // Using Data 2.
  useData2: function() {
    this.newData2 = Array.from(this.data)
  }

}

Answer №2

@Arman Charan is absolutely correct in his response. It's important to note that objects and arrays are not considered primitive types but rather references.

If you want to understand this concept better, check out this informative video here => JavaScript - Reference vs Primitive Values/ Types

For reference types, it's necessary to clone the data onto another variable before making modifications to ensure that changes don't affect the original data.

When dealing with nested arrays and objects at a high level, methods like spread syntax and Array.from may not be effective.

If you're using Lodash, you can safely clone arrays or objects using _.cloneDeep().

I personally enjoy functional programming and highly recommend incorporating Lodash into your projects.

One way to achieve this is:

let original_reference_type = [{ id:1 }, { id: 2 }]
let clone_original = _.cloneDeep(original_reference_type)

clone_original[0].id = "updated"
console.log(original_reference_type) //[{ id:1 }, { id: 2 }] => will not change
console.log(clone_original) // [{ id: "updated" }, { id: 2 }]

Tip: For simple arrays and objects, consider using:

Objects:

let clone_original_data = {...original_data}
or

let clone_original_data = Object.assign({}, original_data)

Arrays:

let clone_original_data = [...original_data]
or

let clonse_original_data = original_data.slice()

For more complex and deeply nested arrays or objects, rely on Lodash's _.cloneDeep()

Answer №3

This is my preferred, "declarative" method that I find to be the most straightforward:

To start off, you should begin by installing lodash using npm i lodash. Next, make sure to import only the specific function you need, rather than importing the entire library. Then, initialize your data with an array taken from the props.

<script>
  import cloneDeep from 'lodash/cloneDeep'

  export default {
    props: {
      data: Array
    },

    data () {
      return {
        // initialization to be done once and non-reactive
        newData1: cloneDeep(this.data),
        newData2: cloneDeep(this.data)
      }
    }
  }
</script>

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

Changing a JavaScript command into a text representation

Currently, I have an array stored in a variable as shown below: arr = [1, 2, 3] Is there a way to convert this array statement into a string like this? newArr = "arr = [1, 2, 3]" ...

JavaScript does not display checkbox values

I am currently testing whether checkbox values appear on the client side. When I execute the code, the alert is not showing anything. I would greatly appreciate any assistance, thank you. <div> <label name="finishing"class=" ...

Issues with Vuetify visibility class functionalityStringReflects Challenges with the Visibility

As per the documentation found here, I'm attempting to utilize a Vuetify visibility class to hide an element on smaller screens. Unfortunately, when using the following class, it has the opposite effect - removing the element on larger screens and di ...

What is the best way to post an image using nodejs and express?

Recently, I've been working on a CMS for a food automation system and one feature I want to incorporate is the ability to upload pictures of different foods: <form method="post" enctype="multipart/form-data" action="/upload"> <td>< ...

Utilizing Angular Filters to Assign Values to an Object within a Controller

I have a JSON example with multiple records, assuming that each name is unique. I am looking to filter out an object by name in the controller to avoid constant iteration through all the records using ng-repeat in my HTML. { "records": [ { "Name" : ...

Create a password variable while typing

Looking to avoid interference from browsers with autocomplete and password suggestions while maintaining the show/hide letters feature. The goal is to keep the password stored as a variable, regardless of whether the characters are shown or hidden. The is ...

Difficulty encountered when trying to map an array to JSX - Error: Unexpected token

I am struggling to properly map an employees array to a new array using ReactJS and JSX. It seems like there is an issue with my return method. Please keep in mind that I am a complete beginner when it comes to React and ES6. Can someone guide me on how t ...

What is the best way to acquire the href value from this source?

Looking to extract the dynamic value "3 Sent" from the html snippet provided. How can this be achieved? <ul class="nav nav-tabs some-tabs"> <li class="active"> <a href="#accepted" data-toggle="tab">1 Accepted</ ...

Retrieving information from the backend using JavaScript

Utilizing devexpress JS Charts requires data to be in the format: [{ category: 'Oceania', value: 35 },{ category: 'Europe', value: 728 }] To achieve this format, I convert a DataTable to JSON in my backend code after running queries b ...

Incorporating Angular module into the mean.io bundle

Need help with adding the angular-ui-grid module to a mean.io package: $ cd packages/custom/mypackage $ npm install angular-ui-grid --save To import the JS, add this line to packages/custom/mypackage/public/index.js: import 'angular-ui-grid'; ...

What is the best way to convert HTML into a React component?

This is the situation I am facing : 1) The application requests a CMS (Content Management System) for page contents. 2) The CMS responds with "<div>Hi,<SpecialButton color="red">My Button</SpecialButton></div>" 3) The applicat ...

Is separating Vue components into their own files necessary?

As I work on developing multiple Vue components, I have decided to organize them in a separate file for better structure. The content of this file would resemble the following: components.js import Slide from './components/slider/Slide.vue'; im ...

No matter how many times I modified the code in the ReactDOM.render() method within my index.js file, the end result remained unchanged

When I ran npx create-react-app my-app, and then proceeded to cd my-app and npm start, a browser opened on localhost:3000. While looking at the index.js file, I noticed that the ReactDOM.render() method included the following code: ReactDOM.render( <Rea ...

Just starting out with jQuery: seeking advice on a user-friendly slideshow plugin, any tips on troubleshooting?

I am currently trying to incorporate a basic jquery slideshow plugin, but I seem to be encountering some difficulties. The documentation mentions the need to install 'grunt' and 'node dependencies', which is confusing to me as I am new ...

Is it possible to access a sub property using a dot string in Vue 3?

Given a Vue 3 proxy object structure as shown below: <script> export default { name: "test", data() { return { users: [{ "id": 1, "name": "Leanne Graham", " ...

Only Chrome causing my JavaScript execution to freeze due to Ajax

When using Ajax, it is supposed to be asynchronous, but for some reason, it seems like it's either stopping or pausing my JavaScript execution and only resuming once the response is received. Here is an example of HTML value: <input value="foo" d ...

Are there any factors within a local network or desktop environment that may impact the execution of JScript?

Something strange is happening with the JavaScript on my project. It works perfectly fine, except when accessed from computers at a specific company. Even more puzzling is that the JavaScript only fails about half of the time when accessed from that compan ...

Immersive image display

Currently on my website, I have a table displaying 9 images with descriptions. I'm looking to enhance user experience by allowing them to click on an image and view it in a larger format like a gallery without disrupting the layout of the page. This ...

Clickable list element with a button on top

Within my web application, there is a list displaying options for the user. Each 'li' element within this list is clickable, allowing the user to navigate to their selected option. Additionally, every 'li' element contains two buttons - ...

Integrating a footer into the enhanced search tab slider

I'm struggling to create a sticky footer like the one on w3schools. Even though I used the same code in my material UI demo, it's not functioning properly. I tried debugging by changing the position from fixed to absolute, but it still isn&apos ...