<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          React Hooks 與Vue3.0 Function based API的對(duì)比?

          共 11916字,需瀏覽 24分鐘

           ·

          2021-02-02 01:36

          一、簡(jiǎn)述

          React Hooks?是 React16.8 引入的新特性,支持在類組件之外使用 state、生命周期等特性。

          Vue Function-based API?是 Vue3.0 最重要的 RFC (Requests for Comments),將 2.x 中與組件邏輯相關(guān)的選項(xiàng)以 API函數(shù) 的形式重新設(shè)計(jì)。

          目錄:

          ?React Hooks?React Hooks是什么?useState Hook?useEffect Hook?React Hooks 引入的原因以及設(shè)計(jì)原則?React Hooks 使用原則及其背后的原理?Vue3.0 Function-based API?基本用法?引入的原因以及解決的問題?React Hooks 與 Vue3.0 Function-based API 的對(duì)比

          二、React Hooks

          React Hooks 是什么?

          引用官網(wǎng)的一段話:

          從概念上講,React 組件更像是函數(shù)。而 Hooks 則擁抱了函數(shù),同時(shí)也沒有犧牲 React 的精神原則。Hooks 提供了問題的解決方案,無需學(xué)習(xí)復(fù)雜的函數(shù)式或響應(yīng)式編程技術(shù)。

          另外,Hooks 是100%向后兼容的,也是完全可選的。

          React Hooks 提供了三個(gè)基礎(chǔ) Hook :?useStateuseEffectuseContext,其他 Hooks 可參考React Hooks API[1]

          useState Hook

          下面是一個(gè)實(shí)現(xiàn)計(jì)數(shù)器功能的類組件示例:

          import React from 'react';class Example extends React.Component {  constructor (props) {    super(props)    this.state = {      count: 0    }  }  render () {    return (      

          You clicked {this.state.count} times

          ) }}

          需求很簡(jiǎn)單,設(shè)定初始值為0,當(dāng)點(diǎn)擊按鈕時(shí),count?加 1。

          當(dāng)使用 useState Hook 實(shí)現(xiàn)上述需求時(shí):

          import React, { useState } from 'react';function Example() {  const [count, setCount] = useState(0);  return (    

          You clicked {count} times

          );}

          其中?useState Hook?做了哪些事情呢?

          1.在調(diào)用 useState 方法時(shí),定義了一個(gè)state變量count,它與類組件中的this.state功能完全相同。對(duì)于普通變量,在函數(shù)退出后即消失,而state中的變量會(huì)被 React 保留。2.useState 方法只接收一個(gè)參數(shù),那就是初始值。useState 方法一次只定義一個(gè)變量,如果想在state中存儲(chǔ)兩個(gè)變量,只需要調(diào)用兩次 useState() 即可。3.useState 的返回值是一個(gè)由?當(dāng)前state?以及?更新state的函數(shù)?組成的數(shù)組。這也是采用?數(shù)組解構(gòu)?方式來獲取的原因。

          在使用 Hooks 實(shí)現(xiàn)的示例中,會(huì)發(fā)現(xiàn) useState 讓代碼更加簡(jiǎn)潔了:

          ?獲取state:類組件中使用?this.state.count?,而使用了 useSatet Hook 的函數(shù)組件中直接使用?count?即可。?更新state:類組件中使用?this.setState()?更新,函數(shù)組件中使用?setCount()?即可。

          這里拋出幾個(gè)疑問,在講解原理的地方會(huì)進(jìn)行詳細(xì)解釋:

          ?React 是如何記住 useState 上次值的??React 是如何知道 useState 對(duì)應(yīng)的是哪一個(gè)組件??如果一個(gè)組件內(nèi)有多個(gè) useState,那重新渲染時(shí) useState 的取值順序又是怎么確定的?

          useEffect Hook

          在講?useEffect?之前,先講一下 React 的副作用。

          在 React 中,數(shù)據(jù)獲取、訂閱或者手動(dòng)修改DOM等操作,均被稱為 '副作用',或者 '作用' 。

          而 useEffect 就是一個(gè) Effect Hook ,為函數(shù)組件添加操作副作用的能力,可以把它看作是類組件中的componentDidMountcomponentDidUpdatecomponentWillUnmount三個(gè)周期函數(shù)的組合。

          下面是一個(gè)關(guān)于訂閱的例子:

          import React from 'react';class Example extends React.Component {  constructor (props) {    super(props)    this.state = {      isOnline: null    }  }  componentDidMount() {    ChatAPI.subscribeToFriendStatus(      this.props.friend.id,      this.handleStatusChange    );  }  componentDidUpdate(prevProps) {    // 當(dāng) friend.id 變化時(shí)進(jìn)行更新    if (prevProps.friend.id !== this.props.friend.id) {      // 取消訂閱之前的 friend.id      ChatAPI.unsubscribeFromFriendStatus(        prevProps.friend.id,        this.handleStatusChange      );      // 訂閱新的 friend.id      ChatAPI.subscribeToFriendStatus(        this.props.friend.id,        this.handleStatusChange      );    }  }  componentWillUnmount() {    ChatAPI.unsubscribeFromFriendStatus(      this.props.friend.id,      this.handleStatusChange    );  }  handleStatusChange = (state) => {    this.setState({      isOnline: status.isOnline    });  }  render () {    return (      
          {this.state.isOnline === null ? 'Loading...' : (this.state.isOnline ? 'Online' : 'Offline') }
          ) }}

          從上述的代碼中不難發(fā)現(xiàn),存在一定的重復(fù)代碼,邏輯不得不拆分在三個(gè)生命周期內(nèi)部。另外由于類組件不會(huì)默認(rèn)綁定 this ,在定義?handleStatusChange?時(shí),還需要為它?綁定this

          這里補(bǔ)充一點(diǎn),對(duì)于類組件,需要謹(jǐn)慎對(duì)待 JSX 回調(diào)函數(shù)中的?this,類組件默認(rèn)是不會(huì)綁定 this 的,下面提供幾種綁定 this 的方法:

          1.通常的做法是將事件處理函數(shù)聲明為 class 中的方法,如:constructor內(nèi)部?this.handleClick = this.handleClick.bind(this)2.在 onClick 內(nèi)部使用箭頭函數(shù), 如:onClick={e=>this.handleClick(id, e)},注意:該方法在每次渲染時(shí)都會(huì)創(chuàng)建不同的回調(diào)函數(shù)。在大多數(shù)情況下,沒什么問題,但如果該回調(diào)函數(shù)作為 prop 傳入子組件時(shí),這些組件可能會(huì)進(jìn)行額外的重新渲染。3.在 onClick 內(nèi)部使用 bind 綁定, 如:onClick={this.handleClick.bind(this, e)}4.使用 class fields 綁定:如:handleClick = (e) => {}

          這也是 React 引入 Hooks 的其中一個(gè)原因。

          下面讓我們看一下 useEffect Hook 是如何實(shí)現(xiàn)上述需求的:

          import React, { useState, useEffect } from 'react';function Example(props) {  const [isOnline, setIsOnline] = useState(null);  useEffect(() => {    const handleStatusChange = (status) => {      setIsOnline(status.isOnline)    }    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);    return () => {      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);    };  }, [props.friend.id]);  return (    
          {isOnline === null ? 'Loading...' : (isOnline ? 'Online' : 'Offline') }
          )}

          在上述例子中,你可能會(huì)對(duì) useEffect Hook 產(chǎn)生以下疑問:

          1.useEffect 做了什么?首先,接收了一個(gè)函數(shù),而 React 會(huì)保存這個(gè)函數(shù)(稱為'effect'),并且在執(zhí)行 DOM 更新后調(diào)用這個(gè)函數(shù),即添加訂閱。2.[props.friend.id]?參數(shù)設(shè)置了什么??默認(rèn)情況下,useEffect 接收一個(gè)函數(shù)作為第一個(gè)參數(shù),在不設(shè)置第二個(gè)參數(shù)時(shí),每一次渲染都會(huì)執(zhí)行 effect,這有可能會(huì)導(dǎo)致性能問題。?為了解決這個(gè)問題,可添加第二個(gè)參數(shù),用來控制什么時(shí)候?qū)?huì)執(zhí)行更新,這時(shí)候就相當(dāng)于?componentDidUpdate?做的事情。?如果想只運(yùn)行一次 effect ,即僅在組件掛載和卸載時(shí)執(zhí)行,第二個(gè)參數(shù)可傳遞一個(gè)空數(shù)組[]3.在 useEffect 中為什么要返回一個(gè)函數(shù)呢?這是一個(gè)可選的操作,每一個(gè) effect 都可以返回一個(gè)清除函數(shù)。在 React 中,有一些副作用是需要清除的,比如 監(jiān)聽函數(shù)、定時(shí)器等,這時(shí)候就需要為 effect 增加一個(gè)返回函數(shù),React 會(huì)在組件卸載的時(shí)候執(zhí)行清除操作。

          Hooks 所提供的功能遠(yuǎn)不止這些,更多詳細(xì)的介紹可以查閱官網(wǎng)文檔[2]

          React Hooks 引入的原因以及設(shè)計(jì)原則

          React Hooks 具體解決了什么問題呢?React 為什么要引入這一特性呢?

          主要有以下三點(diǎn)原因:

          1.在組件之間復(fù)用狀態(tài)邏輯很困難。?React 并沒有提供將可復(fù)用行為附加到組件的途徑,一般比較常見的方法是采用?render props?和?高階組件?解決。?React Hooks 支持?自定義Hook,可以將狀態(tài)邏輯從組件中提出,使得這些邏輯可進(jìn)行單獨(dú)測(cè)試、復(fù)用,在無需修改組件結(jié)構(gòu)的情況下即可實(shí)現(xiàn)狀態(tài)邏輯復(fù)用。點(diǎn)擊查看自定義Hook使用說明[3]2.復(fù)雜組件變得難以理解。?每個(gè)生命周期函數(shù)內(nèi)部邏輯復(fù)雜、功能不單一,相互關(guān)聯(lián)的需求被拆分在各個(gè)生命周期中,而不相關(guān)的代碼卻需要在同一個(gè)周期內(nèi)部進(jìn)行整合。?為了解決這個(gè)問題,React Hooks 將組件中相互關(guān)聯(lián)的部分拆分成更小的函數(shù),引入了?Effect Hook,如上述 useEffect 的示例,正是解決了這個(gè)問題。3.難以理解的class。?this綁定?打包尺寸,函數(shù)通過ES export導(dǎo)出,可以借助 tree-shaking 把沒用到的函數(shù)移除;壓縮混淆,類的屬性和方法沒法壓縮?class熱重載不穩(wěn)定

          React Hooks 設(shè)計(jì)原則

          主要有以下四點(diǎn):

          1.優(yōu)雅高效的復(fù)用狀態(tài)邏輯2.無 class 困擾3.具備 class 已有的能力4.功能單一的副作用

          下面我們根據(jù)幾個(gè)例子來感受 React Hooks 具體是如何體現(xiàn)的。

          1、優(yōu)雅高效的復(fù)用狀態(tài)邏輯

          在之前,狀態(tài)邏輯的復(fù)用一般是采用?Mixins APIRender PropsHOC實(shí)現(xiàn),但是由于Render Props 與 HOC 本身也是組件,狀態(tài)邏輯的復(fù)用也是通過封裝組件的形式來實(shí)現(xiàn),仍難以避免組件多層嵌套的問題,也比利于后續(xù)的理解與維護(hù)。

          在 React Hooks 中,提供了?自定義Hook?來實(shí)現(xiàn)狀態(tài)邏輯的復(fù)用。

          比如 在聊天程序中,使用訂閱獲取好友的狀態(tài):

          import React, { useState, useEffect } from 'react';function useOnline(id) {  const [isOnline, setIsOnline] = useState(null);  useEffect(() => {    function handleStatusChange (state) {      setIsOnline(status.isOnline)    }    ChatAPI.subscribeToFriendStatus(id, handleStatusChange);    return () => {      ChatAPI.unsubscribeFromFriendStatus(id, handleStatusChange);    };  }, [id]);  return isOnline;}// 使用 自定義Hookfunction Example(props) {  const isOnline = useOnline(props.friend.id);  if (isOnline === null) {    return 'Loading...';  }  return isOnline ? 'Online' : 'Offline';}

          可以看到 useOnline 組件的邏輯是與業(yè)務(wù)完全無關(guān)的,它只是用來添加訂閱、取消訂閱,以獲取用戶的狀態(tài)。

          總結(jié):

          ?數(shù)據(jù)來源清楚,之間根據(jù)函數(shù)返回值獲得?代碼量少,更易維護(hù)?避免重復(fù)創(chuàng)建組件帶來性能損耗

          注意

          ?自定義Hook 是一個(gè)函數(shù),名稱必須以?'use'?開頭,這是一個(gè)約定,如果不遵循,React 將無法自動(dòng)檢測(cè)是否違反了 Hook 規(guī)則。?在函數(shù)的內(nèi)部可以調(diào)用其他 Hook,但是請(qǐng)確保只在頂層無條件地調(diào)用其他Hook。?React 會(huì)根據(jù)名稱來檢測(cè) Hook 是否違反了規(guī)則。?自定義 Hook 是一種重用狀態(tài)邏輯的機(jī)制,每次使用時(shí),內(nèi)部 state 與副作用是完全隔離的。

          2、無 class 困擾

          下面我們將根據(jù)一個(gè)具體例子?實(shí)現(xiàn)根據(jù)點(diǎn)擊事件,控制節(jié)點(diǎn)的展示或者隱藏的需求,來對(duì)?Render PropsHOCHooks的實(shí)現(xiàn)方式做簡(jiǎn)單對(duì)比。

          使用 Render Props 實(shí)現(xiàn)

          Render Props 是指一種在 React 組件之間使用一個(gè)值為函數(shù)的 prop 共享代碼的簡(jiǎn)單技術(shù)。

          創(chuàng)建?VisibilityHelper

          import React from 'react';import PropTypes from 'prop-types';class VisibilityHelper extends React.Component {  constructor(props) {    super(props);    this.state = {      isDisplayed: props.initialState || false,    };  }  hide = () => {    this.setState({      isDisplayed: false,    });  }  show = () => {    this.setState({      isDisplayed: true,    });  }  render() {    return this.props.children({      ...this.state,      hide: this.hide,      show: this.show,    });  }}VisibilityHelper.propTypes = {  initialState: PropTypes.bool,  children: PropTypes.func.isRequired,};export default VisibilityHelper;

          對(duì)?VisibilityHelper?的使用:

          import React from 'react';import VisibilityHelper from 'VisibilityHelper';function ButtonComponent() {  return (          {        ({          isDisplayed,          hide,          show        }) => (            
          { isDisplayed ? : }
          ) } );}

          在?組件中,我們使用了一個(gè)帶有函數(shù)prop的?組件,實(shí)現(xiàn)了代碼復(fù)用。

          使用 HOC 實(shí)現(xiàn)

          高階組件,是 React 中復(fù)用組件邏輯的一種高級(jí)技巧,是一種基于 React 組合特性而形成的設(shè)計(jì)模式。

          定義高階組件?VisibilityHelper?,注意 HOC 不會(huì)修改傳入的組件,也不會(huì)使用繼承來復(fù)制其行為。相反,HOC 通過將組件包裝在容器組件中來組成新組件。HOC 是純函數(shù),沒有副作用。

          import React from 'react';function VisibilityHelper(WrappedComponent, initialState = false) {  return class extends React.Component {    constructor(props) {      super(props);      this.state = {        isDisplayed: initialState      };    }    hide = () => {      this.setState({        isDisplayed: false,      });    }    show = () => {      this.setState({        isDisplayed: true,      });    }    render() {      return         isDisplayed={this.state.isDisplayed}        show={() => this.show()}        hide={() => this.hide()}        {...this.props} />;    }  };}// 定義 按鈕組件let ButtonComponent = ({ isDisplayed, hide, show }) => {  return (    
          { isDisplayed ? : }
          );}// 使用高階組件,并設(shè)定默認(rèn)值ButtonComponent = VisibilityHelper(ButtonComponent, true);export default ButtonComponent

          在 React Hooks 中是如何實(shí)現(xiàn)上述邏輯的呢?

          import React, { useState } from 'react';function ButtonComponent() {  const [isDisplayed, show] = useState(false)  return (    
          { isDisplayed ? : }
          )}

          從對(duì)比中可以發(fā)現(xiàn),使用 Hooks 更簡(jiǎn)潔,且不需要在擔(dān)心this綁定地問題。

          3、具備 class 已有的能力

          對(duì)于常用的 class 能力,Hooks 已經(jīng)基本覆蓋。

          對(duì)于其他不常見的能力,官方給出的回應(yīng)是:

          目前暫時(shí)還沒有對(duì)應(yīng)不常用的 getSnapshotBeforeUpdate 和 componentDidCatch 生命周期的 Hook 等價(jià)寫法,但我們計(jì)劃盡早把它們加進(jìn)來。目前 Hook 還處于早期階段,一些第三方的庫可能還暫時(shí)無法兼容 Hook。

          4、功能單一的副作用

          通過文中的幾個(gè)示例,應(yīng)該可以了解到 useEffect Hook 便是設(shè)計(jì)用來解決副作用分散、邏輯不單一的問題。

          在真實(shí)的應(yīng)用場(chǎng)景中,可根據(jù)業(yè)務(wù)需要編寫多個(gè) useEffect。

          React Hooks 使用原則

          兩條使用原則:

          1.只在最頂層使用 Hooks,不能在循環(huán)、條件或嵌套函數(shù)中調(diào)用 Hooks。這是為了保證 Hooks 在每一次渲染中都按照同樣的順序被調(diào)用。2.只能在 React 的函數(shù)組件中或者 自定義Hook 中調(diào)用 Hooks。確保組件的狀態(tài)邏輯在代碼中清晰可見。

          這兩條原則讓 React 能夠在多次的 useState 和 useEffect 調(diào)用之間保持 hook 狀態(tài)的正確。

          React Hooks 背后的原理

          之前的拋出的疑問:

          ?React 是如何記住 useState 上次值的??React 是如何知道 useState 對(duì)應(yīng)的是哪一個(gè)組件??如果一個(gè)組件內(nèi)有多個(gè) useState,那重新渲染時(shí) useState 的取值順序又是怎么確定的?

          在 React 中從編譯到渲染成 Dom,都要經(jīng)歷這樣的過程:JSX -> Element -> FiberNode -> Dom

          Hooks 要想和一個(gè)函數(shù)組件進(jìn)行綁定, 就要和這個(gè)轉(zhuǎn)換過程的某個(gè)節(jié)點(diǎn)進(jìn)行關(guān)聯(lián),由于 Hooks 只有在 render 過程中進(jìn)行調(diào)用,很明顯就只能關(guān)聯(lián)到?FiberNode?上。

          在 FiberNode 上有 一個(gè)屬性?memoizedState,這個(gè)屬性在 class 組件中對(duì)應(yīng)最終渲染的 state。

          class 組件的state一般是一個(gè)對(duì)象,在 函數(shù)組件中變成 一個(gè)鏈表,如 class 組件?memoizedState = {a: 1, b: 2} => 函數(shù)組件 memoizedState = {state: 1, next: {state: 2, next: ..}}

          每個(gè)鏈表的節(jié)點(diǎn)都是一個(gè) useState,從而將所有 Hooks 進(jìn)行串聯(lián)起來。不僅僅 State Hook,其它 Hook 也是通過 memoizedState 串聯(lián)起來的。

          第一次渲染后,通過 FiberNode 的 memoizedState 將所有 Hook 進(jìn)行收集完成。

          當(dāng)執(zhí)行 setState 進(jìn)行組件更新時(shí),重新執(zhí)行函數(shù)組件,這時(shí)會(huì)從收集的 Hooks 中按照?qǐng)?zhí)行順訊依次取出,對(duì)于 State Hook 會(huì)進(jìn)行計(jì)算將最新的值返回, Effect Hook 會(huì)在組件渲染結(jié)束后,先執(zhí)行清除函數(shù),再執(zhí)行 副作用函數(shù)。

          過程如圖:

          過程

          三、Vue3.0 Function-based API

          首先提一下 Vue Function-based API 的升級(jí)策略。

          Vue3.0目前還未發(fā)布(預(yù)計(jì)2019年發(fā)布),vue官方提供了Vue Function API[4],支持Vue2.x版本使用組件邏輯復(fù)用機(jī)制。當(dāng)3.0發(fā)布后,可無縫替換掉該庫。

          另外,Vue3.0計(jì)劃發(fā)布兩個(gè)不同版本:

          ?兼容版本:同時(shí)支持新 API 和 2.x 的所有選項(xiàng)?標(biāo)準(zhǔn)版本:只支持新 API 和部分 2.x 選項(xiàng)

          下面是一個(gè)基礎(chǔ)例子:

          import { value, computed, watch, onMounted } from 'vue'const App = {  template: `    
          count is {{ count }} plusOne is {{ plusOne }}
          `, setup() { // reactive state const count = value(0) // computed state const plusOne = computed(() => count.value + 1) // method const increment = () => { count.value++ } // watch watch(() => count.value * 2, val => { console.log(`count * 2 is ${val}`) }) // lifecycle onMounted(() => { console.log(`mounted`) }) // expose bindings on render context return { count, plusOne, increment } }}

          Vue Function-based API 引入的原因及解決的問題

          引入的原因,借用官方推出的一段話:

          組件 API 設(shè)計(jì)所面對(duì)的核心問題之一就是如何組織邏輯,以及如何在多個(gè)組件之間抽取和復(fù)用邏輯。

          其實(shí)也就是 React Hooks 引入時(shí)提到的:在組件之間復(fù)用狀態(tài)邏輯很困難。

          在Vue2.0中,有一些常見的邏輯復(fù)用模式,如:Mixins高階組件Renderless Components,這些模式均或多或少的存在以下問題:

          ?模版中的數(shù)據(jù)來源不清晰?命名空間容易沖突?性能問題,需要額外的組件實(shí)例嵌套來封裝邏輯,帶來不必要的性能開銷等

          Function-based API 受 React Hooks 的啟發(fā),提供一個(gè)全新的邏輯復(fù)用方案,且不存在上述問題。

          四、React Hooks 與 Vue Function-based API 的對(duì)比

          兩者均具有基于函數(shù)提取和復(fù)用邏輯的能力。

          React Hooks 在每次組件渲染時(shí)都會(huì)調(diào)用,通過隱式地將狀態(tài)掛載在當(dāng)前的內(nèi)部組件節(jié)點(diǎn)上,在下一次渲染時(shí)根據(jù)調(diào)用順序取出。

          而 Vue 的響應(yīng)式 機(jī)制使 setup() 只需要在初始化時(shí)調(diào)用一次,狀態(tài)通過引用儲(chǔ)存在 setup() 的閉包內(nèi)。這也是vue不受調(diào)用順序限制的原因。

          引用鏈接

          [1]?React Hooks API:?https://zh-hans.reactjs.org/docs/hooks-reference.html
          [2]?官網(wǎng)文檔:?https://reactjs.org/
          [3]?自定義Hook使用說明:?https://zh-hans.reactjs.org/docs/hooks-custom.html
          [4]?Vue Function API:?https://github.com/vuejs/vue-function-api



          瀏覽 78
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费在线观看视频黄 | 樱桃性爱视频 | 小黄片视频网站 | 五月丁香网操 | 日本va在线观看 日本va中文字幕 |