首页 > web前端 > js教程 > 您需要了解的 Vue 可组合技巧

您需要了解的 Vue 可组合技巧

Susan Sarandon
发布: 2025-01-11 08:46:44
原创
580 人浏览过

Vue Composables Tips You Need to Know

Vue 可组合项非常强大,但如果您不小心,它们很快就会变得混乱且难以维护。

这就是为什么我确定了 13 个技巧,可以帮助您编写更好、更易于维护的可组合项。

无论您是构建简单的状态管理解决方案还是复杂的共享逻辑,这些技巧都将为您提供帮助:

  • 避免导致意大利面条式代码的常见陷阱
  • 编写更易于测试和维护的可组合项
  • 创建更灵活、可重用的共享逻辑
  • 如果需要,请逐渐从 Options API 迁移到 Composition API

您将学到的技巧是:

  1. 避免通过多个组件进行 Prop 钻孔
  2. 在不相关的组件之间共享数据
  3. 用清晰的方法控制状态更新
  4. 将大组件分解为更小的函数
  5. 将业务逻辑与 Vue 反应性分开
  6. 在一个函数中处理同步和异步数据
  7. 使函数参数更具描述性
  8. 防止使用默认值的未定义选项
  9. 根据需要返回简单或复杂的值
  10. 将不同的逻辑路径分成各自的函数
  11. 一致地处理反应值和原始值
  12. 简化引用展开
  13. 逐步从Options API迁移到Composition API

让我们深入研究每种模式,看看它们如何改进您的 Vue 应用程序。

别忘了,在下面评论你最喜欢的提示!

1. 避免通过多个组件进行支柱钻孔

数据存储模式可以帮助避免通过多个组件层传递道具和事件。

一种情况是父母和孩子通过无休止的道具钻探和事件冒泡进行交流:

<!-- Parent.vue -->
<template>
  <!-- But many more layers of components -->
  <Child :user="user" @change="onUserChange" />
</template>

<script setup>
const user = ref({ name: 'Alice' })
function onUserChange(updatedUser) {
  user.value = updatedUser
}
</script>
登录后复制
登录后复制
登录后复制

这会造成很大的复杂性,因为这些道具和事件必须在组件层次结构中来回移动。

更简单的解决方案是创建一个任何组件都可以导入的共享数据存储:

import { reactive, toRefs } from 'vue'
const state = reactive({ user: { name: 'Alice' } })

export function useUserStore() {
  return toRefs(state)
}
登录后复制
登录后复制
登录后复制

2. 在不相关的组件之间共享数据

当兄弟或“表兄弟”组件需要在没有任何直接连接的情况下共享相同的数据时,数据存储模式也会有所帮助。

假设两个兄弟姐妹都需要相同的用户对象,但没有优雅的道具或事件路径。

这通常会导致在父状态或重复状态之间进行尴尬的数据处理。

更好的方法是依赖一个兄弟姐妹都可以使用的可组合存储:

// SiblingA.vue
import { useUserStore } from './useUserStore'
const { user } = useUserStore()

// SiblingB.vue
import { useUserStore } from './useUserStore'
const { user } = useUserStore()
登录后复制
登录后复制
登录后复制

3. 使用清晰的方法控制状态更新

数据存储模式鼓励提供清晰的方法来更新共享状态。

一些开发人员将整个反应式对象暴露给世界,如下所示:

<!-- Parent.vue -->
<template>
  <!-- But many more layers of components -->
  <Child :user="user" @change="onUserChange" />
</template>

<script setup>
const user = ref({ name: 'Alice' })
function onUserChange(updatedUser) {
  user.value = updatedUser
}
</script>
登录后复制
登录后复制
登录后复制

这使得任何人都可以直接从任何文件更改用户的 darkMode 属性,这可能会导致分散的、不受控制的突变。

更好的想法是将状态返回为只读以及定义更新如何发生的函数:

import { reactive, toRefs } from 'vue'
const state = reactive({ user: { name: 'Alice' } })

export function useUserStore() {
  return toRefs(state)
}
登录后复制
登录后复制
登录后复制

4. 将大型组件分解为更小的功能

内联可组合模式通过将相关状态和逻辑收集到更小的函数中来帮助分解大型组件。

一个巨大的组件可能会将其所有引用和方法放在一个地方:

// SiblingA.vue
import { useUserStore } from './useUserStore'
const { user } = useUserStore()

// SiblingB.vue
import { useUserStore } from './useUserStore'
const { user } = useUserStore()
登录后复制
登录后复制
登录后复制

这种设置很快就会变得难以管理。

相反,内联可组合项可以对逻辑进行分组并在本地提供。然后我们可以稍后将其提取到一个单独的文件中:

export const user = reactive({ darkMode: false })
登录后复制
登录后复制

5. 将业务逻辑与 Vue 反应性分开

精简可组合模式告诉我们将原始业务逻辑与 Vue 反应性分开,以便测试和维护变得更简单。

您可以将所有逻辑嵌入可组合项中:

import { reactive, readonly } from 'vue'
const state = reactive({ darkMode: false })

export function toggleDarkMode() {
  state.darkMode = !state.darkMode
}

export function useUserStore() {
  return {
    darkMode: readonly(state.darkMode),
    toggleDarkMode
  }
}
登录后复制
登录后复制

这迫使您在 Vue 环境中测试逻辑。

相反,将复杂的规则保留在纯函数中,并让可组合项仅处理反应式包装器:

<script setup>
const count = ref(0)
const user = ref({ name: 'Alice' })
// 500 more lines of intertwined code with watchers, methods, etc.
</script>
登录后复制
登录后复制

6. 在一个函数中处理同步和异步数据

异步同步可组合模式将同步和异步行为合并到一个可组合中,而不是创建单独的函数。

这就像 Nuxt 的 useAsyncData 的工作原理一样。

这里我们有一个可组合项,它可以返回承诺,同时还为同步使用提供即时反应属性:

<script setup>
function useCounter() {
  const count = ref(0)
  const increment = () => count.value++
  return { count, increment }
}

const { count, increment } = useCounter()
</script>
登录后复制
登录后复制

7. 让函数参数更具描述性

选项对象模式可以通过期望单个配置对象来清除长参数列表。

这样的调用比较麻烦而且容易出错,添加新选项需要更新函数签名:

export function useCounter() {
  const count = ref(0)
  function increment() {
    count.value = (count.value * 3) / 2
  }
  return { count, increment }
}
登录后复制
登录后复制

每个参数代表什么并不明显。

接受选项对象的可组合项使所有内容保持描述性:

// counterLogic.js
export function incrementCount(num) {
  return (num * 3) / 2
}

// useCounter.js
import { ref } from 'vue'
import { incrementCount } from './counterLogic'

export function useCounter() {
  const count = ref(0)
  function increment() {
    count.value = incrementCount(count.value)
  }
  return { count, increment }
}
登录后复制
登录后复制

8. 防止使用默认值的未定义选项

选项对象模式还建议每个属性的默认值。

假设某些字段存在的函数如果未传递,可能会出现问题:

import { ref } from 'vue'

export function useAsyncOrSync() {
  const data = ref(null)
  const promise = fetch('/api')
    .then(res => res.json())
    .then(json => {
      data.value = json
      return { data }
    })
  return Object.assign(promise, { data })
}
登录后复制
登录后复制

最好使用安全默认值解构选项:

useRefHistory(someRef, true, 10, 500, 'click', false)
登录后复制

9. 根据需要返回简单或复杂的值

动态返回模式确保可组合项可以返回简单用例的单个值或具有更高级控件的扩展对象。

一些方法总是返回一个包含所有内容的对象:

<!-- Parent.vue -->
<template>
  <!-- But many more layers of components -->
  <Child :user="user" @change="onUserChange" />
</template>

<script setup>
const user = ref({ name: 'Alice' })
function onUserChange(updatedUser) {
  user.value = updatedUser
}
</script>
登录后复制
登录后复制
登录后复制

任何只需要主要无功值的人都被迫处理额外的东西。

有条件返回单个引用或对象的可组合项解决了:

import { reactive, toRefs } from 'vue'
const state = reactive({ user: { name: 'Alice' } })

export function useUserStore() {
  return toRefs(state)
}
登录后复制
登录后复制
登录后复制

10.将不同的逻辑路径分成各自的功能

隐藏可组合项模式有助于避免在同一可组合项中混合互斥逻辑。

一些代码将多种模式或代码路径组合在一起:

// SiblingA.vue
import { useUserStore } from './useUserStore'
const { user } = useUserStore()

// SiblingB.vue
import { useUserStore } from './useUserStore'
const { user } = useUserStore()
登录后复制
登录后复制
登录后复制

将每个路径拆分为自己的可组合项更加清晰,并且不会影响功能:

export const user = reactive({ darkMode: false })
登录后复制
登录后复制

11. 一致地处理反应值和原始值

灵活参数模式确保可组合项中的输入和输出被统一处理为反应数据或原始值,避免混淆。

一些代码检查输入是否是引用:

import { reactive, readonly } from 'vue'
const state = reactive({ darkMode: false })

export function toggleDarkMode() {
  state.darkMode = !state.darkMode
}

export function useUserStore() {
  return {
    darkMode: readonly(state.darkMode),
    toggleDarkMode
  }
}
登录后复制
登录后复制

相反,您可以立即转换。

通过使用 ref,如果输入是 ref,则将返回该 ref。否则,它将被转换为 ref:

<script setup>
const count = ref(0)
const user = ref({ name: 'Alice' })
// 500 more lines of intertwined code with watchers, methods, etc.
</script>
登录后复制
登录后复制

12. 简化引用展开

当需要展开时,灵活参数模式也会使用 toValue。

没有它,代码可能会继续执行 isRef 检查:

<script setup>
function useCounter() {
  const count = ref(0)
  const increment = () => count.value++
  return { count, increment }
}

const { count, increment } = useCounter()
</script>
登录后复制
登录后复制

调用更简单:

export function useCounter() {
  const count = ref(0)
  function increment() {
    count.value = (count.value * 3) / 2
  }
  return { count, increment }
}
登录后复制
登录后复制

13. 逐步从Options API迁移到Composition API

Options to Composition 模式可让您以易于遵循的增量方式逐步将大型 Options API 组件迁移到 Composition API。

经典的选项组件可能会这样做:

// counterLogic.js
export function incrementCount(num) {
  return (num * 3) / 2
}

// useCounter.js
import { ref } from 'vue'
import { incrementCount } from './counterLogic'

export function useCounter() {
  const count = ref(0)
  function increment() {
    count.value = incrementCount(count.value)
  }
  return { count, increment }
}
登录后复制
登录后复制

数据、计算属性和方法是分散的。

将其转换为脚本设置将它们组合在一起,使其更易于遵循,并允许您使用这些模式:

import { ref } from 'vue'

export function useAsyncOrSync() {
  const data = ref(null)
  const promise = fetch('/api')
    .then(res => res.json())
    .then(json => {
      data.value = json
      return { data }
    })
  return Object.assign(promise, { data })
}
登录后复制
登录后复制

把它包起来

这 13 个技巧将帮助您编写更好的 Vue 可组合项,更容易在应用程序中维护、测试和重用。

但我们只是触及了表面。

多年来,我收集了更多模式和技巧,并将它们全部放入可组合模式的深入课程中。

总共涵盖16种图案,每种图案有:

  • 深入解释 — 何时使用它、边缘情况和变体
  • 现实世界的示例 - 这样您就可以了解如何使用这些简单示例之外的它们
  • 分步重构示例 — 这样您就可以了解如何将它们应用到您自己的代码中

到这里了解更多。

哦,这门课程优惠至 1 月 15 日,所以您现在就可以享受超值折扣!

查看可组合设计模式

以上是您需要了解的 Vue 可组合技巧的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板