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)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內容