Reactive Responsive Failure in vue3
Brief description of the situation
An empty array of reactive is initialized, and then the interface is called and the data returned by the interface is assigned to the reactive. At this time, it is found that the page data has not been updated. (Scenario: ele-table's dataList)
const dataList = reactive([]); const load = async () => { const res = await Interface functions(); //Suppose the data returned by the request interface // Method 1 failed, direct assignment lost responsiveness // dataList = res; // Method 2 This also fails // (res); };
reason
Directly assign a new array to dataList, resulting in the reactive declaration of reactive object proxying by dataList
Replaced by a new array, because when operating a proxy object, it needs to have a proxy object as a prerequisite, so it loses the responsiveness
In vue3, no matter it is an object or an array, the entire data cannot be assigned directly, which will cause the reactive definition to fail.
Just like the address of the object is replaced, it is not the original object
Solution
Method 1: Create a responsive object whose properties are arrays
let datalist = reactive({ list: [], }) let arr = [1,2,3] = arr
Method 2: Use the ref function (ref can create any data type, reactive can only create objects or arrays)
const datalist = ref([]) = [1, 2, 3]
Method 3: push of array
let datalist = reactive([]) let arr = [1, 2, 3] ((item) => { (item) })
or
let datalist = reactive([]) let arr = [1, 2, 3] (...arr)
Vue3 deconstructed responsive failure analysis
When using vue3, we found that deconstruction cannot be used to process responsive data, and today we will see why.
Deconstruct responsive data in vue3
<div>{{counter}}</div> <div>{{}}</div> const reactiveObj = reactive({ counter: 0, obj: { value: 1 } }); setInterval(() => { ++; ++; }, 1000); const { counter, obj } = reactiveObj; return { counter, obj };
You can see on the page that the value of counter will not change, but the value is constantly increasing.
We all know that vue3 uses the proxy feature of ES6 to implement responsiveness. Let’s first review proxy.
const obj = { value: 1 } const proxy = new Proxy(obj, { get: function(target, key) { return (...arguments); }, set: function(target, key, value) { return (...arguments) } }) ++; (); // 2
proxy itself intercepts the object. It intercepts the obj object through the return value of new Proxy. When the value in the object is operated, set or get will be triggered.
However, for the original values (string, number, etc.), you need to wrap them outside and become an object, otherwise you cannot use new Proxy to intercept them.
Let's see how vue3 is handled.
In vue3, use ref to add responsiveness to the basic data type.
export function ref(value?: unknown) { return createRef(value, false) } function createRef(rawValue: unknown, shallow: boolean) { if (isRef(rawValue)) { return rawValue } // Use an object to wrap the basic data type data return new RefImpl(rawValue, shallow) } class RefImpl<T> { private _value: T private _rawValue: T public dep?: Dep = undefined public readonly __v_isRef = true constructor(value: T, public readonly __v_isShallow: boolean) { this._rawValue = __v_isShallow ? value : toRaw(value) this._value = __v_isShallow ? value : toReactive(value) } get value() { trackRefValue(this) return this._value } set value(newVal) { newVal = this.__v_isShallow ? newVal : toRaw(newVal) if (hasChanged(newVal, this._rawValue)) { this._rawValue = newVal this._value = this.__v_isShallow ? newVal : toReactive(newVal) triggerRefValue(this, newVal) } } }
From the above code, we can find that vue3 wraps the original value into an object and accesses the original value through the get value and set value methods, so that the .value must be carried when accessing the value.
For objects, reactive is still called internally if you use ref.
export const toReactive = <T extends unknown>(value: T): T => isObject(value) ? reactive(value) : value export function reactive(target: object) { if (isReadonly(target)) { return target } return createReactiveObject( target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap ) }
However, you still need to access the internal responsive data through .value.
let reactiveObj = ref({ counter: 0, obj: { a: 1 } }); ();
Why does deconstruction destroy responsiveness?
Deconstruct the assignment, distinguishing the assignment of the basic data type and the reference type. The assignment of the original type is equivalent to passing by value, and the value of the reference type is equivalent to passing by reference.
const obj = { value: 1, obj1: { value: 1 } } const val = ; const obj1 = obj.obj1;
Although the val above is a value, when accessing val, the get method of the obj object has been bypassed, which is the loss of responsiveness discussed in this article.
The deconstructed value of obj1 is passed by reference, and the internal pointer still points to obj.obj1, so accessing the content will not lose its responsiveness.
Summarize
The above is personal experience. I hope you can give you a reference and I hope you can support me more.