成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【譯】函數(shù)組件和類組件有什么不同?

gself / 2528人閱讀

摘要:但是,你可能已經(jīng)注意到,當(dāng)你試圖通過指定依賴數(shù)組來優(yōu)化時,可能會遇到帶有過時閉包的錯誤。這是否意味著閉包是問題所在我不這么認(rèn)為。到目前為止,我所看到的所有情況下,過時的閉包問題都是由于錯誤地假設(shè)函數(shù)不更改或總是相同而發(fā)生的。

原文鏈接:https://overreacted.io/how-ar...

在很長一段時間內(nèi),標(biāo)準(zhǔn)答案是class components提供更多的特性(像state)。但隨著Hooks的出現(xiàn),答案就不再是這樣子了。

或許你聽說過他們中的一個性能可能更好,哪一個?因為各種的判斷標(biāo)準(zhǔn)獲取都存在缺陷,所以我們需要小心仔細(xì)的得出結(jié)論。性能的好壞主要取決于什么?它主要取決于你的代碼在做什么,而不是你使用的是function還是class。在我們的觀察中,盡管優(yōu)化的策略可能會有些許的不同,但性能的差異幾乎可以忽略不及。

無論是哪種情況,我們都不建議你重寫現(xiàn)有的組件,除非你有一些其他的原因或者是想成為Hooks的早期的采用者。Hooks仍然是一個新特性(就像2014年的React一樣),一些最佳實踐還沒有被寫入到教程中。

那我們該怎么辦?function componentsclass components之間有什么本質(zhì)的區(qū)別嗎?顯然,在構(gòu)思模型中是不同的。在這篇文章中,我們將看到他們之間最大的區(qū)別,自從2015年推出function componetns以來,它就一直存在著,但是卻經(jīng)常被忽視:

function components捕獲渲染值(capture value)

注意: 本文并不是對函數(shù)或者類的值做判斷。我只描述了React中這兩個編程模型之間的區(qū)別。有關(guān)更廣泛地采用函數(shù)的問題,請參閱hooks常見問題解答。

思考下面這樣一個組件:

function ProfilePage(props) {
  const showMessage = () => {
    alert("Followed " + props.user);
  };

  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };

  return (
    
  );
}

這個組件通過setTimeout模擬網(wǎng)絡(luò)請求,在點擊按鈕3秒后彈出props.user的值,如果props.user的值是Dan的話,他將在點擊后3秒彈出“Followed Dan”。(注意,使用箭頭函數(shù)還是函數(shù)聲明的形式并不重要,handleClick函數(shù)的工作方式完全相同)

如果改寫成class形式可能長下面這個樣子:

class ProfilePage extends React.Component {
  showMessage = () => {
    alert("Followed " + this.props.user);
  };

  handleClick = () => {
    setTimeout(this.showMessage, 3000);
  };

  render() {
    return ;
  }
}

通常認(rèn)為這兩段代碼是等效的。但是大家經(jīng)常在這兩種形式之間來回切換代碼而不去關(guān)注他們的含義。

然而其實這兩段代碼是有細(xì)微的差別的,就我個人而言,我花費了一段時間才看出來。

如果你自己想弄清楚的話,這里有一個在線demo。本文的剩余部分解釋了有什么不同和它的重要性。

再繼續(xù)之前,我要強(qiáng)調(diào),我所描述的差異本身和React Hooks無關(guān),上面的例子甚至都沒有使用Hooks。

這全部都是React中,function和class的差別。如果你想要在React應(yīng)用中去頻繁的使用function components,那么你應(yīng)該去了結(jié)它。

我們將用一個在React應(yīng)用程序中常見的錯誤來說明這一區(qū)別。

打開這個示例,有一個主頁select和兩個主頁,且每一個包含一個Follow按鈕。

嘗試按照下面的順序操作:

點擊一個Follow按鈕

改變select選項然后等待3秒

查看alert的文字

你會發(fā)現(xiàn)一個問題:

function components中,在Dan的主頁點擊follow然后切換到Sophie,alert仍然會展示“Followed Dan”。

class components中,alert的卻是“Followed Sophie”。

在這個例子中,第一個行為是正確的。如果我Follow A,然后導(dǎo)航B的主頁,我的組件不應(yīng)該Follow到B。這個class顯然有缺陷。

所以為什么我們class的例子展示出這樣的結(jié)果呢?

讓我們仔細(xì)研究一下class中的showMessage方法:

showMessage = () => {
  alert("Followed " + this.props.user);
};

這個方法從this.props.user取值,在React中,props應(yīng)該是不可變的,但是this卻是可變的。

實際上,在React內(nèi)部會隨著時間的推移改變this,以便可以在render和生命周期中取到最新的版本。

所以如果我們的組件在請求過程中re-render,this.props將會改變,showMessage方法將會從“最新”的props中取到user的值。

這就暴露了一個關(guān)于UI的有趣問題。如果說UI是一個關(guān)于當(dāng)前應(yīng)用state的函數(shù),那么事件處理函數(shù)就是render的一部分,就像是可視化輸出一樣。我們的事件處理函數(shù)“屬于“某一特定state和props的render。

但是在包含超時操作的回調(diào)函數(shù)內(nèi)讀取this.props會破壞這個關(guān)聯(lián)。showMessage沒有“綁定”到任何一個特定的render,因此它“丟失”了正確的props。

我們說function components不會存在這個問題。那么我們該怎么去解決呢?

我們需要去用某種方式“修復(fù)”正確的props到showMessage之間的關(guān)聯(lián)。在執(zhí)行的某個地方,props丟失了。

一個簡單的方式就是在早期我們就拿到這個this.props的值,然后顯示的去將它傳遞到超時處理函數(shù)中:

class ProfilePage extends React.Component {
  showMessage = (user) => {
    alert("Followed " + user);
  };

  handleClick = () => {
    const {user} = this.props;
    setTimeout(() => this.showMessage(user), 3000);
  };

  render() {
    return ;
  }
}

這是可行的。然而,這種方法使代碼更加冗長,并且隨著時間的推移更容易出錯。如果我們需要的不僅僅是一個單一的props怎么辦?如果ShowMessage調(diào)用另一個方法,而該方法讀取this.props.something或this.state.something,我們將再次遇到完全相同的問題。所以我們必須通過在ShowMessage調(diào)用的每個方法,將this.props和this.state作為參數(shù)傳遞。

這樣做我們通常會破壞一個class,并且會導(dǎo)致很多bug出現(xiàn)。

同樣,在handleClick中用alert展示也不能暴露出更深的問題。如果我們想要去結(jié)構(gòu)化我們的代碼,將代碼拆分出不同的方法,并且在讀取props和state時也能保持一樣的展示結(jié)果,而且不僅僅在React中,你也可以在任何UI庫中去調(diào)用它。

也許,我們可以在構(gòu)造函數(shù)中綁定這些方法?

class ProfilePage extends React.Component {
  constructor(props) {
    super(props);
    this.showMessage = this.showMessage.bind(this);
    this.handleClick = this.handleClick.bind(this);
  }

  showMessage() {
    alert("Followed " + this.props.user);
  }

  handleClick() {
    setTimeout(this.showMessage, 3000);
  }

  render() {
    return ;
  }
}

不,這并不能解決任何問題。記住,我們的問題是拿到this.props太晚了,而不是我們使用何種語法。但是,如果我們完全依賴于js的閉包,問題就會得到解決。

閉包通常是被避免的,因為它很難考慮一個隨時間變化的值。但是在React中,props和state應(yīng)該是不可變的。

這意味著,如果去掉某個特定render中的props或state,則始終可以指望它們保持相同:

class ProfilePage extends React.Component {
  render() {
    // Capture the props!
    const props = this.props;

    // Note: we are *inside render*.
    // These aren"t class methods.
    const showMessage = () => {
      alert("Followed " + props.user);
    };

    const handleClick = () => {
      setTimeout(showMessage, 3000);
    };

    return ;
  }
}

已經(jīng)在render時“捕獲”到了props。

這樣,它里面的任何代碼(包括showMessage)都可以保證取到某個特定render中的props了。

然后我們可以添加很多的helper函數(shù),他們都可以捕獲到props和state。閉包救了我們。

上面的例子是正確的,但看起來很奇怪。如果只是在render中定義函數(shù)而不是使用類方法,那么我們使用一個class又有什么意義呢?

實際上我們可以通過移除class來簡化代碼:

function ProfilePage(props) {
  const showMessage = () => {
    alert("Followed " + props.user);
  };

  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };

  return (
    
  );
}

就像上面所說的,props仍然可以被捕獲到,React將它作為一個參數(shù)傳遞。不同的是,props對象本身不會因React而發(fā)生變化了。

在下面中就更明顯了:

function ProfilePage({ user }) {
  const showMessage = () => {
    alert("Followed " + user);
  };

  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };

  return (
    
  );
}

當(dāng)父組件根據(jù)不同的props渲染時,React將會再次調(diào)用function,但是我們點擊的事件處理函數(shù)是上一個包含user值的render,并且showMessage函數(shù)已經(jīng)拿到了user這個值

這就是為什么在這個版本的function demo中在Sophie主頁點擊Follow,然后改變select,將會alert “Followed Sophie”。

現(xiàn)在我們知道了在React中 function 和 class的最大不同。

function components捕獲渲染值(capture value)

對于鉤子,同樣的原理也適用于state??紤]這個例子:

function MessageThread() {
  const [message, setMessage] = useState("");

  const showMessage = () => {
    alert("You said: " + message);
  };

  const handleSendClick = () => {
    setTimeout(showMessage, 3000);
  };

  const handleMessageChange = (e) => {
    setMessage(e.target.value);
  };

  return (
    <>
      
      
    
  );
}

這里是在線demo

這個例子說明了相同點:在點擊send按鈕后,再次修改輸入框的值,3秒后的輸出依然是點擊前輸入框的值。這說明function Hooks同樣具有capture value的特性。

所以我們知道了在React中function默認(rèn)情況下會捕獲props和state(capture value)。但是如果我們想要去避免這個capture value呢?

在class中,我們可以通過使用this.props和this.state,因為this本事是可變的,React改變了它,在function components中,還有一個被所有組件所共享的可變值,被叫做ref

function MyComponent() {
  const ref = useRef(null);
  // You can read or write `ref.current`.
  // ...
}

但是,你必須自己管理它。

ref和實例字段有著相同的作用,你也許更為熟悉“dom refs”,但是這個概念更為普遍,它僅僅是一個“放置一些東西的通用容器”。

盡管看起來它像是某一些東西的鏡像,但實際上他們表示著相同的概念。

React默認(rèn)不會為function components創(chuàng)建保存最新props和state的refs。因為很多情況下你是不需要他們的,并且分配他們也很浪費時間。但是需要的時候可以手動的去跟蹤值:

function MessageThread() {
  const [message, setMessage] = useState("");
  const latestMessage = useRef("");

  const showMessage = () => {
    alert("You said: " + latestMessage.current);
  };

  const handleSendClick = () => {
    setTimeout(showMessage, 3000);
  };

  const handleMessageChange = (e) => {
    setMessage(e.target.value);
    latestMessage.current = e.target.value;
  };

這時我們發(fā)現(xiàn),在點擊send按鈕后繼續(xù)輸入,3秒后alert的是點擊按鈕后輸入的值而不是點擊按鈕錢輸入的值。

通常,應(yīng)該避免在渲染期間讀取或設(shè)置refs,因為它們是可變的。我們希望保持渲染的可預(yù)測性。但是,如果我們想要獲取特定props或state的最新值,手動更新ref可能會很煩人。我們可以通過使用一種效果來實現(xiàn)自動化(useEffect在每次render都會執(zhí)行):

function MessageThread() {
  const [message, setMessage] = useState("");

  // Keep track of the latest value.
  const latestMessage = useRef("");
  useEffect(() => {
    latestMessage.current = message;
  });

  const showMessage = () => {
    alert("You said: " + latestMessage.current);
  };

這里是demo

我們在effect中進(jìn)行賦值,以便ref的值只在DOM更新后才更改。

像這樣使用ref不是經(jīng)常需要的。通常capture props或state才是默認(rèn)更好的選擇。但是,在處理諸如間隔和訂閱之類的命令式API時,它非常方便。記住,您可以跟蹤任何這樣的值:一個prop、一個state變量、整個props對象,甚至一個函數(shù)。

在本文中,我們研究了class中常見的中斷模式,以及閉包如何幫助我們修復(fù)它。但是,你可能已經(jīng)注意到,當(dāng)你試圖通過指定依賴數(shù)組來優(yōu)化Hooks時,可能會遇到帶有過時閉包的錯誤。這是否意味著閉包是問題所在?我不這么認(rèn)為。

正如我們上面所看到的,閉包實際上幫助我們解決了難以注意到的細(xì)微問題。類似地,它們使在并發(fā)模式下正確地編寫代碼變得更加容易。

到目前為止,我所看到的所有情況下,“過時的閉包”問題都是由于錯誤地假設(shè)“函數(shù)不更改”或“props總是相同”而發(fā)生的。事實并非如此,我希望這篇文章能夠幫助澄清。

function components沒有props和state,因此它們的也同樣重要。這不是bug,而是function components的一個特性。例如,函數(shù)不應(yīng)該從useEffect或useCallback的“依賴項數(shù)組”中被排除。(正確的解決方案通常是上面的useReducer或useRef解決方案。)

當(dāng)我們用函數(shù)編寫大多數(shù)React代碼時,我們需要調(diào)整優(yōu)化代碼的直覺,以及什么值會隨著時間而改變。

正如Fredrik所說:

對于Hooks,我迄今為止發(fā)現(xiàn)的最好的規(guī)則是“代碼就像任何值在任何時候都可以改變”。

React的function總是捕捉它們的值(capture value)—— 現(xiàn)在我們知道為什么了。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/102990.html

相關(guān)文章

  • Top 15 - Material Design框架和類庫()

    摘要:這是一個用于構(gòu)建響應(yīng)式應(yīng)用和網(wǎng)站的前端框架。是基于設(shè)計的一套豐富的組件。這是一個對混合式手機(jī)應(yīng)用框架的擴(kuò)展庫。到目前為止它僅大小,而且不依賴于任何第三方的插件,它可以很輕量的被用來創(chuàng)建和應(yīng)用。 _Material design_是Google開發(fā)的,目的是為了統(tǒng)一公司的web端和手機(jī)端的產(chǎn)品風(fēng)格。它是基于很多的原則,比如像合適的動畫,響應(yīng)式,以及顏色和陰影的使用。完整的指南詳情請看這里...

    Cristic 評論0 收藏0
  • Top 15 - Material Design框架和類庫()

    摘要:這是一個用于構(gòu)建響應(yīng)式應(yīng)用和網(wǎng)站的前端框架。是基于設(shè)計的一套豐富的組件。這是一個對混合式手機(jī)應(yīng)用框架的擴(kuò)展庫。到目前為止它僅大小,而且不依賴于任何第三方的插件,它可以很輕量的被用來創(chuàng)建和應(yīng)用。 _Material design_是Google開發(fā)的,目的是為了統(tǒng)一公司的web端和手機(jī)端的產(chǎn)品風(fēng)格。它是基于很多的原則,比如像合適的動畫,響應(yīng)式,以及顏色和陰影的使用。完整的指南詳情請看這里...

    phpmatt 評論0 收藏0
  • [] React組件 是采用Functional 還是 Class編寫 ?

    摘要:在里面有兩種組件類組件和函數(shù)式組件兩者有明顯的區(qū)別比如是屬于的類是一個函數(shù)它返回一個組件什么是先看一段代碼這是一個函數(shù)式組件它和類組件最關(guān)鍵的區(qū)別就是函數(shù)式組件沒有和一系列的鉤子函數(shù)這也是函數(shù)式組件經(jīng)常被用作無狀態(tài)組件的原因 在React里面有兩種組件, Class components(類組件) 和 Functional components(函數(shù)式組件).兩者有明顯的區(qū)別,比如 ...

    Integ 評論0 收藏0
  • 】為什么 React16 對開發(fā)人員來說是一種福音

    摘要:譯者前端小智原文就像人們對更新移動應(yīng)用程序和操作系統(tǒng)感到興奮一樣,開發(fā)人員也應(yīng)該對更新框架感到興奮。錯誤邊界是一種組件。注意將作為值傳遞進(jìn)去并不會導(dǎo)致使用。如果兩者不同,則返回一個用于更新狀態(tài)的對象,否則就返回,表示不需要更新狀態(tài)。 譯者:前端小智 原文:medium.freecodecamp.org/why-react16… 就像人們對更新移動應(yīng)用程序和操作系統(tǒng)感到興奮一樣,開發(fā)人員也應(yīng)...

    kbyyd24 評論0 收藏0

發(fā)表評論

0條評論

gself

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<