vue 3.0新特性之reactive与ref

2023-11-12

vue 3.0新特性

参考:  https://www.cnblogs.com/Highdoudou/p/9993870.html

https://www.cnblogs.com/ljx20180807/p/9987822.html

性能优化

  • 观察者机制的变化:Proxy 替代 object.defineProperty  

    •  Vue 2.x使用 Object.defineProperty 的 getter 和 setter。 但是,Vue 3 将使用 ES2015 Proxy 作为其观察者机制。 这消除了以前存在的警告,使速度加倍,并节省了一半的内存开销。
  • virtual DOM重构(比2.5快一倍) 【和模版大小有关 --> 和模版内的动态内容数量相关】

    1.   传统:组件 update时,整个vdom树需要重新创建,然后遍历进行diff, update

    2.   新的更新策略: block tree

      1.  区分动态节点和静态节点

      2.  基于动态节点指令(v-if, v-for,  {{ name }}等)更新

  • 编译时优化

  1. slot默认编译为函数

  2. vnode的创建函数保持参数一致化

  3. 编译时生成vnode的类型标记

新增composition-api,

https://composition-api.vuejs.org/

可以在vue2.x的项目中通过安装@vue/composition-api包来使用composition-api.

  • reactive:reactive的作用是将对象包装成响应式对象——通过 Proxy代理后的对象。
  • ref:由传入值返回一个响应式的、可变的且只有value一个属性的ref对象。

  当ref被作为render context被返回,在template中使用该ref对象时,自动获取内部的值,不需要使用.value属性。

复制代码

<template>
  <div>{{ count }}</div>
</template>

<script>
  export default {
    setup() {
      return {
        count: ref(0)
      }
    }
  }
</script>

复制代码

  当ref对象被作为属性,传入响应式对象reactive时,会自动获取其内部的值(表现得像普通的属性值,而非对象)。

复制代码

const count = ref(0)
const state = reactive({
  count
})

console.log(state.count) // 0

state.count = 1
console.log(count.value) // 1

复制代码

  reactive属性绑定新的ref对象后,原来ref的value不变(断开了)。

const otherCount = ref(2)

state.count = otherCount
console.log(state.count) // 2
console.log(count.value) // 1

  其他情况获取ref时需要带.value

复制代码

const arr = reactive([ref(0)])
// need .value here
console.log(arr[0].value)

const map = reactive(new Map([['foo', ref(0)]]))
// need .value here
console.log(map.get('foo').value)

复制代码

    •   reactive对象与ref对象的区别

    可以通过如何撰写标准的 JavaScript 逻辑来比较:

复制代码

// 风格 1: 将变量分离
let x = 0
let y = 0

function updatePosition(e) {
  x = e.pageX
  y = e.pageY
}


// 风格 2: 单个对象
const pos = {
  x: 0,
  y: 0,
}

function updatePosition(e) {
  pos.x = e.pageX
  pos.y = e.pageY
}

复制代码

  • 可以将风格 (1) 转换为使用 ref写法 (为了让基础类型值具有响应性) 。

  • 将风格 (2) 转换为使用 reactive 对象的写法。

      如果只使用 reactive 的问题是,使用组合函数时必须始终保持对这个所返回对象的引用以保持响应性。这个对象不能被解构或展开

复制代码

// 组合函数:
function useMousePosition() {
  const pos = reactive({
    x: 0,
    y: 0,
  })

  // ...
  return pos
}

// 消费组件
export default {
  setup() {
    // 这里会丢失响应性!
    const { x, y } = useMousePosition()
    return {
      x,
      y,
    }

    // 这里会丢失响应性!
    return {
      ...useMousePosition(),
    }

    // 这是保持响应性的唯一办法!
    // 你必须返回 `pos` 本身,并按 `pos.x` 和 `pos.y` 的方式在模板中引用 x 和 y。
    return {
      pos: useMousePosition(),
    }
  },
}

复制代码

toRefs API 用来提供解决此约束的办法——它将响应式对象的每个 property 都转成了相应的 ref。

复制代码

function useMousePosition() {
  const pos = reactive({
    x: 0,
    y: 0,
  })

  // ...
  return toRefs(pos)
}

// x & y 现在是 ref 形式,可以i解构了!
const { x, y } = useMousePosition()

复制代码

 

  • computed:传入一个getter()函数,返回一个值不可变的响应式ref对象。
const count = ref(1)
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2  count值改变,plusOne的值相应的改变

plusOne.value++ // error

  当传入的是一个具有get和set函数的对象时,返回的是一个可写的ref对象。

复制代码

const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: val => {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) // 0   count值改变,plusOne的值随之改变;改变plusOne的值, count的值也相应的改变

复制代码

  • readonly:将接受到的对象(无论是响应式对象、ref对象或普通对象),转成通过Proxy代理的只读对象。

复制代码

const original = reactive({ count: 0 })

const copy = readonly(original)

watchEffect(() => {
  // works for reactivity tracking
  console.log(copy.count)
})

// mutating original will trigger watchers relying on the copy
original.count++

// mutating the copy will fail and result in a warning
copy.count++ // warning!

复制代码

  • watchEffect:接受一个函数,当依赖改变时,重新调用该函数。

复制代码

const count = ref(0)

watchEffect(() => console.log(count.value))

setTimeout(() => {
  count.value++
}, 100)

复制代码

  当watchEffect()在setup()或生命周期钩子中被调用时,监听就始终存在该组件的生命周期中,直到组件unmount.

  另一种卸载监听的情况是,watchEffect()返回一个stop handler,调用该handler即可停止监听。

const stop = watchEffect(() => {
  /* ... */
})

// later
stop()

  当向后台获取数据时,watchEffect()接受async回调函数。

const data = ref(null)
watchEffect(async () => {
  data.value = await fetchData(props.id)
})

  组件的update函数也有watch effect。用户定义的watchEffect会在组件update之后再去调用。

复制代码

<template>
  <div>{{ count }}</div>
</template>

<script>
  export default {
    setup() {
      const count = ref(0)

      watchEffect(() => {
        console.log(count.value)
      })

      return {
        count
      }
    }
  }
</script>

复制代码

上述代码,第一轮会同步打印count.value(在onmount生命周期前); 当count发生改变时,先执行组件更新,然后再去log.

  如果想将watchEffect中的回调函数第一次执行,放在onmount后,

onMounted(() => {
  watchEffect(() => {
    // access the DOM or template refs
  })
})

  如果想让watchEffect()调用发生在组件update前,或re-run同步,需要传递一个带有flush属性(默认值为post)的option对象。

watchEffect(()=> {
//...
}, {
 flush: 'sync'  // 在更新前触发 flush: "pre"
})

此外,option对象还有ontrack和ontrigger两个函数属性,用于调试watcher的行为。

  • onTrack will be called when a reactive property or ref is tracked as a dependency
  • onTrigger will be called when the watcher callback is triggered by the mutation of a dependency

复制代码

watchEffect(
  () => {
    /* side effect */
  },
  {
    onTrigger(e) {
      debugger   // 进行交互式调试
    }
  }
)

复制代码

  • watch:等价于vue 2.x中的this.$watch.

相比于watchEffect(), watch()可帮我们实现:

  1. Perform the side effect lazily;
  2. Be more specific about what state should trigger the watcher to re-run;
  3. Access both the previous and current value of the watched state.

  watch()的数据源可以是一个返回值的getter函数,或者是一个ref对象。

复制代码

// watching a getter
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)

// directly watching a ref
const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})

复制代码

  对于多数据源的监听,可借助数组。

watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  /* ... */
})

 生命周期api调整

复制代码

<template>
  <div>{{count}} {{obj.foo}}</div>
</template>
<script>
import { ref, reactive, watchEffect } from '@vue/composition-api'
export default {
  props: {
    name: String
  },
  setup (props) {
    const count = ref(0)
    const obj = reactive({ foo: 'abc' })
    watchEffect(() => {
      console.log(props.name)
    })
    return {
      count,
      obj
    }
  }
}
</script>

复制代码

setup()接受的第一个参数是props。props是响应式的。注意:传参时不能对其解构。上面的代码将props传入setup()后,并通过watchEffect()进行监听。

setup()还可接受第二个参数context(相当于vue2.x中的this, setup()不允许使用this),context作为参数时,可以进行解构。常用的有:

context.attrs, context.slots, context.emit

setup(props, {attrs}) {
    function onClick() {
      console.log(attrs.foo) // 可以保证是最新的值
    }
 }

其他生命周期函数可以在setup()中被同步注册。当同步执行生命周期hooks时,组件实例的renderContext,watcher和computed properties也同步建立。当组件卸载时,内部的生命周期hooks也会同步去掉。

复制代码

setup() {
    onMounted(() => {
      console.log('mounted!')
    })
    onUpdated(() => {
      console.log('updated!')
    })
    onUnmounted(() => {
      console.log('unmounted!')
    })
  }

复制代码

  1. <template>和之前一样,同样 vue-next也支持手写 render的写法。 template和 render同时存在的情况,优先 render。
  2. setup()是新增的主要变动。顾名思义, setup函数会在组件挂载前运行一次,类似组件初始化的作用, setup需要返回一个对象或者函数。返回对象会被赋值给组件实例的 renderContext,在组件的模板作用域可以被访问到,类似 data的返回值。返回函数会被当做是组件的 render。

基于逻辑关注点组织代码

在vue 2.x中,使用的是option api,要完成一个函数所用到的data或computed计算属性距离这个函数的定义可能有很多行(代码是分散的),这种碎片化使得代码维护变得困难。

这一问题在composition api中得到了解决。每个逻辑关注点的代码现在都被组合进了一个组合函数(命名以use开头)。这大大减少了在处理大型组件时不断“跳转”的需要。同时组合函数也可以在编辑器中折叠起来,使组件更容易浏览。

复制代码

  setup() {
    // ...
  },
}

function useCurrentFolderData(networkState) {
  // ...
}

function useFolderNavigation({ networkState, currentFolderData }) {
  // ...
}

function useFavoriteFolder(currentFolderData) {
  // ...
}

function useHiddenFolders() {
  // ...
}

function useCreateFolder(openFolder) {
  // ...
}

复制代码

setup() 函数现在只是简单地作为调用所有组合函数的入口。最后的 return 语句作为单一出口确认暴露给模板的内容。

复制代码

export default {
  setup() {
    // 网络状态
    const { networkState } = useNetworkState()

    // 文件夹状态
    const { folders, currentFolderData } = useCurrentFolderData(networkState)
    const folderNavigation = useFolderNavigation({
      networkState,
      currentFolderData,
    })
    const { favoriteFolders, toggleFavorite } = useFavoriteFolders(
      currentFolderData
    )
    const { showHiddenFolders } = useHiddenFolders()
    const createFolder = useCreateFolder(folderNavigation.openFolder)

    // 当前工作目录
    resetCwdOnLeave()
    const { updateOnCwdChanged } = useCwdUtils()

    // 实用工具
    const { slicePath } = usePathUtils()

    return {
      networkState,
      folders,
      currentFolderData,
      folderNavigation,
      favoriteFolders,
      toggleFavorite,
      showHiddenFolders,
      createFolder,
      updateOnCwdChanged,
      slicePath,
    }
  },
}

复制代码

 

 

 

 逻辑提取和复用

一个组合函数仅依赖它的参数 Vue 全局导出的 API,而不是依赖 this 上下文。你可以将组件内的任何一段逻辑导出为函数以复用。

复制代码

import { ref, onMounted, onUnmounted } from 'vue'

export function useMousePosition() {
  const x = ref(0)
  const y = ref(0)
   // 提取为函数
  function update(e) {
    x.value = e.pageX
    y.value = e.pageY
  }

  onMounted(() => {
    window.addEventListener('mousemove', update)
  })

  onUnmounted(() => {
    window.removeEventListener('mousemove', update)
  })

  return { x, y }
}

复制代码

在一个组件中调用上述组合函数

复制代码

import { useMousePosition } from './mouse'

export default {
  setup() {
    const { x, y } = useMousePosition()
    // 其他逻辑...
    return { x, y }
  },
}

复制代码

与现有api配合

  • 组合式 API 会在 2.x 的选项 (datacomputed 和 methods) 之前解析,并且不能提前访问这些选项中定义的 property。

  • setup() 函数返回的 property 将会被暴露给 this。它们在 2.x 的选项中可以访问到。

 

vue3.0与react的比较:

    1. 同样的逻辑组合、复用能力

    2. composition api 的 setup() 只会调用一次,相比与react hooks

      • 符合js 直觉

      • 没有闭包变量问题

      • 不会在每次渲染时重复执行,降低垃圾回收的压力;

      • 不存在内联回调导致子组件永远更新的问题

      • 不存在忘记记录依赖的问题,也不需要“useEffect”和“useMemo”并传入依赖数组以捕获过时的变量。Vue 的自动依赖跟踪可以确保侦听器和计算值总是准确无误。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue 3.0新特性之reactive与ref 的相关文章

  • vue3+Element-plus el-select 下拉选择 多选增加全选封装组件(2023-09-20 TSelect组件新增自定义显示下拉项label)

    2023 09 20 TSelect组件新增自定义显示下拉项label 一 效果图 含适用于条件查询组件中使用 二 参数配置 1 代码示例
  • vue3 父子组件传参详解

    前言 我引用了大佬的文章 但我实在找不到网址链接了 我记录在笔记上的 如果大佬看见了 麻烦给我说一下 我注明一下出处 建议先看son vue 里面写了那三种方式 首先放一个我的demo defineProps什么的父子传参api不用引入 直
  • Vue3-wangeditor富文本编辑器的使用

    wangeditor官网 用于 Vue React wangEditor开源 Web 富文本编辑器 开箱即用 配置简单https www wangeditor com v5 for frame html vue3 按照官网提示安装 两个都要
  • vue3 + vite 在线预览docx, pdf, pptx(内外网)并实现移动端适配

    一 内网 1 docx 使用docx preview 安装插件 npm i docx preview S 引入依赖 docx import renderAsync from docx preview let docx import meta
  • vue3的一些知识点plus--3

    二十 兄弟组件传值 Bus 兄弟组件直接的传值 最基础的是通过同一个父级进行数值的传递 使用prop和emit 太过繁琐 父级 div a a b b div let flag ref false let getFlag params bo
  • vue3快速入门-Teleport传送(瞬移组件)

    Vue 的组件架构使我们能够将用户界面构建为能够精美地组织业务逻辑和表示层的组件 Teleporting是Vue 3发布带来的一项新功能 它的灵感来自React Portals 相同的门户是 React 中的一个常见功能 在 Vue2 的
  • vue3 的 ref、 toRef 、 toRefs

    1 ref 对原始数据进行拷贝 当修改 ref 响应式数据的时候 模版中引用 ref 响应式数据的视图处会发生改变 但原始数据不会发生改变
  • uni-app微信小程序开发自定义select下拉多选内容篇

    欢迎点击领取 前端面试题进阶指南 前端登顶之巅 最全面的前端知识点梳理总结 分享一个使用比较久的 技术框架公司的选型 uni app uni ui vue3 vite4 ts 需求分析 微信小程序 uni ui内容 1 创建一个自定义的下拉
  • vue3的provide

    provide 和 inject 通常成对一起使用 使一个祖先组件作为其后代组件的依赖注入方 无论这个组件的层级有多深都可以注入成功 只要他们处于同一条组件链上 provide 提供一个值 可以被后代组件注入 inject 注入一个由祖先组
  • vue3知识点:setup

    文章目录 二 常用 Composition API 1 拉开序幕的setup setup的两个注意点 本人其他相关文章链接 二 常用 Composition API 问题 啥叫 组合式API 答案 请看官方文档 https v3 cn vu
  • vue3+ts深入组件(四)动态组件

    一 引入 掌握程度 了解 使用Vue时 有时会遇到tab切换 如下图 1 可实现方法 1 v if 2 component动态组件 3 使用vue Router 路由切换 2 对比 第一种方法 v if 这可能是我们能最快想到的解决办法 但
  • vue3(二)配置标题和服务代理

    这里的标题如何改成自己的标题 第一步 修改vue config js transpileDependencies true chainWebpack config gt config plugin html tap args gt args
  • electron-vue2 项目初始化

    不要使用网上或者 github 的模板初始化项目 直接上代码 安装 vuecli 脚手架 npm update vue cli 初始化 project name 项目 vue create project name 进入项目 cd proj
  • Vue实例挂载的过程

    一 思考与分析 我们都听过知其然知其所以然这句话 那么不知道是否思考过new Vue 这个过程中究竟做了些什么 过程中是如何完成数据的绑定 又是如何将数据渲染到视图的等等 首先找到vue的构造函数 源码位置 src core instanc
  • vue3+ts实现todolist功能

    先看一下实现效果 可以看到内部实现的内容有enter输入 单项删除 全选 以及删除选中项等功能 具体在实现前需要常见有ts的vue3项目 项目创建 具体项目创建 就是 vue create 项目名称 在创建后 选择的时候有vue2和vue3
  • vant4 自定义垂直步骤条时间线组件几行css代码改造完成(附效果图)

    直接上效果图片
  • vue3 新特性

    注册全局组件 import HelloWorld from components HelloWorld vue const app createApp App 全局挂载属性和方法 方法一 app config globalPropertie
  • Vue3状态管理库Pinia——核心概念(Store、State、Getter、Action)

    个人简介 个人主页 前端杂货铺 学习方向 主攻前端方向 正逐渐往全干发展 个人状态 研发工程师 现效力于中国工业软件事业 人生格言 积跬步至千里 积小流成江海 推荐学习 前端面试宝典 Vue2 Vue3 Vue2 3项目实战 Node js
  • vue项目中批量删除如何实现的

    简单回答 与单个删除的接口为同一个 然后通过数组对象的id来删除
  • element中表格组件的row-class-name和class-name属性的使用以及无效处理

    1 这两个属性的使用 row class name用在el table标签上 class name用在el table column标签上 两个属性即可绑定类名也可绑定函数

随机推荐

  • Fedora的启动方式(命令行启动)

    Linux有6种不同的运行级别 默认的情况下Fedora安装完成后是从X Window启动的 X Window占用系统资源很大 所以对于我们仅仅想使用命令行模式的人来说 界面那么大 耗费资源太多有些浪费 那如何让Fedora从命令行启动而不
  • 卷麻了,00后测试用例写的比我还好,简直无地自容......

    经常看到无论是刚入职场的新人 还是工作了一段时间的老人 都会对编写测试用例感到困扰 例如 如何编写测试用例 作为一个测试新人 刚开始接触测试 对于怎么写测试用例很是头疼 无法接触需求 只能站在用户角度去做测试 但是这样情况会导致不能全方位测
  • parallel scavenge 与parnew 区别:

    Parallel Scavenge收集器是一个新生代收集器 它也是使用复制算法的收集器 又是并行的多线程收集器 看上去和ParNew都一样 那它有什么特别之处呢 Parallel Scavenge收集器的特点是它的关注点与其他收集器不同 C
  • 一款盲盒的交友软件叫什么(微信恋爱脱单交友盲盒小程序制作开发介绍)

    盲盒的交友软件一般叫做叫 盲盒脱单神器 月老交友盲盒或者是叫做一元交友等名称都是运营商自己随便起的 微信恋爱脱单交友盲盒小程序 一般情况是以H5网页的形式进行使用 做成微信小程序的形式需要相关资质 主要功能有 幻灯片 放入盒子 随机匹配 星
  • git clone指定分支拉代码、版本回退、log/reflog对比

    指定分支clone代码 1 git clone 不指定分支 默认就是master git clone http 10 1 1 11 service tmall service git 2 git clone 指定分支 git clone b
  • 【2022/2023年硕士研究生408计算机学科考试大纲原文】+【2009-2021年408统考真题+解析PDF】

    文章目录 2009 2021年408统考真题 解析 PDF版 I 考试性质 II 考查目标 III 试形式和试卷结构 一 试卷满分及考试时间 二 答题方式 三 试卷内容结构 四 试卷题型结构 IV 考查内容 数据结构 一 线性表 二 栈 队
  • CAS 5.3自定义 登录

    自定义认证校验策略 我们知道CAS为我们提供了多种认证数据源 我们可以选择JDBC File JSON等多种方式 但是如果我想在自己的认证方式中可以根据提交的信息实现不同数据源选择 这种方式就需要我们去实现自定义认证 自定义策略主要通过现实
  • 网页中插入图片的代码

    本文转载至 http www luke99 com celuechuangyi 2011 05 6912 html 如何在网页中插入图片呢 只要有图片的地址 就可以通过代码设置而放入我们的网页的 代码具体如下 img src 其中蓝色部分为
  • 牛客网题集——Min Value(逻辑)

    Min Value 牛客网测试平台 题意 一个由 N 个数组成的序列 a1 a2 a3 an 1 an 从中任选两个数 ai 和 aj 使得 ai aj 的绝对值最小 并且计算出 i j 的值 其中 i j 输入描述 输入第一行包含一个正整
  • 调用高德地图展示车辆行驶轨迹

    如何在页面中使用高德地图并分页展示多段历史轨迹 引入高德地图的JavaScript API 打开index html key 后面的内容是你自己在高德上申请 的key 引入高德组件 配置webpack 找到webpack base conf
  • 【Java日期时间】@JsonFormat与@DateTimeFormat注解的区分和使用

    目录标题 JsonFormat与 DateTimeFormat注解的区分和使用 1 背景 2 JsonFormat代码示例 步骤 注意 3 DateTimeFormat代码示例 步骤 注意 总结 JsonFormat与 DateTimeFo
  • QWizardPage、QWizard

    QWizardPage 一 描述 QWizard 代表一个向导 每个页面都是一个 QWizardPage Page 提供了五个可以重新实现以提供自定义行为的虚函数 当用户单击向导的 Next 按钮时 将调用 initializePage 来
  • 连接数据库超时设置autoReconnect=true

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 1 问题现象 com MySQL jdbc CommunicationsException The last packet successfully received fr
  • 2021-07-26

    解决 Action client not connected arm gripper controller follow joint trajectory ERROR 1627267012 953273779 3804 152000000
  • cin中输入空格断开的解决方法

    cin中输入空格断开的解决方法 cin gt gt a 此时输入 hello world cout lt
  • LaTeX添加包

    将包文件夹放入 CTEX MiKTeX tex latex目录中
  • Head First的MVC之歌(英文版)

    MVC之歌 歌名 模型 视图 控制器 ModelViewController 词曲 James Dempsey https pan baidu com s 1PXDVDqRQVpKcZ1bQwCLNLQ 请大佬 翻译并唱 出来
  • 和为 K 的最少斐波那契数字数目(贪心)

    题目描述 给你数字 k 请你返回和为 k 的斐波那契数字的最少数目 其中 每个斐波那契数字都可以被使用多次 斐波那契数字定义为 F1 1 F2 1 Fn Fn 1 Fn 2 其中 n gt 2 数据保证对于给定的 k 一定能找到可行解 示例
  • 增强网关设计与使用

    增强网关 目的 整合错误码 对外显示友好 对内便于快速定位问题 记录出错请求 依照错误码制定处理策略 设计 状态码格式 示例 E01001B002 解析 E 统一前缀 表明异常 01 应用标识 001 功能域 B 错误类型 002 错误码
  • vue 3.0新特性之reactive与ref

    vue 3 0新特性 参考 https www cnblogs com Highdoudou p 9993870 html https www cnblogs com ljx20180807 p 9987822 html 性能优化 观察者机