为什么 Mixin 被认为是有害的

为什么 Mixin 被认为是有害的

Mixin 是在 Vue 2 中引入的,作为组件之间共享代码的解决方案,这种方式成为许多代码库不可或缺的一部分。然而,随着时间的推移,它们的使用开始出现问题。尽管 mixins 最初很有吸引力,但现在许多开发人员认为它是有害的。在本文中,我们将探讨Mixin的缺点和更好的共享代码的方法。

缺点

复杂

Mixin 可以向组件添加过多的逻辑,使其变得更加复杂且难以理解,从而导致意想不到的后果和维护困难。例如,如果一个组件有多个 mixin,每个 mixin 都有自己的属性和方法,那么该组件将有很多逻辑,并且很难确定每个属性和方法如何影响组件的行为。由于混入而导致组件过于复杂,使得扩展或调试变得具有挑战性。

为了避免这种情况,明智地选择 mixins 并确保它们简化而不是使得组件的逻辑复杂化至关重要。Mixin 会给组件带来偶然和本质的复杂性。偶然复杂性是指在不影响功能的情况下可以消除的不必要的复杂性,而本质复杂性是解决问题所固有的,无法避免。使用 mixins 时考虑这两种类型的复杂性非常重要。

命名冲突和模糊的合并策略

Mixin 可能与组件具有重叠的属性,从而导致命名冲突和意外行为。

比如说我们有一个包含特定员工逻辑的mixin,其中包括声明增值税金额。

// mixins/employee.js
export default {
  data() {
    return {
      vat: 20
    };
  },
  computed: {
    calculateSalary() {
      return this.baseSalary - (this.baseSalary * this.vat) / 100;
    }
  }
};

以及还声明了增值税金额的薪资显示组件:

<template>
  <div id="app">工资: {{ calculateSalary }}div>
template>

<script>
import employee from "./mixins/employee.js";

export default {
  name: "App",
  mixins: [employee],
  data() {
    return {
      baseSalary: 100000,
      vat: 30,
    };
  },
};
script>

在这种情况下,计算函数里声明的增值税金额(vat)将被忽略,并且在具有更复杂逻辑的现实示例中,这很难发现,并且如果我们对 mixin 进行隔离单元测试,可能会得到误报。

当两个不同 mixins 之间的命名冲突时,这可能会更加令人困惑。在这种情况下,最后声明的一个会覆盖另一个!

可重用性降低

Mixins 使得重用组件变得更加困难,因为它们增加了组件的依赖性并使其与特定功能的耦合更加紧密。

例如,想象一个使用 mixin 的组件,该 mixin 为该组件提供了特定的样式。如果另一个组件也想使用相同的样式,则它必须使用相同的 mixin。这意味着组件的样式与现在的 mixin 紧密耦合,并且如果不使用 mixin 则无法重用。

这使得组件的可重用性降低,因为如果不包含 mixin 及其依赖项,它就无法在应用程序的其他部分中使用。这可能会导致代码重复并使应用程序更难以维护。

解决方案

组合式api

组合式api 是 Vue 3 的亮点。主要优点是以可组合函数的形式实现干净、高效的逻辑重用。它解决了 mixin 的缺点。社区里有非常多使用该方式的项目,例如VueUse。此外,它还是一种干净的机制,可以轻松地将有状态的第三方服务或库集成到 Vue 的响应性系统中,例如不可变数据、状态机和RxJS。

前面提到了使用 mixin 会创建高度耦合且难以扩展或维护的代码:

为什么 Mixin 被认为是有害的_第1张图片
另一种方法是让每个组件显式导入其所有依赖项。这样,一切都是透明的并且易于推理。设计上消除了命名冲突,并且测试也更加简单。

为什么 Mixin 被认为是有害的_第2张图片
实际上,Composition API 是一组实用帮助程序,使我们能够使用显式导入的函数而不是声明选项来编写组件。它是一个涵盖以下 API 的总称:

  • Reactivity API(响应式api):例如ref()reactive(),它允许我们直接创建反应状态、计算状态和观察者。
  • Lifecycle Hooks(生命周期钩子):例如onMounted()onUnmounted(),它允许我们以编程方式挂钩到组件生命周期。
  • 依赖注入,即provide()inject(),它允许我们在使用 Reactivity API 时利用 Vue 的依赖注入系统。

简单示例:

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

export function useMouse() {
  const x = ref(0)
  const y = ref(0)
  function update(event) {
    x.value = event.pageX
    y.value = event.pageY
  }
  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  return { x, y }
}
<script setup>
import { useMouse } from './mouse.js'

const { x, y } = useMouse()
script>

<template>鼠标位置: {{ x }}, {{ y }}template>

你可能感兴趣的:(vue,vue.js,前端,javascript)