为什么说组合式函数是 Vue3 中最棒的特性之一 ?

7,061次阅读
没有评论

共计 4361 个字符,预计需要花费 11 分钟才能阅读完成。

微信截图_20230927172059

为什么说组合式函数是 Vue3 中最棒的特性之一 ? 

组合式函数 (Composition API) 是 Vue3 中引入的一个重要特性, 它可以说是 Vue3 中最棒的特性之一, 主要有以下几个原因:

  1. 更好的代码组织

组合式函数让组件逻辑可以通过组合多个小的单元函数来组织, 每个函数负责一个具体的功能。这种函数式的编程范式可以让代码更加清晰易懂。

  1. 更好的代码复用

组合函数可以很容易地在多个组件中复用, 使得开发者可以抽象出通用的业务逻辑作为可复用的逻辑单元。这避免了同样逻辑代码的重复。

  1. 更好的类型推导

通过 TypeScript 的类型系统, 组合函数可以提供更准确的代码提示, 提高开发效率。

  1. 更好的逻辑抽象

组合函数让组件只需要关注自身的 UI 展示, 通过组合函数将逻辑抽象成可重用的代码, 使组件代码更加清晰和聚合。

  1. 更好的面向切面编程

组合函数天然适合面向切面编程, 可以更方便地处理一些与组件逻辑无关的横切关注点, 如日志、缓存等。

  1. 更好的逻辑复用和代码组织

总之, 组合式函数为 Vue 带来了函数式编程的思想, 可以帮助开发者写出更优雅的代码, 是 Vue3 相比 Vue2 最大的进步之一。它让 Vue 的编程体验更接近 React Hooks。

什么是“组合式函数”?

在 Vue 应用的概念中,“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数。

当构建前端应用时,我们常常需要复用公共任务的逻辑。例如为了在不同地方格式化时间,我们可能会抽取一个可复用的日期格式化函数。这个函数封装了无状态的逻辑:它在接收一些输入后立刻返回所期望的输出。复用无状态逻辑的库有很多,比如你可能已经用过的 lodash 或是 date-fns

相比之下,有状态逻辑负责管理会随时间而变化的状态。一个简单的例子是跟踪当前鼠标在页面中的位置。在实际应用中,也可能是像触摸手势或与数据库的连接状态这样的更复杂的逻辑。

鼠标跟踪器示例

如果我们要直接在组件中使用组合式 API 实现鼠标跟踪功能,它会是这样的:



但是,如果我们想在多个组件中复用这个相同的逻辑呢?我们可以把这个逻辑以一个组合式函数的形式提取到外部文件中:

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

// 按照惯例,组合式函数名以“use”开头
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}
}

下面是它在组件中使用的方式:



如你所见,核心逻辑完全一致,我们做的只是把它移到一个外部函数中去,并返回需要暴露的状态。和在组件中一样,你也可以在组合式函数中使用所有的 组合式 API。现在,useMouse() 的功能可以在任何组件中轻易复用了。

更酷的是,你还可以嵌套多个组合式函数:一个组合式函数可以调用一个或多个其他的组合式函数。这使得我们可以像使用多个组件组合成整个应用一样,用多个较小且逻辑独立的单元来组合形成复杂的逻辑。实际上,这正是为什么我们决定将实现了这一设计模式的 API 集合命名为组合式 API。

举例来说,我们可以将添加和清除 DOM 事件监听器的逻辑也封装进一个组合式函数中:

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

export function useEventListener(target, event, callback) {
  // 如果你想的话,// 也可以用字符串形式的 CSS 选择器来寻找目标 DOM 元素
  onMounted(() => target.addEventListener(event, callback))
  onUnmounted(() => target.removeEventListener(event, callback))
}

有了它,之前的 useMouse() 组合式函数可以被简化为:

// mouse.js
import {ref} from 'vue'
import {useEventListener} from './event'

export function useMouse() {const x = ref(0)
  const y = ref(0)

  useEventListener(window, 'mousemove', (event) => {
    x.value = event.pageX
    y.value = event.pageY
  })

  return {x, y}
}

每一个调用 useMouse() 的组件实例会创建其独有的 x、y 状态拷贝,因此他们不会互相影响。如果你想要在组件之间共享状态,请阅读 状态管理 这一章。

异步状态示例

useMouse() 组合式函数没有接收任何参数,因此让我们再来看一个需要接收一个参数的组合式函数示例。在做异步数据请求时,我们常常需要处理不同的状态:加载中、加载成功和加载失败。



如果在每个需要获取数据的组件中都要重复这种模式,那就太繁琐了。让我们把它抽取成一个组合式函数:

// fetch.js
import {ref} from 'vue'

export function useFetch(url) {const data = ref(null)
  const error = ref(null)

  fetch(url)
    .then((res) => res.json())
    .then((json) => (data.value = json))
    .catch((err) => (error.value = err))

  return {data, error}
}

现在我们在组件里只需要:

接收响应式状态

useFetch() 接收一个静态 URL 字符串作为输入——因此它只会执行一次 fetch 并且就此结束。如果我们想要在 URL 改变时重新 fetch 呢?为了实现这一点,我们需要将响应式状态传入组合式函数,并让它基于传入的状态来创建执行操作的侦听器。

举例来说,useFetch() 应该能够接收一个 ref:

const url = ref('/initial-url')

const {data, error} = useFetch(url)

// 这将会重新触发 fetch
url.value = '/new-url'

或者接收一个 getter 函数:

// 当 props.id 改变时重新 fetch
const {data, error} = useFetch(() => `/posts/${props.id}`)

我们可以用 watchEffect() 和 toValue() API 来重构我们现有的实现:

// fetch.js
import {ref, watchEffect, toValue} from 'vue'

export function useFetch(url) {const data = ref(null)
  const error = ref(null)

  watchEffect(() => {
    // 在 fetch 之前重置状态
    data.value = null
    error.value = null
    // toValue() 将可能的 ref 或 getter 解包
    fetch(toValue(url))
      .then((res) => res.json())
      .then((json) => (data.value = json))
      .catch((err) => (error.value = err))
  })

  return {data, error}
}

toValue() 是一个在 3.3 版本中新增的 API。它的设计目的是将 ref 或 getter 规范化为值。如果参数是 ref,它会返回 ref 的值;如果参数是函数,它会调用函数并返回其返回值。否则,它会原样返回参数。它的工作方式类似于 unref(),但对函数有特殊处理。

注意 toValue(url) 是在 watchEffect 回调函数的内部调用的。这确保了在 toValue() 规范化期间访问的任何响应式依赖项都会被侦听器跟踪。

这个版本的 useFetch() 现在能接收静态 URL 字符串、ref 和 getter,使其更加灵活。watch effect 会立即运行,并且会跟踪 toValue(url) 期间访问的任何依赖项。如果没有跟踪到依赖项(例如 url 已经是字符串),则 effect 只会运行一次;否则,它将在跟踪到的任何依赖项更改时重新运行。

这是 更新后的 useFetch(),为了便于演示,添加了人为延迟和随机错误。

想要了解更多关于 Vue3 组合式函数的用法, 请点击 《Vue3 组合式函数》

原文地址: 为什么说组合式函数是 Vue3 中最棒的特性之一 ?

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-09-20发表,共计4361字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)