This is the third day of my participation in Gwen Challenge. For more details, see: “Gwen Challenge” 😛
Are you surprised to see the headline? Is there a design flaw in Reactivity? In fact, drunk weng’s meaning is not wine! Reactivity can be said to be the most complex place in VUE3, of course, is also the most powerful point, it sounds like a piece of hard bones ha 🍖, which reminds me of the liangjian Li Yunlong in the face of small Japanese provocation said: even if the God of hell comes, I have to hug him a few beard down. So let’s hug Reactivity’s beard today.
In VUe3, it exposes all the data-responsive apis. In VUe2, it does not do this. How does vue2 do this? This process is called injection, and it will be injected into the component instance as follows:
{
// The data in data is reactive and is injected into the component instance
data(){
return{
name:"Forensic".idol:"Steve Jobs".publicNumber:"Front-end hunter."}}}Copy the code
In VUe3, however, it is no longer data, but the setup function, which we call the Composition Api. To use reactive data in the setup function, we inevitably need to expose the reactive Api for us to use. Next, Let’s take a look at some of the functions vue3 provides related to data responsiveness.
🍇 Get responsive data
Apis for getting reactive data:
-
reactive
The API passes in an object and returns an object proxy, which can be used to depth all the members of the proxy object, meaning that an object nested within the object is responsive data
For example 🌰 :
import { reactive } from 'vue' const state = reactive({name:"Forensic".age:18}) window.state = state; Copy the code
Effect display:
The object is now responsive, and vUE can be notified of operations on the object
-
readonly
This API requires passing in an object or a proxy. It also returns an object proxy, which can only read members of the proxy object, but cannot modify them. It can only get members of the proxy object, but cannot set members.
For example 🌰 :
import { reactive,readonly } from 'vue' const imState = readonly({name:"Forensic".age:18}) window.imState = imState; Copy the code
Effect display:
See, an error is reported indicating that the target to be modified is read-only, the modification failed
Readonly can transmit an object or a proxy
import { reactive,readonly } from 'vue' const state = reactive({name:"Forensic".age:18}) const imState = readonly(state);// Pass a proxy window.imState = imState; Copy the code
Effect display:
It is also not possible to assign to a proxy. After readonly is passed, the proxy can only be read and cannot be assigned. However, we can modify the value before readOnly and then proxy it.
📢 Note: Reactive and readonly apis are used to proxy objects and cannot be used to proxy ordinary values
For example 🌰 :
import { reactive,readonly } from 'vue' const state = reactive("Forensic") Copy the code
Effect display:
As a warning, raw values cannot be propped up, so what if you need to propped up normal values? That’s where the refAPI comes in
-
ref
A ref can pass in any data and will eventually put the data into an object value, such as {value:… }, access to value is reactive, and if the value given to value is an object, it is broached by reactive
For example 🌰 :
import { reactive,readonly,ref } from 'vue' const state = ref({name:"Forensic".age:18}) window.state = state; Copy the code
Effect display:
Alternatively, if the value passed in is already a proxy, the proxy will be used directly
For example 🌰 :
import { reactive,readonly,ref } from 'vue' const state = reactive({name:"Forensic".age:18}); const imState = ref(state) window.imState = imState; Copy the code
Effect display:
-
computed
For computed, you need to pass in a function that returns the same value as ref, {value:… }, when reading the value, it will decide whether to run the function according to the situation, which is whether the function is used or not, and it is cached. When the dependent reactive data does not change, it will get the value in the cache. Only when state.name or state.age changes, it will run again.
For example 🌰 :
import { reactive,readonly,ref ,computed} from 'vue' const state = reactive({name:"Forensic".age:18}) const result = computed(() = >{ console.log("computed"); return state.name + state.age }) console.log(result.value); Copy the code
Effect display:
Anyway, these four apis, no matter how they’re handled, have one purpose, which is to turn data into responsive data.
So which one do you use in development?
- If you want an object to become responsive data, you can use
reactive
orref
- If all properties of an object are readable only, use
readonly
- If you want to make non-object data responsive, use
ref
- If you want to get a new reactive data from a known reactive data, use
computed
📢 note: if you use ref, you must obtain the data from ref. Value, otherwise you cannot obtain it, remember! 😁
- If you want an object to become responsive data, you can use
🍉 Listen for data changes
- watchEffect
const stop = watchEffect(() = > {
// The watchEffect function executes immediately, listens for the reactive data used in the function, and executes again when the reactive data changes
})
// The listener is stopped by calling stop
stop();// Stop listening
Copy the code
For example 🌰 :
import { reactive, ref, watchEffect } from "vue";
const state = reactive({a: 1.b: 2});const count = ref(0);
watchEffect(() = >{
console.log(state.a,count.value);// It will be executed immediately
})
state.a++;// This is done again depending on data changes
Copy the code
Effect display:
The watchEffect function knows that the dependency has changed because the data inside it is reactive, and when the data is read it uses the GET method, which collects the dependency. Note also that if the dependent data changes many times at the same time, the final result will be displayed once, because the execution process is asynchronous, it will be executed in the microqueue, and it will run after the data changes, as shown in the following example:
For example 🌰 :
import { reactive, ref, watchEffect } from "vue";
const state = reactive({a: 1.b: 2});const count = ref(0);
watchEffect(() = >{
console.log(state.a,count.value);
})
// Run multiple times
state.a++;
state.a++;
state.a++;
state.a++;
state.a++;
state.a++;
state.a++;
state.a++;
Copy the code
Effect display:
As you can see from the end result, it only runs twice, once immediately, and the second time after the data changes
- watch
This watch is equivalent to vue2’s $watch. This watch is a bit troublesome because it needs to manually specify which values to monitor. When it changes, it will give you both the new value and the old value
For example 🌰 :
import { reactive, ref, watch } from "vue";
const state = reactive({a: 1.b: 2});const count = ref(0);
watch(() = >state.a,(newValue,oldValue) = >{
console.log("New value",newValue,"Old value",oldValue);
})
state.a++;// Modify dependencies
Copy the code
Effect display:
📢 Note: The difference between watch and watchEffect is that it does not run the function immediately, but only when the dependent value changes. Two parameters are passed in watch. In the example above, ()=>state.a. If you pass state.a directly, you pass a 1, so that the data is not responsive, as follows:
For example 🌰 : directly pass state
import { reactive, ref, watch } from "vue";
const state = reactive({a: 1.b: 2});const count = ref(0);
watch(state.a,(newValue,oldValue) = >{
console.log("New value",newValue,"Old value",oldValue);
})
state.a++;// Modify dependencies
Copy the code
Effect display:
Invalid monitor source: 1 The monitor source must be a getter/effect function, a ref, a passive object, or an array of these types.
When passing a ()=>state.a function, which runs inside watch, collects dependencies. When using refAPI, the first argument in watch can be written as count, since count is an object, as follows:
For example 🌰 : pass count directly
import { reactive, ref, watch } from "vue";
const state = reactive({a: 1.b: 2});const count = ref(0);
watch(count,(newValue,oldValue) = >{
console.log("New value",newValue,"Old value",oldValue);
})
count.value++;// Modify dependencies
Copy the code
Effect display:
Value = count. Value = count. Value = count.
For example 🌰 : pass count directly
import { reactive, ref, watch } from "vue";
const state = reactive({a: 1.b: 2});const count = ref(0);
watch(count.value,(newValue,oldValue) = >{
console.log("New value",newValue,"Old value",oldValue);
})
count.value++;// Modify dependencies
Copy the code
Effect display:
From the running results, there is also a warning, so this should be paid attention to 😚
By the way, watch can monitor multiple data, as follows:
For example 🌰 : pass count and ()=>state.a
import { reactive, ref, watch } from "vue";
const state = reactive({a: 1.b: 2});const count = ref(0);
watch([() = >state.a,count],([newValue1,newValue2],[oldValue1,oldValue2]) = >{
console.log("New value",newValue1,newValue2,"Old value",oldValue1,oldValue2);
})
count.value++;
state.a++;
Copy the code
Effect display:
📢 Note: Whether it is watch or watchEffect, callbacks are executed asynchronously when a dependency changes and, of course, are queued for execution.
In general, watchEffect is the most convenient because it automatically tracks dependency changes without manual specification, but sometimes you have to use Watch, for example: We don’t want the callback to be executed at first, we want it to be executed when the data changes, so watch is the only way to do that, and then when the data changes, we need to know what the old value is? This is also where you need to use Watch, and finally, you need to monitor some data that is not available in the callback function, for example, by printing console.log(” I’m changing “), which is not possible with watchEffect
🍋 judgment
There are four apis for fetching responsive data, reactive, ReadOnly, REF, computed, and two forms of return, one is object proxy and the other is {value:… } in this form, sometimes we may be awake and confused, so vue3 provides four apis to distinguish which way to get responsive data:
-
IsProxy: used to check whether data is obtained by Reactive or Readonly
-
IsReative: To determine whether a certain data is created by reative, you can see this link: v3.vuejs.org/api/basic-r…
-
IsReadonly: Checks whether a data is created by readonly
-
IsRef: Checks whether data is a REF object
🍆 conversion
Sometimes we get a data, we don’t know what it is, maybe sometimes we don’t know whether it is ref or proxy, we don’t know what it is!
In this case we can use unref
- unref
Unref = isRef(val)? Val. value: val, if it is ref then take the value of val.value, if it is not val
For example 🌰 :
function useNewTodo(todos){
todos = unref(todos);
/ /... Other code
}
Copy the code
- toRef
ToRef converts an attribute in a reactive object into data in the ref format
For example 🌰 :
import { reactive, toRef } from "vue";
const state = reactive({ name: "Forensic".age: 18 });
const nameRef = toRef(state,"name");
console.log(nameRef);// Finally {value:... } form
nameRef.value = "Front-end hunter.";// When the value is changed, the data in state will be affected
console.log(state.name);
Copy the code
Effect display:
- toRefs
All attributes of a reactive object are converted to the REF format and returned wrapped in a plain-Object
For example 🌰 :
import { reactive, toRefs } from "vue";
const state = reactive({ name: "Forensic".age: 18 });
const stateAsRefs = toRefs(state);
console.log(stateAsRefs);
/* stateAsRefs It is not a proxy object, but a normal object in the following format :{name:{value:ObjectRefImpl}, age:{value:ObjectRefImpl}} */
Copy the code
Effect display:
Why would you do that?
For example 🌰 : we need to mix two responsive data together. If we use the expansion operator directly, we are screwed. The data will lose its responsiveness
setup() {
const state1 = reactive({a:1.b:2});
const state2 = reactive({c:3.d:4});
return {
...state1,// Unresponsive, equivalent to writing a:1,b:2 here. state2,C :3,d:4
};
},
Copy the code
So how to solve it? Just put a toRefs on the outside
setup() {
const state1 = reactive({a:1.b:2});
const state2 = reactive({c:3.d:4});
return {
...toRefs(state1),// Be responsive. toRefs(state2),// Be responsive
};
},
Copy the code
😊 well, above is my share, I hope you can help, welcome to discuss duck in the comments section ~
I hope you can like 👍 to support oh ~ 😘, I will be more motivated 🤞, good night!