What does the Composition API bring to Vue

  • Better code organization
  • Better logic reuse
  • Better type derivation

Better code organization

  • In optionsAPI components, when a component becomes too large, the list of different business logic also grows. When working with individual business logic, we must constantly “jump” to the option blocks of the related code. Fragmentation makes it difficult to understand and maintain complex components.

  • The Composition API enables us to gather together related code for the same logic.

Better logic reuse

In Setup, you can separate the logical code into a separate composite function. The function naming convention is useXxxx format, and then reference the useXxx function in setup

Example: Get the mouse logic to pull away

What if we wanted to remove the mouse-capture logic so that each component could use a responsive mouse-location coordinate? We can write the logic in a separate file, extract the above code into a separate composite function, export it, and reference it in setup

//useMousePosition.js
import {  ref, onMounted, onUnmounted } from 'vue'

function useMousePosition() {
    const x = ref(0)
    const y = ref(0)

    function update(e) {
        x.value = e.pageX
        y.value = e.pageY
    }

    onMounted(() = > {
        console.log('useMousePosition mounted')
        window.addEventListener('mousemove', update)
    })

    onUnmounted(() = > {
        console.log('useMousePosition unMounted')
        window.removeEventListener('mousemove', update)
    })

    return {
        x,
        y
    }
}
Copy the code

Use: import the relevant logic, deconstruct the coordinates

<template>
    <p>mouse position {{x}} {{y}}</p>
</template>

<script>
import useMousePosition from './useMousePosition'

export default {
    name: 'MousePosition'.setup() {
        const { x, y } = useMousePosition()
        return {
            x,
            y
        }
    }
}
</script>
Copy the code

Better type derivation

In optionsAPI,datamethodscomputedEtc are mounted to the current instance, unified usethisThis makes it unhelpful to derive types syntactically. According to js usage habits, we should use similarthis.methods.fn1()Is logical.

Vue3 setup does not use this. Instead, it wraps each logic into a function, making the logic clearer and returning values clear.

ref() / reactive()toRef() / toRefs()

ref / reactiveuse

Ref () :

  • The ref function takes an internal value (the original value) and returns a reactive and mutable REF object.

  • This object is an object with a value property that can be used to access or change the value of a reactive variable.

  • The ref value can be used for templates and reactive

Reactive () :

  • To create reactive state for JavaScript objects, you can use the Reactive method

  • The API returns a reactive object state.

  • Reactive conversions are “deep” — they apply to all nested properties

The view updates automatically when the reactive state changes

For example:

<template>
    <p>ref demo {{ageRef}} {{state.name}}</p>
</template>

<script>
import { ref, reactive } from 'vue'

export default {
    name: 'Ref'.setup() {
        const ageRef = ref(20) // The value type is responsive
        const nameRef = ref(' ')

        const state = reactive({
            name: nameRef
        })

        setTimeout(() = > {
            console.log('ageRef', ageRef.value)

            ageRef.value = 25 //. Value Changes the value
            nameRef.value = 'xxx'
        }, 1500);

        return {
            ageRef,
            state
        }
    }
}
</script>
Copy the code

Ref can also get DOM elements

<template>
    <p ref="elemRef">I'm a line of text</p>
</template>

<script>
import { ref, onMounted } from 'vue'

export default {
    name: 'RefTemplate'.setup() {
        const elemRef = ref(null)

        onMounted(() = > {
            console.log('ref template', elemRef.value.innerHTML, elemRef.value)
        })

        return {
            elemRef
        }
    }
}
</script>
Copy the code

toRef / toRefsuse

ToRef: Creates a REF for a prop wrapped reactive object and maintains a reference relationship between the two

<template>
    <p>toRef demo - {{ageRef}} - {{state.name}} {{state.age}}</p>
</template>

<script>
import { ref, toRef, reactive } from 'vue'

export default {
    name: 'ToRef'.setup() {
        const state = reactive({
            age: 20.name: 'xxx'
        })

        const age1 = computed(() = > {
            return state.age + 1
        })

        // // toRef If used for ordinary objects (non-reactive objects), the output does not have a reactive formula
        // const state = {
        // age: 20,
        // name: 'xxx'
        // }

        const ageRef = toRef(state, 'age')

        setTimeout(() = > {
            state.age = 25
        }, 1500)

        setTimeout(() = > {
            ageRef.value = 30 //. Value Changes the value
        }, 3000)

        return {
            state,
            ageRef
        }
    }
}
</script>
Copy the code

ToRefs: Transforms a reactive object (wrapped in Reactive) into a normal object. Each prop of the object is a corresponding REF, and the two are referenced

<template>
    <p>toRefs demo {{age}} {{name}}</p>
</template>

<script>
import { ref, toRef, toRefs, reactive } from 'vue'

export default {
    name: 'ToRefs'.setup() {
        const state = reactive({
            age: 20.name: 'xx'
        })

        const stateAsRefs = toRefs(state) // Turn a reactive object into a normal object

        // const {age: ageRef, name: nameRef} = stateAsRefs
        // return {
        // ageRef,
        // nameRef
        // }

        setTimeout(() = > {
            state.age = 25
        }, 1500)

        return stateAsRefs
    }
}
</script>
Copy the code

So if you use the toRefs structure, the responsiveness is preserved, and if you write it like this, you lose the responsiveness

setup() {
    const state = reactive({
        age: 20.name: 'xx'
    })
    return {
        ...state
    }
}
Copy the code

Best way to use the above API

  • Reactive for objects and REF for value type responses

  • Setup returns toRefs(state), or toRef(state,’ XXX ‘). Try not to return reactive objects, otherwise you will need to use variables in the template as state.xxx

  • XxxRef = xxxRef = xxxRef = xxxRef

  • ToRefs is used when a synthesized function returns a reactive object, for example:

Deep understanding of

Why we needref

The official answer:

To put it simply:

  1. Return value type, the response will be lost. By changing this reactive value to a reference, it can be modified anywhere without losing its responsiveness and can be safely modified

  2. For example, setup, computed (computed returns an object similar to ref, including.value), and composite functions can all return value types. If Vue does not define ref, users will create their own ref, which will be chaotic

.value

<template>
    <p>why ref demo {{state.age}} - {{age1}}</p>
</template>

<script>
import { ref, toRef, toRefs, reactive, computed } from 'vue'

function useFeatureX() {
    const state = reactive({
        x: 1.y: 2
    })

    return toRefs(state)
}

export default {
    name: 'WhyRef'.setup() {
        const { x, y } = useFeatureX()

        const state = reactive({
            age: 20.name: 'xxx'
        })

        // Computed returns an object similar to ref, also with.value
        const age1 = computed(() = > {
            return state.age + 1
        })

        setTimeout(() = > {
            state.age = 25
        }, 1500)

        return {
            state,
            age1,
            x,
            y
        }
    }
}
</script>
Copy the code

refWhy is the created object needed.value

  1. As stated above, ref is an object (so as not to lose the response), so use.valueUsed to store its original value
  2. Can be achieved by.valueProperties of thegetsetImplementing responsiveness

Note: For templates and reactive, you do not need to write.value. For other cases, you need to obtain and modify

Why we needtoReftoRefs

ToRefs is useful when returning a reactive object from a composite function so that the consuming component can decompose/diffuse the returned object without losing its responsiveness. (This also makes it easier to deconstruct the assignment)

function useFeatureX() {
  const state = reactive({
    foo: 1.bar: 2
  })

  // Operate on the logic of state

  // Convert to ref on return
  return toRefs(state)
}

export default {
  setup() {
    // Can be destructed without losing responsiveness
    const { foo, bar } = useFeatureX()

    return {
      foo,
      bar
    }
  }
}
Copy the code

So, the goal is to decompose/diffuse the object data without losing the response. You don’t create responsiveness, you continue responsiveness

setupIn theprops

So props in Setup is equivalent to a reactive object created using reactive functions.

Notice, optionalpropsWill not betoRefsProcessing, so if apropsIt doesn’t have to be transmitted, it has to be usedtoRef, the official website is explained as follows:For example:

<PropsTest :p1="' I am p1" :p2="' I am the p2 '"></PropsTest>
Copy the code
//PropsTest.vue
<template>
  <p>props demo <br>
    p1:{{p1}}  <br>
    p2:{{p2}}  <br>
    p3:{{p3}}</p>
</template>

<script>
import {ref, reactive, toRef, toRefs, onMounted} from 'vue'

export default {
  name: 'PropsTest'.setup(props) {
    const {p1, p2,p3} = toRefs(props)
    // const p3 = toRef(props, 'p3')
    onMounted(() = > {
      console.log('p1', p1)
      console.log('p2', p2)
      console.log('p3', p3)
      return {
        p1,
        p2,
        p3
      }
    })
  },
  props: {p1:String.p2:String.p3:String}}</script>
Copy the code

If used this way:

const {p1, p2} = toRefs(props)
const p3 = toRef(props, 'p3')
Copy the code

You can return a reactive object