toRef: Create a new Ref variable and convert a field of the Reactive object into a Ref variable
toRefs: Create a new object, each of its fields is the Ref variable of each field of the Reactive object
Tell me about toRef
First define a reactive object
interface Member {<!-- --> id: number name: string } const userInfo: Member = reactive({<!-- --> id: 1, name: 'White' }) console.log('userInfo=', userInfo)
If you want to convert the name
field of the userInfo
object into a Ref variable, you can do the following: let nameR = toRef(userInfo, 'name')
At this time, this nameR
is a Ref variable,
Therefore, when reading and assigning values later, you must use nameR.value
to operate.
Therefore, when reassigning nameR
, the values of nameR
and userInfo.name
will be updated at the same time.
let nameR = toRef(userInfo, 'name') console.log('nameR is a Ref variable, value=', nameR.value) /** * @name editNameR * @description Modify the value of nameR */ const editNameR = () => {<!-- --> nameR.value = 'edit-White' // You can see that after reassigning `nameR`, the values of `nameR` and `userInfo.name` are updated at the same time console.log('edit - nameR=', nameR.value) console.log('edit - userInfo=', userInfo) }
toRef
can also receive an array. In this case, the second parameter is the subscript of the array.
let wordList = reactive(['a', 'b', 'c']) let a = toRef(wordList, 0) console.log('a=', a.value) // a console.log('wordList[0]=', wordList[0]) // a
Object – Set default value
If there is a property on the Reactive
object that does not have an initial value, you can pass the third parameter to set it (the default value is only valid for Ref variables)
interface MemberCopy {<!-- --> id: number name: string age?: number // The age attribute, because it is optional, the default value will be `undefined` } // When declaring variables, omit the `age` attribute const theInfo: MemberCopy = reactive({<!-- --> id: 1, name: 'Black' }) // At this time, in order to avoid program running errors, you can specify an initial value, but the initial value is only valid for the Ref variable and will not affect the value of the Reactive field. let age = toRef(theInfo, 'age', 18) console.log('age=', age.value) // age= 18 console.log('theInfo.age=', theInfo.age) // theInfo.age= undefined // Unless reassigned, both will be updated at the same time age.value = 25 console.log(age.value) // 25 console.log(theInfo.age) // 25
Array – Set default value
const words = reactive(['a', 'b', 'c']) // When the value corresponding to the subscript does not exist, return `undefined` const d = toRef(words, 3) console.log(d.value) // undefined console.log(words[3]) // undefined // After setting the default value, the default value will be used for the Ref variable. The Reactive array will not be affected at this time. const e = toRef(words, 4, 'e') console.log(e.value) // e console.log(words[4]) // undefined
There is also a special usage that is not recommended,
In the process of toRef
, if a key that does not exist on the original object is used, the .value of the defined Ref variable
will be undefined
code>
Give an example // As we all know, White does not have a girlfriend const girlfriend = toRef(userInfo, 'girl') console.log('girlfriend=', girlfriend.value) // girlfriend= undefined console.log('userInfo.girlfriend=', userInfo.girl) // userInfo.girl= undefined //At this time, there are only two Keys on the userInfo object console.log(Object.keys(userInfo)) // ['id', 'name'] /* If, assign a value to the Ref variable (girlfriend) of this non-existent key, Then the original `Reactive object (userInfo)` will also add the key (girl) synchronously, and its value will also be updated synchronously. */ girlfriend.value = 'Marry' console.log('girlfriend=', girlfriend.value) // girlfriend= Marry console.log('userInfo.girl=', userInfo.girl) // userInfo.girlfriend= Marry console.log('Look at the attributes of userInfo =', userInfo) // Girl, id, name of Proxy
Why does emphasize not to use
in TypeScript? Because at compile time, TypeScript’s type checking cannot be passed.
If you must use it, you can consider using the any
type, as follows: 1, 2, 3
// 1. Directly specify the type as `any` type Member = any //Of course it is usually `const userInfo: any` // 2. Or allow any key value while maintaining the interface type. interface Member {<!-- --> [key: string]: any } // 3. The same applies to using `Record` type Member = Record<string, any>
Tell me about toRefs:
Unlike toRef, toRefs
only accepts one parameter (a reactive
variable)
interface People {<!-- --> id: number name: string } // Declare a `Reactive` variable. At this time, the TS type of `theKing` is: const theKing: People const theKing: People = reactive({<!-- --> id: 1, name: 'Black' }) console.log('theKing=', theKing) // Pass `toRefs` as input parameter. At this time, the TS type of this new `useToRefs` variable is no longer `People`, but: const useToRefs: ToRefs<People> const useToRefs = toRefs(theKing) console.log('useToRefs=', useToRefs) // You can also rewrite a new type to specify it, because each field is a Ref variable associated with the original, so it can also be declared like this: interface newPeople {<!-- --> id: Ref<number> name: Ref<string> } const useToRefsCopy: newPeople = toRefs(theKing) console.log('useToRefsCopy=', useToRefsCopy) That’s all. In fact, you don’t need to manually specify the type in daily use. TypeScript will automatically derive it, which can save a lot of development work.
Convert an array
const charList = reactive(['a', 'b', 'c']) const charListRefs = toRefs(charList) console.log('charListRefs=', charListRefs) console.log('charListRefs[0]=', charListRefs[0].value) // charListRefs[0]= a
Destructuring and assignment,
This is very different from directly deconstructing a Reactive variable. When deconstructing a Reactive variable directly, you get an ordinary variable that no longer has any response.
// The `Reactive object or array` converted with `toRefs` supports ES6 destructuring and `will not lose responsiveness`, because every variable after destructuring is responsive. const {<!-- --> name } = toRefs(theKing) console.log('name=', name.value) // name= Black // At this time, reassign the deconstructed variables and the original variables will be updated simultaneously. name.value = 'Tom' console.log('After reassignment-name=', name.value) // After reassignment-name= Tom console.log('After reassignment-theKing', theKing.name) // After reassignment-theKing Tom //--------------------------------Look at the example below---------------- ---------- /* Take a calculator function as an example, This time, it is modified to have a Reactive data status center inside, which is deconstructed into multiple Ref variables when the function returns. In this way, when calling the useCalculator function, the Ref variable can be obtained directly through destructuring, without the need for additional conversion work. */ interface CalculatorState {<!-- --> num: number, step: number // The amount to be increased for each calculation } // Declare a function that "uses the calculator" const useCalculator = () => {<!-- --> // Manage internal variables in the form of data center const state: CalculatorState = reactive({<!-- --> num: 0, step: 10 }) const add = () => {<!-- --> state.num + = state.step } return {<!-- --> ...toRefs(state), add } } //The deconstructed `num` and `step` are both Ref variables const {<!-- --> num, step, add } = useCalculator() console.log('num=', num.value) // num= 0 console.log('step=', step.value) // step= 10 // Call the calculator method, and the data will also be updated responsively add() console.log('After calling the add() method, num=', num.value) // After calling the add() method, num= 10