Modular API

01-setup

  1. We know it’s new in Vue3.0setupInstead of abeforeCreatecreatedAnd,setupbeforeCreatecreatedPerform more early
export default {
  beforeCreate () {
    console.log('beforeCreate')
  },

  created () {
    console.log('created')},setup() {
    console.log('setup')}}Copy the code

  1. The setup function is the entry point to the Composition API, where all Composition API functions are used and executed only once during initialization

  2. Properties and methods defined in the setup function must eventually be returned or they cannot be used in the template

  3. The official setup template example

<template>
  <div>{{ readersNumber }} {{ book.title }}</div>
</template>
Copy the code
<script>
  import { ref, reactive } from 'vue'

  export default {
    setup() {
      const readersNumber = ref(0)
      const book = reactive({ title: 'Vue 3 Guide' })

      // expose to template
      return {
        readersNumber,
        book
      }
    }
  }
</script>
Copy the code

parameter

The setup function takes two parameters, props and context

props

The props in the setup function is reactive and will be updated when the parent passes in a new props

export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}
Copy the code

Note: Because props are reactive, you cannot use ES6 deconstruction, which would eliminate the responsiveness of prop

Context

Context is a plain JavaScript object that exposes the component’s three properties

export default {
  setup(props, context) {
    // Attribute (non-responsive object)
    console.log(context.attrs)

    // slot (non-responsive object)
    console.log(context.slots)

    // Trigger event (method)
    console.log (context) emit)}} orexport default {
  setup(props, { attrs, slots, emit }){... }}Copy the code

Attrs and slots are stateful objects that are always updated as the component itself is updated. This means you should avoid deconstructing them and always refer to properties as attrs.x or slots.x

Access the component’s property

When SETUP is executed, the component instance has not yet been created. Therefore, you can only access the following property:

  1. props
  2. attrs
  3. slots
  4. emit

this

Calling this in setup is undefined because setup() is called before parsing other component options, so this inside setup() behaves completely differently than this in other options.

02- Life cycle

Vue3.0 calls the lifecycle hook inside setup ()

Vue2.x Vue3.x
beforeCreate No longer need
created No longer need
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestroy onBeforeUnmount
destroyed onUnmounted
errorCaptured onErrorCaptured

New hook function

  1. onRenderTracked
  2. onRenderTriggered

If you continue to use the Vue2. X syntax

  1. BeforeUnmount replaces beforeDestroy
  2. Unmounted replaces destroyed

03-ref

  1. Function: Defines a response to data

  2. Syntax: const XXX = ref(initValue);

  3. To access and modify the count variable inside setup, use count.value

  4. To manipulate data in a template:.value is not required

  5. The sample

<template>
    {{count}}
</template>
Copy the code
setup {
    const count = ref(0)
    console.log(count.value) / / 0
    
    count.value++
    console.log(count.value) / / 1
    
    return {count}
}
Copy the code
  1. Ref recommends defining basic data types, but you can also use complex data types, because if you define objects or arrays in ref, the Vue will help you convert them toReactive object

7. Implement ref by hand

// define a ref
function ref (target) {
// Reactive is implemented when the object type is specified
  target = reactive(target) 
  return {
    _is_ref: true.// Identifies the current object as a ref object
    // Save the target data
    _value: target,
    get value () {
      console.log('Hijacked to read data')
      return this._value;
    },
    set value (val) {
      console.log('Hijacked modify data, ready to update interface', val)
      this._value = val; }}}Copy the code
  1. refGet elements, for example, get input focus/call a function of a child component or access its properties
<template>
  <h2>App</h2>
  <input type="text">---
  <input type="text" ref="inputRef">
  
  <button @click="open">Open the popup window</button>
  <update ref="updateRef" />
</template>
Copy the code
<script lang="ts">
import { onMounted, ref } from 'vue'
import Update from "./components/update.vue"

export default {
  components: {
    Update
  },
  setup() {
    /** * Automatically get input focus */
    const inputRef = ref<HTMLElement|null> (null)
    onMounted(() = > {
      inputRef.value && inputRef.value.focus()
    })
    
    /** * Automatically calls the child component's open function */
    const updateRef = ref(null);
    const open = () = > { updateRef.value.open(); };
    return {
      inputRef
    }
  },
}
</script>

Copy the code

04-unref

  1. If the argument is oneref, returns the internal value, otherwise returns the parameter itself.
  2. This is val = isRef(val), right? Val. value: The syntactic sugar function of val.
  3. Handwritten implementationunref
// define a function unref to determine whether the current object is a ref object
function unref (target) {
  return target && target._is_ref? target.value : target;
}
Copy the code

05-toRef

  1. Can be used to create a new REF for a property on a source responsive object. The REF can then be passed, maintaining a reactive connection to its source property

  2. Ref = ref

    • refA copy of a new data value is operated separately, without affecting each other during update
    • toRefIt maintains a reactive connection to its source property
  3. Example 1: Reactive connection


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

const fooRef = toRef(state, 'foo')

fooRef.value++
console.log(state.foo) / / 2

state.foo++
console.log(fooRef.value) / / 3

Copy the code
  1. Example 2 If: definedhookThe function needs a ref object
// Only one ref object is received, and the value of ref is returned
function useData(foo: Ref) {
  return foo.value;
}

const component = defineComponent({
  props: {
    foo: {
      type: Number.require: true
    }
  },

  setup (props, context) {
    const data = useData(toRef(props, 'foo'))

    return {
      data
    }
  }
})
Copy the code
  1. ToRef is implemented by handwriting
// Define a function toRef that can be used to create a new ref for a property on a source responsive object. The REF can then be passed, maintaining a reactive connection to its source property.
function toRef(target, prop) {
  let _target = target[prop];
  let state = target && target._is_reactive;
  return {
    _value: _target,
    get value() {
      this._value = state ? target[prop] : this._value;
      return this._value;
    },
    set value(val) {
      this._value = val; target[prop] = state ? val : target[prop]; }}; }Copy the code

06-toRefs

  1. Converts a reactive object to a normal object, where each of the result objectspropertyThey all point to the original objectpropertyref.
  2. When a responsive object is returned from a combined function,toRefsVery useful so that the consuming component can decompose/diffuse the returned object without losing responsiveness:
  3. toRefsWill only be contained in the source objectpropertygenerateref. Use this if you want to create a REF for a particular propertytoRef
  4. The sample
setup {
    const data = reactive({
        tableData: [].loading: false,})// In the template we want to use the tableData and loading properties directly,
    // "..." It becomes unresponsive,
    // Destruct without losing responsiveness
    return {
        ...toRefs(data),
    }
}
Copy the code
  1. Handwritten implementationtoRefs
// Define a toRefsHandler handler object
function toRefsHandler(prop, val) {
  return {
    _value: val,
    __v_isRef: true._key: String(prop),
    get value() {
      return this._value;
    },
    set value(val) {
      this._value = val; }}; }// Define a function toRefs that converts a reactive object to a normal object, where each property of the resulting object is a ref to the corresponding property of the original object.
function toRefs(target) {
  let result = {};
  if (target && typeof target '= "object") {if (array.isarray (target)) {// Array data to traverse target.foreach ((item, index) => { result[index] = toRefsHandler(index, item); }); ForEach ((key) => {result[key] = toRefsHandler(key, target[key]); }); } return result; }}Copy the code

07-isRef

  1. Check if the value is a ref object
  2. Handwritten implementationisRef
function isRef(obj) {
  return obj && obj._is_ref
}
Copy the code

08-shallowRef

  1. Create a trace itself.valueChanges the ref, but does not make its value also responsive
  2. Shallow hijacking (shallow monitoring)—- shallow response
  3. Handwritten implementationshallowRef
function shallowRef(target) {
  const result = {
    _value: target, // An internal attribute used to hold data
    _is_ref: true.// is used to identify the ref object
    get value () {
      return this._value
    },
    set value (val) {
      this._value = val
      console.log('Set value data has been updated, go update interface')}}return result
}
Copy the code

09-customRef

  1. Create a customrefAnd has explicit control over its dependency tracing and update triggering.
  2. It requires a factory function that acceptstracktriggerFunction as arguments, and should return an object with get and set
  3. Using customrefthroughv-modelimplementationdebounceExample:
<input v-model="text" />
Copy the code
function useDebouncedRef(value, delay = 200) {
  let timeout
  return customRef((track, trigger) = > {
    return {
      get() {
        // Trace its dependencies
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() = > {
          value = newValue
          // Update triggered
          trigger()
        }, delay)
      }
    }
  })
}

export default {
  setup() {
    return {
      text: useDebouncedRef('hello')}}}Copy the code

10-triggerRef

  1. Manual execution andshallowRefAssociated with any side effects.
const shallow = shallowRef({
  greet: 'Hello, world'
})

// Record "Hello, world" on the first run
watchEffect(() = > {
  console.log(shallow.value.greet)
})

// This does not trigger side effects because refs are shallow
shallow.value.greet = 'Hello, universe'

// record "Hello, universe"
triggerRef(shallow)

Copy the code

11-reactive

  1. Returns a reactive copy of the object
  2. Deep hijacking (deep monitoring)—- deep responsiveness
  3. Reactive transformation is “deep” — it affects all nested properties
  4. Through internalProxyReflectimplementation
  5. Handwritten implementationreactive
// Define a reactiveHandler handler object
const reactiveHandler = {
  // Get the attribute value
  get(target, prop) {
    if (prop `= "_is_reactive") return true; const result = Reflect.get(target, prop); Console. log(" intercepted read data ", prop, result); return result; }, // Add attribute set(target, prop, value) {const result = reflect. set(target, prop, value); Console. log(" intercepted modified data or added properties ", prop, value); return result; }, // Delete a property deleteProperty(target, prop) {const result = reflect.deleteProperty (target, prop); Console. log(" blocked deleted data ", prop); return result; }}; Function reactive(target) {if (target && typeof target ') {function reactive(target) {if (target && typeof target '= "object") {
    // Perform recursive processing of all data in arrays or objects reactive
    // Check whether the current data is an array
    if (Array.isArray(target)) {
      // The array is traversed
      target.forEach((item, index) = > {
        target[index] = reactive(item);
      });
    } else {
      // Determine if the current data is an object
      // The data of the object is also traversed
      Object.keys(target).forEach((key) = > {
        target[key] = reactive(target[key]);
      });
    }
    return new Proxy(target, reactiveHandler);
  }
  // If the data passed in is of a primitive type, it is returned directly
  return target;
}
Copy the code

12-readonly

  1. A read-only proxy that accepts an object (reactive or pure) or ref and returns the original object
  2. A read-only proxy is deep: any nested property accessed is also read-only.
  3. withreactiveSame if any property is usedrefWhen accessed through a proxy, it is automatically unpacked:
const raw = {
  count: ref(123)}const copy = readonly(raw)

console.log(raw.count.value) / / 123
console.log(copy.count) / / 123
Copy the code
  1. Handwritten implementationreadonly
// Defines a readonlyHandler handler
const readonlyHandler = {
  get(target, prop) {
    if (prop `= "_is_readonly") return true; const result = Reflect.get(target, prop); Console. log(" read data intercepted ", prop, result); return result; }, set(target, prop, value) {console.warn(" can only read data, cannot modify data or add data "); return true; }, deleteProperty(target, prop) {console.warn(" read data only, don't delete data "); return true; }}; Function readonly(target) {if (target && typeof target '= "object") {
    // Check whether target is an array
    if (Array.isArray(target)) {
      // go through the number group
      target.forEach((item, index) = > {
        target[index] = readonly(item);
      });
    } else {
      // Determine whether target is an object
      // Iterate over the object
      Object.keys(target).forEach((key) = > {
        target[key] = readonly(target[key]);
      });
    }
    return new Proxy(target, readonlyHandler);
  }
  // If it is not an object or array, return it directly
  return target;
}
Copy the code

13-isProxy

  1. Check whether the object is created byreactivereadonlyCreate the proxy
  2. The return value is Boolean
  3. Handwritten implementationisProxy
// Define a function isProxy to check whether the current object is reactive or readonly
function isProxy(obj) {
  return isReactive(obj) || isReadonly(obj);
}
Copy the code

14-isReactive

  1. Check whether the object is created byreactiveCreate a responsive proxy.
  2. The return value is of Boolean type
  3. Handwritten implementationisReactive
// Define a function isReactive to check whether the current object is a reactive object
function isReactive(obj) {
  return obj && obj._is_reactive;
}
Copy the code

15-isReadonly

  1. Check whether the object is a read-only proxy created by ReadOnly
  2. The return value is of Boolean type
  3. Handwritten implementationisReadonly
// Define a function isReadonly to determine whether the current object is a readOnly object
function isReadonly(obj) {
  return obj && obj._is_readonly;
}
Copy the code

15-toRaw

  1. returnreactivereadonlyThe original object of the proxy.
  2. Changed the proxy object into a normal object, the data changes, the interface does not change
  3. It is not officially recommended.
const foo = {}
const reactiveFoo = reactive(foo)

console.log(toRaw(reactiveFoo) `= foo) // true
Copy the code

16-markRaw

  1. Marks an object so that it will never be converted to a proxy. Return the object itself
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false

// Can also be used when nested within other reactive objects
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false

Copy the code

17-shallowReactive

  1. Create a reactive proxy that tracks the responsiveness of its own property, but does not perform deep reactive transformations of nested objects (exposing raw values).
  2. Shallow hijacking (shallow monitoring)—- shallow response
  3. The official sample
const state = shallowReactive({
  foo: 1.nested: {
    bar: 2}})// Changing the nature of state itself is reactive
state.foo++
/ /... But nested objects are not converted
isReactive(state.nested) // false
state.nested.bar++ // non-responsive
Copy the code
  1. Handwritten implementationshallowReactive
// Define a shallowReactive function that passes in a target object
function shallowReactive(target) {
  // Check whether the current target object is of type object (object/array)
  if (target && typeof target `= "object") { return new Proxy(target, reactiveHandler); } // If the data passed is of a primitive type, return target directly; }Copy the code

18-shallowReadonly

  1. Create a proxy that makes its own property read-only, but does not perform deep read-only conversion of nested objects (exposing raw values)
  2. Shallow hijacking (shallow monitoring)—- shallow read-only
  3. The official sample
onst state = shallowReadonly({
  foo: 1.nested: {
    bar: 2}})// Changing the property of state itself will fail
state.foo++
/ /... But it applies to nested objects
isReadonly(state.nested) // false
state.nested.bar++ / / for
Copy the code
  1. Handwritten implementationshallowReadonly
// Define a shallowReadonly function
function shallowReadonly(target) {
  // We need to determine whether the current data is an object
  if (target && typeof target `= "object") { return new Proxy(target, readonlyHandler); } return target; }Copy the code

19 – dojo.provide and inject

  1. Provide and inject provide dependency injection functions similar to those of 2.xprovide/inject
  2. Realize communication between components (grandparent and grandchild) across hierarchies
<! -- Parent component -->
<template>
  <h2>The parent component</h2>
  <Son />
</template>
<script lang="ts">
import { provide, ref } from 'vue'
import Son from './Son.vue'

export default {
  name: 'ProvideInject'.components: {
    Son
  },
  setup() {
    
    const msg = ref('I'm the MSG of the parent component')

    provide('msg', msg)

    return {
      msg
    }
  }
}
</script>
Copy the code
<! Son.vue--> <template> <div> <h2> <hr> <GrandSon /> </div> </template> <script lang="ts"> import GrandSon from './GrandSon.vue' export default { components: { GrandSon }, } </script>Copy the code
<! <template> <h3 :style="{MSG}"> {{msg}}</h3> </template> <script lang="ts"> import { inject } from 'vue' export default { setup() { const msg = inject('msg') return { msg } } } </script>Copy the code

At the end

  • This article is mainly for the author to learn Vue3.0 from teacher Yang Hongbo
  • This article incorporates the official Vue3.0 documentation
  • The handwritten part of this article is only a simple implementation, which has not considered the complex logic
  • If there is any improper please correct