This is the 26th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

reactive

Earlier we looked at a small example of converting primitive types to responsive objects for REF and computed:

<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png" /> <h1>{{ count }}</h1> <h1>{{ double }}</h1> < button@click ="increase">👍+1</button> </div> </template> <script lang="ts"> import {ref, computed} from "vue"; export default { name: "App", setup() { const count = ref(0); const double = computed(() => { return count.value * 2; }); const increase = () => { count.value++; }; return { count, increase, double, }; }}; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>Copy the code

In this case, however, the ref is usually a primitive type, and the variables are very scattered. If we want all the variables to be wrapped in one variable, we can use Reactive. Let’s take a look at the rewritten code:

<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png" /> <h1>{{ data.count }}</h1> <h1>{{ data.double }}</h1> < button@click ="data.increase">👍+1</button> </div> </template> <script lang="ts"> import {ref, computed, reactive } from "vue"; interface DataProps { count: number; double: number; increase: () => void; } export default { name: "App", setup() { const data: DataProps = reactive({ count: 0, increase: () => { data.count++; }, double: computed(() => data.count * 2), }); return { data, }; }}; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>Copy the code

Effect achieved:

Note:

const data = reactive({
            count: 0,
            increase: () => {
                data.count++;
            },
            double: computed(() => data.count * 2),
        });
Copy the code

Here if we don’t use interface it’s going to give us a type error. The following error message is displayed:

 'data' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.  
    35 |         // };
    36 |         // const data: DataProps = reactive({
  > 37 |         const data = reactive({
       |               ^^^^
    38 |             count: 0,
    39 |             increase: () => {
    40 |                 data.count++;
Copy the code

This is because using data.count in computed callbacks creates a type inference loop. So we’re going to use interface to create a new type.

Optimization:

We can use the spread operator (spread operator) in ES6 to expand the object.

<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png" /> <h1>{{ count }}</h1> <h1>{{ double }}</h1> < button@click ="increase">👍+1</button> </div> </template> <script lang="ts"> import {ref, computed, reactive } from "vue"; interface DataProps { count: number; double: number; increase: () => void; } export default { name: "App", setup() { const data: DataProps = reactive({ count: 0, increase: () => { data.count++; }, double: computed(() => data.count * 2), }); return { ... data, }; }}; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>Copy the code

Effect:

Or use the most basic way:

<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png" /> <h1>{{ count }}</h1> <h1>{{ double }}</h1> < button@click ="increase">👍+1</button> </div> </template> <script lang="ts"> import {ref, computed, reactive } from "vue"; interface DataProps { count: number; double: number; increase: () => void; } export default { name: "App", setup() { const data: DataProps = reactive({ count: 0, increase: () => { data.count++; }, double: computed(() => data.count * 2), }); return { count: data.count, increase: data.increase, double: data.double, }; }}; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>Copy the code

Effect:

Why? Let’s look at the type of count:

So it’s going to be number so it’s not going to be reactive and that’s why it’s going to get this result.

toRefs

At this point we use toRefs.

Converts a reactive object to a normal object, where each property of the resulting object is a REF pointing to the corresponding property of the original object.

Code:

<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png" /> <h1>{{ count }}</h1> <h1>{{ double }}</h1> < button@click ="increase">👍+1</button> </div> </template> <script lang="ts"> import {ref, computed, reactive } from "vue"; interface DataProps { count: number; double: number; increase: () => void; } export default { name: "App", setup() { const data: DataProps = reactive({ count: 0, increase: () => { data.count++; }, double: computed(() => data.count * 2), }); const refData = toRefs(data); return { ... refData, }; }}; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>Copy the code

Effect: