Lifecycle hook

This is the 21st day of my participation in the August Text Challenge.More challenges in August

Setup can be used to replace options like Data, Methods, computed, watch, and so on, as well as life-cycle hooks

You can register lifecycle hooks using the directly imported onX function

Created and beforeCreate hook functions are missing from the Composition API

The setup function is called as soon as the component is created

So the logic that would be executed in the Created and beforeCreate functions can be written directly inside the setup function

<template>
  <div>
    <button @click="changeCount">{{ count }}</button>
  </div>
</template>

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

export default {
  name: 'Home'.setup() {
    let count = ref(0)

    console.log(The setup function will be called first.)

    onMounted(() = > console.log('onMounted'))
    onUpdated(() = > console.log('onUpdated'))
    onBeforeUnmount(() = > console.log('onBeforeUnmount'))

    const changeCount = () = > count.value++

    return {
      count,
      changeCount
    }
  }
}
</script>
Copy the code

Dojo.provide and inject

We actually used Provide and Inject before, and the Composition API replaces the Provide and Inject options as well

We can define each Property with the provide method,

Inject desired properties and corresponding values in descendant components (inject desired properties and corresponding values)

Provide can be passed two arguments:

  • Name: name of the supplied property
  • Value: indicates the provided attribute value

Inject can be passed two parameters:

  • The name of the property to inject
  • The default value

Parent component - data provider

<template>
  <div>
    <h2>Name {{name}} in the Home component</h2>
    <h2>Age {{age}} in the Home component</h2>

    <button @click="changeAgeInHome">Modify the age in the Home component</button>

    <Home />
  </div>
</template>

<script>
import { ref, readonly, provide } from 'vue'
import Home from './components/Home.vue'

export default {
  name: 'App'.components: {
    Home
  },

  setup() {
    const name = ref('Klaus')
    const age = ref(23)

    // Provide data
    // Parameter 1 -- key
    // Parameter 2 -- value

    // provide data to descendant components that are best modified to readonly
    // Descendant components cannot modify the data provided by the parent component
    // If you want to modify, the descendant component can only emit an event for the parent (data provider) to modify
    // The purpose of this is to ensure one-way data flow, i.e. data is passed from parent to child
    // In this way, the data source will become unified during the later debugging, which is convenient for debugging and maintenance
    provide('name', readonly(name))
    provide('age', readonly(age))

    const changeAgeInHome = () = > age.value++

    return {
      name,
      age,
      changeAgeInHome
    }
  }
}
</script>
Copy the code

Child component - data consumer

<template>
  <div>
    <h2>{{ name }}</h2>
    <h2>{{ age }}</h2>
  </div>
</template>

<script>
import { readonly, ref, inject } from 'vue'

export default {
  name: 'Home'.setup() {
    // Inject receives the value provided by provide
    The inject function takes two arguments
    // Parameter 1: the name of the received data
    // Parameter 2: default value -- Optional
    const name = inject('name')
    
    // The default value is set to readonly to prevent child components from arbitrarily modifying the data passed by the parent component
    const age = inject('age', readonly(ref(18))

    return {
      name,
      age
    }
  }
}
</script>
Copy the code

Stage of practice

counter

use

<template>
  <div>
    <p>count: {{ count }}</p>
    <p>doubleCount: {{ doubleCount }}</p>

    <button @click="increment">increment</button>
    <button @click="decrement">decrement</button>
  </div>
</template>

<script>
// The name of the incoming hook function can be arbitrary, but it is recommended to refer to the react hook function and use the small hump beginning with use
import useCount from './hooks/useCount'

export default {
  name: 'Home'.setup() {
    const {
      count,
      doubleCount,
      increment,
      decrement
    } = useCount() // The introduced hook is a function, so it is called first

    return {
      count,
      doubleCount,
      increment,
      decrement
    }
  }
}
</script>
Copy the code

hook -- /src/hooks/useCount.js

import { ref, computed } from 'vue'

export default function() {
  const count = ref(0)
  const doubleCount = computed(() = > count.value * 2)

  const increment = () = > count.value++
  const decrement = () = > count.value--

  return {
    count,
    doubleCount,
    increment,
    decrement
  }
}
Copy the code

Another way to use it

<template>
  <div>
    <p>count: {{ count }}</p>
    <p>doubleCount: {{ doubleCount }}</p>

    <button @click="increment">increment</button>
    <button @click="decrement">decrement</button>
  </div>
</template>

<script>
// You can use the template to destruct the return value of the hook function directly
import useCount from './hooks/useCount'

export default {
  name: 'Home'.setup() {
    return {
      // Not recommended -- deconstructed data needs to be used in templates
      // If there are too many hook functions introduced, then it is not convenient to know.
      // Which hook function does that data come from. useCount() } } }</script>
Copy the code

Listen for scroll position

use

<template>
  <div class="screen">
    <div class="hint">
      <p>scrollX: {{ scrollX }}</p>
      <p>scrollY: {{ scrollY }}</p>
    </div>
  </div>
</template>

<script>
import useScrollPostion from './hooks/useScrollPostion'

export default {
  name: 'App'.setup() {
    const { scrollX, scrollY } = useScrollPostion()

    return {
      scrollX,
      scrollY
    }
  }
}
</script>

<style scoped>
.screen {
  width: 300vw;
  height: 300vh;
}

.hint {
  position: fixed;
  right: 30px;
  bottom: 30px;
}
</style>
Copy the code

hook

import { ref } from 'vue'

export default function() {
  const scrollX = ref(0)
  const scrollY = ref(0)

  window.addEventListener('scroll'.() = > {
    scrollX.value = window.scrollX
    scrollY.value = window.scrollY
  })

  return {
    scrollX,
    scrollY
  }
}
Copy the code

Monitoring mouse scrolling

import { ref } from 'vue'

export default function() {
  const mouseX = ref(0)
  const mouseY = ref(0)

  window.addEventListener('mousemove'.e= > {
    // We can use pageX and pageY in event to get the position of mouse movement
    mouseX.value = e.pageX
    mouseY.value = e.pageY
  })

  return {
    mouseX,
    mouseY
  }
}
Copy the code

localStorage

hook

import { ref, watch } from 'vue'

export default function(key, value) {
  const data = ref(value)

  if (value) {
    localStorage.setItem(key, JSON.stringify(value))
  } else {
    data.value = JSON.parse(localStorage.getItem(key))
  }

  // Data is a ref object, so when listening, listen for data.value
  // v is the value of newValue, which is the value property of data
  
  // Tips: If ref is an object, the value of the ref object is a reactive object by default
  watch(data.value, v= >  localStorage.setItem(key, JSON.stringify(v)))

  return data
}
Copy the code

use

<template>
  <div>
    <h2>{{ storage.name }}</h2>
    <button @click="changeStorage">change</button>
  </div>
</template>

<script>
import useLocalStorage from './hooks/useLocalStorage'

export default {
  name: 'App'.setup() {
    const storage = useLocalStorage('info', { name: 'Klaus' })

    console.log(useLocalStorage('info').value? .name)const changeStorage = () = > {
      storage.value.name = 'Alex'
    }

    return {
      storage,
      changeStorage
    }
  }
}
</script>
Copy the code

Setup top-level authoring

< Script Setup > is a compile-time syntactic sugar for using composite apis in single-file components (SFC)

Eventually, the vUE component is compiled as a setup function

The parent component

<template>
  <div>
    <Cpn :message="msg" @changeMsg="changeMsg" />
  </div>
</template>

<script setup>
 import { ref } from 'vue'
 
 // There is no need to define the component's name attribute in Script Setup. Its value is named as the file name of the SFC

 // The component can be used directly after it is introduced, without any registration operation
 import Cpn from './components/Cpn.vue'

 const msg = ref('Hello World')

 const changeMsg = v= > msg.value = v

 // All methods and data that need to be used in the template do not need to be returned
</script>
Copy the code

Child components

<template>
  <div>
    <h2>{{ message }}</h2>
    <button @click="change">change</button>
  </div>
</template>

<script setup>
 import { defineProps, defineEmits } from 'vue'

  // Accept the props passed by the parent component via defineProps
  defineProps({
    message: {
      type: String.required: true}})// Use the defineEmits method to define the events that need to be triggered
  // This method returns a function that all registered methods can use to fire events
  const emit = defineEmits(['changeMsg'])

  const change = function() {
    emit('changeMsg'.'Hello Vue')}</script>
Copy the code