8

In my Vue.js app, I have an array value that should only be updated when a user completes a specific "refresh" action. However, as soon as I assign a new value to that array value, the array value becomes reactive and changes instantly as the data in the assigned value changes. The array value should remain un-reactive.

For example, I have a method, refresh(), which when triggered is meant to update displayedData, which should not be reactive, with currentData, which should be reactive. displayedData should only update when refresh is called.

methods: {
    refresh: function() {
        this.displayedData = this.currentData;
    }
}

4 Answers 4

17

To make a value not reactive without making it static, you can make a "deep copy" of it using stucturedClone(), which is universally supported as of early 2022:

this.displayedData = structuredClone(this.currentData);

A widely used method prior to the availability of structuredClone() was using JSON to encode and then decode it:

this.displayedData = JSON.parse(JSON.stringify(this.currentData));

Both of these methods assign the current state of one value to another value, and no changes to the first value will change the second value until this code is triggered again. However, structeredClone() is the superior method for several reasons.

The reason this is necessary isn't because of Vue.js specifically, but because of JavaScript in general. In JavaScript, arrays and objects are "passed by reference" rather than "passed by value".

Sign up to request clarification or add additional context in comments.

2 Comments

Now this is beautiiful. For around a single time execution use case this is the best choice. Though perfomance should be evaluated for numerous iterations loops use cases.
This will work on any data, even if it's not an object FYI
3

You can use destructuring assigment: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment?retiredLocale=it

this.displayedData = {...this.currentData}

You will have a new object made with the "copied" data from the first

Comments

2

An approach (WITHOUT disabling reactivity) is to use a different array for your temporary data and move stuff over in to the good array when the user presses refresh.

You could copy the values in the first array into the temp array like this.temp = this.permanent.slice() in the created or mounted life-cycle function.

Slice would make a shallow copy of the array. If you need to also clone the items in the array, then maybe use some deep copy library or the JSON.parse(JSON.stringify(...)) method.

1 Comment

I needed to do this for an object, not an array, so I used Object.assign() to shallow-clone my object.
2

If you DON'T add the currentData to the data() method then it will not be reactive.

export default {
    currentData: [],
    data() {
        return {

        }
    },
    methods: {
        refresh: function() {
            this.displayedData = this.currentData;
        }
    }
}

You can then still reference currentData in the section using {{ $options.currentData }}

5 Comments

That's expected, the value outside of data is totally ouf of the reactive vue component
I see what you mean now. The provided example does make a value non-reactive, but it also makes it static.
thanks, that solves all the problems with foreighn variables that should be stored 'as is' without proxying - for example, those that are compared with null in some external code (e.g. Yandex.Maps components)
This old, but still viewed/replied to so: @Cole: I don't agree that it makes it static, its non-reactive. Thus anything that relies on it, won't be updated. The value of currentData would still change, but the associated Vue things that use it (Like the html bindings) wont be updated. If you did a forced refresh or re-render of the data, then it might show the new value. Also, its outside of Vue world, so it acts strange. See jsfiddle.net/sLbyh1q8 Click refresh multiple times and look at Console output. Note my use of $options and not, and how they differ in updates.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.