Vue 3 Composition API与Hooks模式

Vue 3 的 Composition API 引入了 Hook 函数的概念,这是一种更加模块化和可重用的状态管理和逻辑组织方式。

自定义Hook

首先,我们创建一个自定义 Hook,例如 useCounter,它封装了计数器的逻辑:

javascript 复制代码
// useCounter.js
import { ref } from 'vue';

export function useCounter() {
  const count = ref(0);

  function increment() {
    count.value++;
  }

  function decrement() {
    count.value--;
  }

  return {
    count,
    increment,
    decrement
  };
}

在上面的代码中,ref 用于创建响应式数据,incrementdecrement 方法分别用于增加和减少计数器的值。return 语句暴露了可以被组件直接使用的数据和方法。

然后,在组件中,我们可以导入并使用这个 Hook:

javascript 复制代码
<template>
  <div>
    <h1>Count: {{ count }}</h1>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
  </div>
</template>

<script>
import { defineComponent } from 'vue';
import { useCounter } from './useCounter';

export default defineComponent({
  setup() {
    const { count, increment, decrement } = useCounter();

    return {
      count,
      increment,
      decrement
    };
  }
});
</script>

在组件的 setup 函数中,我们调用了 useCounter Hook 并将返回的对象解构赋值给局部变量。这些变量可以直接在模板中使用,因为它们都是响应式的。

这种模式的好处在于:

  1. 逻辑分离:Hook 可以封装特定的业务逻辑,使得组件代码更清晰,更容易维护。
  2. 复用性:Hook 可以在多个组件之间共享,减少代码重复。
  3. 类型安全:在 TypeScript 中,自定义 Hook 可以提供类型定义,提高代码的可读性和可预测性。
  4. 响应式系统:通过 ref 或 reactive 创建的响应式数据,可以确保状态变化时视图的自动更新。

Vue 3 的 Composition API 结合 Hook 模式,使得开发者能够更灵活地组织和重用代码,提高了代码的可维护性和开发效率。

内置Hook

除了自定义 Hook,Vue 3 的 Composition API 还提供了许多内置 Hook,如 watch, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, toRefs, computed, watchEffect 等。

1. onMounted: 当组件挂载完成后执行的钩子。

javascript 复制代码
import { onMounted } from 'vue';

export default {
  setup() {
    let element;

    onMounted(() => {
      element = document.querySelector('#someElement');
      // 在这里可以执行依赖于DOM的初始化操作
    });

    return {};
  }
};

2. computed: 计算属性,类似于 Vue 2 中的计算属性。

javascript 复制代码
import { ref, computed } from 'vue';

export default {
  setup() {
    const base = ref(10);
    const multiplier = ref(2);

    const result = computed(() => {
      return base.value * multiplier.value;
    });

    return {
      base,
      multiplier,
      result
    };
  }
};

3. watch: 监听响应式数据的变化。

javascript 复制代码
import { ref, watch } from 'vue';

export default {
  setup() {
    const base = ref(10);
    const multiplier = ref(2);

    watch(base, (newBase, oldBase) => {
      console.log(`Base changed from ${oldBase} to ${newBase}`);
    });

    return {
      base,
      multiplier
    };
  }
};

4. watchEffect: 在任何依赖改变时运行的副作用函数。

javascript 复制代码
import { ref, watchEffect } from 'vue';

export default {
  setup() {
    const base = ref(10);
    const multiplier = ref(2);

    watchEffect(() => {
      console.log(`Result: ${base.value * multiplier.value}`);
    });

    return {
      base,
      multiplier
    };
  }
};

5. toRefs: 将对象的属性转换为响应式引用,以便直接在模板中使用。

javascript 复制代码
import { ref, toRefs } from 'vue';

export default {
  props: {
    user: {
      type: Object,
      required: true
    }
  },
  setup(props) {
    const { name, age } = toRefs(props.user);

    return {
      name,
      age
    };
  }
};

6. reactive: 创建一个响应式对象,允许深度监听对象的属性变化。

javascript 复制代码
import { reactive } from 'vue';

export default {
  setup() {
    const state = reactive({
      count: 0,
      user: {
        name: 'John Doe',
        age: 30
      }
    });

    function increment() {
      state.count++;
    }

    return {
      state,
      increment
    };
  }
};

7. provide/inject: 提供和注入依赖,类似于 Vue 2 中的非响应式版本,但Vue 3中可以提供响应式数据。

javascript 复制代码
// 父组件
import { provide } from 'vue';

export default {
  setup() {
    const theme = ref('light');

    provide('theme', theme);

    return {};
  }
};
javascript 复制代码
// 子组件
import { inject } from 'vue';

export default {
  setup() {
    const theme = inject('theme');

    return {
      theme
    };
  }
};

8. watch with options:

提供更细粒度的控制,如深度监听、异步处理和仅在初始值更改时触发。

javascript 复制代码
import { ref, watch } from 'vue';

export default {
  setup() {
    const base = ref(10);
    const multiplier = ref(2);

    watch(
      [base, multiplier],
      ([newBase, newMultiplier], [oldBase, oldMultiplier]) => {
        if (newBase !== oldBase || newMultiplier !== oldMultiplier) {
          console.log(`Result: ${newBase * newMultiplier}`);
        }
      },
      {
        deep: true, // 深度监听
        immediate: true // 初始值更改时立即触发回调
      }
    );

    return {
      base,
      multiplier
    };
  }
};

9. effectScope: 用于在特定作用域内运行副作用,便于清理和管理。

javascript 复制代码
import { effectScope, ref } from 'vue';

export default {
  setup() {
    const scope = effectScope();
    const count = ref(0);

    const stopEffect = scope.run(() => {
      console.log('Effect running');
      scope.watch(count, () => {
        console.log(`Count is now: ${count.value}`);
      });
    });

    return {
      count,
      stopEffect
    };
  }
};
相关推荐
阿伟来咯~13 分钟前
记录学习react的一些内容
javascript·学习·react.js
吕彬-前端18 分钟前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱20 分钟前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai30 分钟前
uniapp
前端·javascript·vue.js·uni-app
也无晴也无风雨31 分钟前
在JS中, 0 == [0] 吗
开发语言·javascript
bysking1 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓2 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4112 小时前
无网络安装ionic和运行
前端·npm
理想不理想v2 小时前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云2 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js