vue3与react、 react hooks - 千百度社区-前端论坛-技术交流-千百度社区

vue3与react、 react hooks

vue3与react、 react hooks

一、Vue3新特性:setup、ref、reactive、computed、watch、watchEffect函数、生命周期钩子、自定义hooks函数、toRef和toRefs、shallowReactive 与 shallowRef、readonly 与 shallowReadonly、toRaw 与 markRaw、customRef、provide 与 inject、Fragment、Teleport、Suspense、data选项应始终被声明为一个函数

2、setup是所有composition  API(组合式api)展示的舞台, 返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用,setUp(props, contex)接受两个参数,props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性(其实就是vue2.0的props功能),context:上下文对象(其中可以获取到1、attrs组件外部传递过来,但没有在props配置中声明的属性。2、slots:插槽内容3、emit:分发自定义事件的函数,并且以后在setup中不能写this.$emit,要写context.emit)

3、ref一般用来定义一个基本类型的响应式数据, reactive定义一个响应式源对象,接收一个普通对象然后返回该普通对象的响应式代理器对象,响应式转换是“深层的”:会影响对象内部所有嵌套的属性,内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据都是响应式的;watch默认是惰性的,watchEffect默认立即执行;watch可以获取到当前值和之前值,watchEffect只能获取当前值;watch可以传递多个函数作为参数,watchEffect只需要传递一个回调函数

4、

(1)、vue2响应式原理:

核心:

对象: 通过defineProperty对对象的已有属性值的读取和修改进行劫持(监视/拦截)

数组: 通过重写数组更新数组一系列更新元素的方法来实现元素修改的劫持

(2)、Vue3的响应式原理:

核心:

通过Proxy(代理):拦截对data任意属性的任意(13种)操作, 包括属性值的读写, 属性的添加, 属性的删除等…

通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作

5、生命周期:

为什么要在生命周期前加”on”?

因为setup是围绕beforeCreate和created生命周期来运行的,所以不需要显式地定义它们,这些生命周期函数接受一个回调函数,当钩子被组件调用时将会被执行。

beforeCreate -> 使用 setup()

created -> 使用 setup()

beforeMount -> onBeforeMount

mounted -> onMounted

beforeUpdate -> onBeforeUpdate

updated -> onUpdated

beforeDestroy -> onBeforeUnmount

destroyed -> onUnmounted

errorCaptured -> onErrorCaptured

1.vue3中已经没有destroyed 和beforeDestroy 了

2.vue3也可以用vue2的生命周期,vue3生命周期比vue2快

6、自定义hook函数

什么是hook? —-本质是一个函数,把setup函数中使用的composition API进行了封装

类似于vue2中的mixin

自定义hook的优势:复用代码,让setup中的逻辑更清晰易懂

(1)、基础封装hooks

//定义的hooks

import {reactive,onMounted,onBeforeUnmount} from ‘vue’

export default function(){

    let point=reactive(

        {

            x:0,

            y:0

        }

    )

    function sponk(event){

        console.log(point);

        point.x=event.pageX;

        point.y=event.pageY;

        console.log(event);

    }

    onMounted(()=>{

        console.log(‘onMounted’);

        document.getElementById(‘HelloWorld’).addEventListener(‘click’,sponk)

    })

    onBeforeUnmount(()=>{

        console.log(‘onBeforeUnmount’);

        document.getElementById(‘HelloWorld’).removeEventListener(‘click’,sponk)

    })

    return point;

}

//使用hooks的组件

<template>

  <div class=”hello” id=”HelloWorld”>

    x轴位置:{{valz.x}}<br/>

    y轴位置:{{valz.y}}<br/>

  </div>

</template>

<script>

  //引入定义的hooks

  import point from ‘./../hook/commonFirst’

  export default {

    name: ‘HelloWorld’,

    props: {

      msg: String

    },

    setup(){

      console.log(‘—setup—‘);

      //触发执行此方法即可

      let valz=point()

      return{

        valz

      }

    },

}

</script>

(2)、 封装发 axios 请求的 hook 函数

hooks/useRequest.ts

import { ref } from ‘vue’

import axios from ‘axios’

/*

使用axios发送异步ajax请求

*/

export default function useUrlLoader<T>(url: string) {

  const result = ref<T | null>(null)

  const loading = ref(true)

  const errorMsg = ref(null)

  axios

    .get(url)

    .then(response => {

      loading.value = false

      result.value = response.data

    })

    .catch(e => {

      loading.value = false

      errorMsg.value = e.message || ‘未知错误’

    })

  return {

    loading,

    result,

    errorMsg

  }

}

<template>

  <div class=”about”>

    <h2 v-if=”loading”>LOADING…</h2>

    <h2 v-else-if=”errorMsg”>{{ errorMsg }}</h2>

    <!– <ul v-else>

    <li>id: {{result.id}}</li>

    <li>name: {{result.name}}</li>

    <li>distance: {{result.distance}}</li>

  </ul> –>

    <ul v-for=”p in result” :key=”p.id”>

      <li>id: {{ p.id }}</li>

      <li>title: {{ p.title }}</li>

      <li>price: {{ p.price }}</li>

    </ul>

    <!– <img v-if=”result” :src=”result[0].url” alt=””> –>

  </div>

</template>

<script lang=”ts”>

import { watch } from ‘vue’

import useRequest from ‘./hooks/useRequest’

// 地址数据接口

interface AddressResult {

  id: number

  name: string

  distance: string

}

// 产品数据接口

interface ProductResult {

  id: string

  title: string

  price: number

}

export default {

  setup() {

    // const {loading, result, errorMsg} = useRequest<AddressResult>(‘/data/address.json’)

    const { loading, result, errorMsg } = useRequest<ProductResult[]>(‘/data/products.json’)

    watch(result, () => {

      if (result.value) {

        console.log(result.value.length) // 有提示

      }

    })

    return {

      loading,

      result,

      errorMsg

    }

  }

}

</script>

其他可以查看从0到1学vue3_山竹回家了的博客-CSDN博客_vue3

下面写一下vue3、react hooks原理及其区别

vue3 带来的六大新特性

Performance:性能比vue2.x块1.2~2倍

Tree shaking support:支持按需编译,体积更小

Composition API:组合API,类似React Hooks

Custom Renderer API:暴露了自定义渲染API

Fragment,Teleport(Protal),Suspense:新增三个组件

Better TypeScript support:更好的支持TS

Performance

Vue3.0在性能方面比Vue2.x快了1.2~2倍。

重写虚拟DOM的实现

运行时编译

静态提升与事件侦听器缓存

SSR 速度提高

Three-shaking support

Vue3.x中的核心API都支持tree-shaking,这些API都是通过包引入的方式而不是直接在实例化时就注入,只会对使用到的功能或特性进行打包(按需打包),这意味着更多的功能和更小的体积。

Composition API

Vue2.x中,我们通常采用mixin来复用逻辑代码,使用起来虽然方便,但也存在一些问题:代码来源不清晰、方法属性可能出现冲突。因此,Vue3.x引入了Composition API(组合API),使用纯函数分割复用代码。和React Hooks的概念相似。

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

更好的类型推导

Fragment、Teleport、Suspense

新增三个组件。

Fragment

在书写Vue2.x时,由于组件必须是一个根结点,很多时候会添加一些没有意义的节点用于包裹。Fragment组件就是用于解决这个问题的(这和React 中的Fragment组件是一样的)。

Teleport

Teleport其实就是React中的Portal。Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。

一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框。

Suspense

同样的,这和React中的Supense是一样的。

Suspense 让你的组件在渲染之前进行“等待”,并在等待时显示 fallback 的内容。

Vue3.0 是如何变快的

diff 算法优化

Vue2 中的虚拟dom 是进行全量对比

Vue3 新增静态标记,这和react的fiber类似,都是打tag

hoistStatic 静态提升

Vue2 中无论元素是否参与更新,每次都会重新创建,然后在渲染

Vue3 中对于不参与更新的元素,会做静态提升,只被创建一次,在渲染时直接复用即可

cacheHandlers 事件侦听器缓存

默认情况下默认情况下onClick会被视为动态绑定,所以每次都会去追踪它的变化,但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用即可

ssr 渲染

当有大量静态的内容的时候,这些内容会被当作纯字符串推进一个buffer里面,即使存在动态的绑定,会通过模版插值嵌入进去,这样会比通过虚拟dom来渲染的快上很多很多

当静态内容大到一定量级的时候,会用_createStaticVNode方法在客户端去生成一个static node。这些静态node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染。

vue3底层设计思想:

1.浏览器性能提升

  首先,随着ES6的发展已及广泛使用,浏览器对这些新的特性逐渐增加,性能不断优化,这就给vue3优化提供了一个机会,通过重写来优化提升vue的性能。

2、底层实现方法

在框架设计上,vue2.0 是采用Object.defineProperty来实现双向绑定原理,这个属性本身就存在一些不足的地方,比如:

1.Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。 为了解决这个问题,经过vue内部处理后可以使用以下几种方法来监听数组,push(),pop(),shift(),unshift(),splice(),sort(),reverse();由于只针对了以上八种方法进行了hack处理,所以其他数组的属性也是检测不到的,还是具有一定的局限性。

  2.Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue 2.x里,是通过 递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象是才是更好的选择,新增的属性还行通过set方法来添加监听,有一定的局限性。

  vue3主要采用的Proxy特性,有以下优点:

  1.可以劫持整个对象,并返回一个新的对象

  2.有13种劫持操作,但同时Proxy作为ES6的新特性,有一定的兼容问题,最主要的是这个属性无法用polyfill来兼容,这个需要在vue3中需要解决的问题。

React原理分析:

实现和更新原理

React将每个节点转化为fiber对象,最终形成一个fiber树结构,来依次渲染。通过两个fiber的对比来实现更新。这里要说到几个diff算法,分别是tree diff,component diff和element diff。同时更新过程可能会被打断,让优先级更高的任务优先执行(例如浏览器渲染)

Tree diff

新旧两个DOM树,逐层对比的过程;当整个DOM树逐层对比完毕,则所有需要被更新的元素必然能被找到;

Component diff

在进行Tree Diff的时候,每一层中,组件级别的对比。如果对比前后,组件的类型相同,则暂时认为此组件不需要被更新;如果对比前后,组件类型不同,则需要移除旧组件,创建新组件,并追加到页面上;

Element diff

在进行组件对比的时候,如果两个组件类型相同,则需要进行元素级别的对比,叫做element diff;

React 原理分析(一) —— React 设计思想 – 掘金 (juejin.cn)

React 源码分析(二)—— Fiber 的 render 阶段 – 掘金 (juejin.cn)

React 原理分析(三)—— Fiber 的commit 阶段 – 掘金 (juejin.cn)

vue与react的区别:

1、Vue和React存在着很多的共同点:

数据驱动视图

组件化

都使用Virtual DOM

2、核心思想不同

vue的主要特点:灵活易用的渐进式框架,进行数据拦截/代理,它对侦测数据的变化更敏感、更精确。

Reactt推崇函数式编程(纯组件),数据不可变以及单向数据流,当然需要双向的地方也可以手动实现, 比如借助onChange和setState来实现。

由于两者核心思想的不同,所以导致Vue和React在后续设计产生了许多的差异。

3、组件写法差异

Vue 推荐的做法是 template 的单文件组件格式(简单易懂,从传统前端转过来易于理解),即 html,css,JS 写在同一个文件(vue也支持JSX写法)

React推荐的做法是JSX + inline style, 也就是把 HTML 和 CSS 全都写进 JavaScript 中,即 all in js

这个差异一定程度上也是由于二者核心思想不同而导致的。

4.、响应式原理不同

Vue依赖收集,自动优化,数据可变。Vue递归监听data的所有属性,直接修改。当数据改变时,自动找到引用组件重新渲染。

React基于状态机,手动优化,数据不可变,需要setState驱动新的state替换老的state。当数据改变时,以组件为根目录,默认全部重新渲染, 所以 React 中会需要 shouldComponentUpdate 这个生命周期函数方法来进行控制

vue3.2中的defineProps、defineEmits、defineExpose,方便使用

vue3.2中的defineProps、defineEmits、defineExpose – 简书 (jianshu.com)

最后编辑于 : 2022.08.16 10:00:37 © 著作权归作者所有,转载或内容合作请联系作者

请登录后发表评论

    没有回复内容