【vue3】钩子函数详细介绍

2 篇文章 0 订阅
1 篇文章 0 订阅

1、setup()

这不是一个传统的钩子函数,但它是最主要的入口点,其为我们使用 Vue3 的 Composition API 新特性提供了统一的入口,用于初始化组件的状态和定义组合逻辑。

setup() 函数可以接收两个参数:props 和 context。然而,在使用 <script setup> 语法糖时,props 可以直接解构,而不需要显式地接收 context。

1)基本示例:

// 使用普通 script 标签
export default {
  name: 'MyComponent',
  props: ['message'],
  setup(props) {
    // 使用 ref 创建响应式引用
    const count = ref(0);

    // 定义一个方法来增加计数
    const increment = () => {
      count.value++;
    };

    // 返回模板中可访问的属性和方法
    return {
      count,
      increment,
      message: props.message
    };
  }
};

2)使用 <script setup> 语法糖时,代码变得更简洁:

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

<script setup>
import { ref } from 'vue';

const count = ref(0);

const increment = () => {
  count.value++;
};
</script>

在 <script setup> 中,你不再需要返回任何东西,因为脚本中的顶层绑定现在是模板上下文的一部分。同时,你也可以直接解构 props,使得代码更清晰:

<template>
  <div>{{ message }}</div>
</template>

<script setup>
defineProps({
  message: String
});
</script>

备注:defineProps() 是一个实用函数,用于在 <script setup> 中声明组件的 props。同样地,你可以使用 defineEmits() 来声明组件可以触发的自定义事件。


2、ref() 和 reactive()

虽然不是严格意义上的钩子,但这两个函数用于创建响应式数据引用和对象。ref() 创建一个响应式的值引用,而reactive() 创建一个响应式的对象。

1、ref() 用于创建一个响应式引用类型。它接受一个值作为参数,并返回一个包含该值的响应式引用对象。这个引用对象有一个 .value 属性,用于获取或设置其内部值。

<template>
  <p>Count: {{ count }}</p>
  <button @click="increment">Increment</button>
</template>

<script setup>
import { ref } from 'vue';

// 创建一个初始值为 0 的响应式引用
const count = ref(0);

// 方法来修改 ref 的值
const increment = () => {
  count.value++;
};
</script>

2、reactive()

reactive() 用于使一个对象成为响应式的。它接受一个普通 JavaScript 对象作为参数,并返回一个经过代理的响应式版本的该对象。与 ref() 不同,你不需要使用 .value 来访问或修改对象的属性。

<template>
  <p>{{ state.message }}</p>
  <button @click="updateMessage">Update Message</button>
</template>

<script setup>
import { reactive } from 'vue';

// 创建一个响应式对象
const state = reactive({
  message: 'Hello Vue!',
  count: 0
});

// 修改响应式对象的属性
const updateMessage = () => {
  state.message = 'Updated message!';
};
</script>

3、computed()

用于创建计算属性,当依赖的数据变化时,计算属性会被重新计算。

传统写法是嵌套在export default 下的setup()中,此处我们使用 <script setup>语法糖来写:

<template>
  <div>
    <p>Full Name: {{ fullName }}</p>
    <button @click="updateName">Update Name</button>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';

// 响应式状态
const firstName = ref('John');
const lastName = ref('Doe');

// 使用 computed 创建 fullName 计算属性
const fullName = computed(() => {
  return `${firstName.value} ${lastName.value}`;
});

// 更新名字的方法
const updateName = () => {
  firstName.value = 'Jane';
  lastName.value = 'Doe';
};
</script>

4、watch()

用于观察响应式数据的变化,并在数据发生变化时执行某些操作。

传统写法是嵌套在export default 下的setup()中,此处我们使用 <script setup>语法糖来写:

import { ref, watch } from 'vue';

export default {
  setup() {
    // 1、监听ref的参数
    const count1 = ref(0);
    const count2 = ref(0);

    // 同时监听 count1 和 count2 的变化
    watch([count1, count2], ([newCount1, newCount2], [oldCount1, oldCount2]) => {
      console.log(`Count1 changed from ${oldCount1} to ${newCount1}`);
      console.log(`Count2 changed from ${oldCount2} to ${newCount2}`);
    }, { immediate: true, deep: true });

    // 更新 count1 和 count2 的方法
    const incrementCount1 = () => {
      count1.value++;
    };

    const incrementCount2 = () => {
      count2.value++;
    };

    // 2、监听reactive的变化
    const state = reactive({ nested: { count: 0 } });

   // 深度监听 state 对象的所有属性
    watch(state, (newValue, oldValue) => {
      console.log(`State changed from`, oldValue, `to`, newValue);
    }, { deep: true });

    // 更新 state.nested.count 的方法
    const increment = () => {
      state.nested.count++;
    };

    return {
      count1,
      count2,
      incrementCount1,
      incrementCount2,
      state,
      increment
    };
  }
};

备注:

1、deep: true:立即触发

2、deep: true:深度监听一个响应式对象的所有属性

 5、onBeforeMount()

在组件被挂载到DOM中之前调用。

<script setup>
import { onBeforeMount, ref } from 'vue';

onBeforeMount(() => {
    // 在组件挂载前加载数据
});
</script>

备注:由于 onBeforeMount() 钩子在服务端渲染(SSR)期间也会被调用,因此确保在这个钩子中执行的代码是可以在没有 DOM 环境下运行的,例如异步数据加载是可以的,而涉及到 DOM 操作的代码则不适合放在这里。此外,异步操作可能需要使用 async/await 语法来等待操作完成,如上面示例中所示。 

6、onMounted()

当组件被挂载到DOM中后调用。这是执行异步操作或初始化事件监听器的好地方。

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

onMounted(() => {
  // 执行方法
});
</script>

备注:onMounted() 只在服务端渲染(SSR)中被跳过,因为它依赖于浏览器环境,不会在没有 DOM 的环境中执行。如果你的应用支持 SSR,确保在 onMounted 中执行的代码不会抛出错误,因为它们可能在没有 DOM 的环境中被调用。

 7、onBeforeUpdate()

在组件开始更新之前调用。

<script setup>
import { onBeforeUpdate, ref } from 'vue';

onBeforeUpdate(() => {
  // 执行方法
});
</script>

备注:

1、onBeforeUpdate() 钩子并不阻止更新的发生,它只是允许你在更新发生前执行一些代码。如果你需要在更新后执行代码,可以使用 onUpdated() 生命周期钩子。

2、在 Vue 3 的 Composition API 中,这些钩子函数应该在 setup() 函数内部定义,以便它们可以访问由 ref 或 reactive 创建的响应式状态。

 

8、onUpdated()

当组件完成更新后调用。这个钩子在服务器端渲染期间不被调用。

<script setup>
import { onUpdated, ref } from 'vue';

onUpdated(() => {
  // 组件更新后执行的代码
});
</script>

备注:onUpdated() 钩子在服务端渲染(SSR)期间不会被调用,因为它依赖于 DOM 更新,而 SSR 在客户端首次加载时才生成完整的 HTML。因此,确保你的 onUpdated 钩子中的代码不会在没有 DOM 的环境中引发错误。 

 8、onBeforeUnmount()

在组件被卸载并从DOM中移除之前调用。

<script setup>
import { onBeforeUnmount, ref } from 'vue';

onBeforeUnmount(() => {
    // 在组件卸载前停止计数
});
</script>

备注:确保在组件生命周期的适当阶段进行清理是非常重要的,特别是在处理定时器、WebSocket 连接或外部资源时。onBeforeUnmount() 提供了一个执行这些清理任务的理想时机。 

9、onUnmounted()

当组件被卸载并从DOM中移除时调用。这是清除定时器、事件监听器等资源的好时机。

<script setup>
import { onUnmounted, ref } from 'vue';

onUnmounted(() => {
  // 当组件卸载前执行
});
</script>

备注:在实际应用中,你可能会有更复杂的场景,例如订阅 WebSocket 连接、注册全局事件监听器等,在这些情况下,onUnmounted() 钩子同样可以用来确保在组件不再使用时进行适当的清理工作。

10、provide() 和 inject()

provide() 和 inject() 是用于实现祖先组件向后代组件注入数据或功能的一种方式,无需通过中间组件显式地传递 props。这对于跨多层组件树传递数据特别有用,可以避免 prop-drilling(道具钻孔)的问题。

1、父组件(Parent.vue)

<template>
  <Child />
</template>

<script setup>
import Child from './Child.vue';

// 使用 provide() 注入数据
const theme = 'dark';
const toggleTheme = () => {
  // 实现主题切换逻辑
  theme === 'dark' ? 'light' : 'dark';
};

provide('theme', theme);
provide('toggleTheme', toggleTheme);
</script>

2、子组件(Child.vue)

<template>
  <Grandchild />
</template>

<script setup>
import Grandchild from './Grandchild.vue';

// 使用 inject() 接收数据
const theme = inject('theme');
const toggleTheme = inject('toggleTheme');

console.log('Current theme:', theme);
</script>

3、孙组件(Child.vue)

<template>
  <div>
    Current theme is: {{ theme }}
    <button @click="toggleTheme">Toggle Theme</button>
  </div>
</template>

<script setup>
// 使用 inject() 接收数据
const theme = inject('theme');
const toggleTheme = inject('toggleTheme');

console.log('Current theme:', theme);
</script>

在这个示例中,Parent.vue 组件使用 provide() 向其子代组件树中注入了 theme 和 toggleTheme。Child.vue 和 Grandchild.vue 组件通过 inject() 来接收这些值。即使 Grandchild.vue 并没有直接从父组件接收这些值,它仍然能够访问到这些信息,因为它们已经被注入到了组件树中。

备注:值得注意的是,provide() 应该在一个组件的 setup() 函数中调用,而 inject() 可以在任何组件的 setup() 函数中使用,甚至在模板表达式中也可以直接使用注入的值。

 此外,inject() 允许提供一个默认值,以防注入的键在祖先组件中未被提供。例如:

const theme = inject('theme', 'light'); // 如果 'theme' 未被提供,则默认为 'light'

这样,即使某个组件忘记使用 provide() 提供数据,你的应用也不会崩溃,并且可以提供一个合理的默认行为。

  • 33
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值