React函數(shù)組件與類的區(qū)別有哪些_第1頁(yè)
React函數(shù)組件與類的區(qū)別有哪些_第2頁(yè)
React函數(shù)組件與類的區(qū)別有哪些_第3頁(yè)
React函數(shù)組件與類的區(qū)別有哪些_第4頁(yè)
React函數(shù)組件與類的區(qū)別有哪些_第5頁(yè)
已閱讀5頁(yè),還剩5頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第React函數(shù)組件與類的區(qū)別有哪些目錄一、函數(shù)式組件捕獲了渲染所用的值二、閉包讓類組件成為擁有特定props和state的渲染三、區(qū)分useState與useRef的使用首先我們要知道的是,項(xiàng)目性能能主要取決于代碼的作用,而不是選擇函數(shù)式還是類組件。盡管優(yōu)化策略各有略微不同,但它們之間的性能差異可以忽略不計(jì)。

一、函數(shù)式組件捕獲了渲染所用的值

首先我們來(lái)看下面這個(gè)組件:

functionApp(props){

constshowMessage=()={

alert('Hello'+props.user);

consthandleClick=()={

setTimeout(showMessage,3000);

return(

buttonhandleClick}Say/button

}

它渲染了一個(gè)利用來(lái)模擬網(wǎng)絡(luò)請(qǐng)求,然后顯示一個(gè)確認(rèn)警告的按鈕。例如,如果是傳遞進(jìn)來(lái)的props.user是jie,那么三秒后就會(huì)彈出Hellojie。

那么我們用類應(yīng)該怎么寫這個(gè)組件呢?一個(gè)簡(jiǎn)單的重構(gòu)可能就象這樣:

classAppextendsReact.Component{

showMessage=()={

alert('Hello'+ps.user);

handleClick=()={

setTimeout(this.showMessage,3000);

render(){

returnbuttonthis.handleClick}Say/button

}

我們通常做代碼重構(gòu)的時(shí)候都認(rèn)為他們兩個(gè)是等效的,但是事實(shí)真的如此嗎,我們很少注意到它們之間的含義。

下面我們新建一個(gè)react項(xiàng)目,在src下新建兩個(gè)組件,一個(gè)classComponent組件,一個(gè)是functionComponent組件。代碼就是上面我們寫的這兩個(gè)組件,只不過(guò)內(nèi)容稍有區(qū)別:

classComponent:

importReactfrom'react';

classProfilePageextendsReact.Component{

showMessage=()={

alert('你選擇了'+ps.user);

handleClick=()={

setTimeout(this.showMessage,3000);

render(){

returnbuttonthis.handleClick}選擇/button

exportdefaultProfilePage;

functionComponent:

importReactfrom'react';

functionProfilePage(props){

constshowMessage=()={

alert('你選擇了'+props.user);

consthandleClick=()={

setTimeout(showMessage,3000);

return(

buttonhandleClick}選擇/button

exportdefaultProfilePage;

在app.js中我們將這兩個(gè)組件引入:

importReactfrom"react";

importReactDOMfrom"react-dom";

importProfilePageFunctionfrom'./functionComponent';

importProfilePageClassfrom'./classComponent';

exportdefaultclassAppextendsReact.Component{

state={

user:'小杰',

render(){

return(

label

b選擇你想要拜訪的朋友/b

select

value={this.state.user}

onChange={e=this.setState({user:e.target.value})}

optionvalue="小杰"小杰/option

optionvalue="小尚"小尚/option

optionvalue="小寧"小寧/option

/select

/label

h1歡迎來(lái)到{this.state.user}的家!/h1

ProfilePageFunctionuser={this.state.user}/

b(這是來(lái)自函數(shù)式組件的)/b

ProfilePageClassuser={this.state.user}/

b(這是來(lái)自類組件的)/b

}

運(yùn)行項(xiàng)目,科研看到這樣的界面:

當(dāng)我們單擊上面的按鈕時(shí),執(zhí)行的就是函數(shù)式組件,點(diǎn)擊下面的按鈕時(shí),執(zhí)行的就是類。如果按照我們以往的思路,他們二者都會(huì)有相同的結(jié)果,但事實(shí)真的如此嗎?

我們按照下面的順序執(zhí)行:

1.點(diǎn)擊函數(shù)式組件按鈕

2.在點(diǎn)擊后立刻切換想要拜訪的朋友

函數(shù)式組件的執(zhí)行結(jié)果如下:

頁(yè)面彈出的還是我們當(dāng)時(shí)選擇的值

同樣的操作我們?cè)僭囈幌骂惤M件:

現(xiàn)在頁(yè)面彈出的就是我們實(shí)時(shí)更改的值了。

在這個(gè)例子中,第一個(gè)行為是正確的。因?yàn)樽铋_始我選擇要拜訪小杰點(diǎn)擊了確定發(fā)出了命令,然后我再切換到小尚,但是我并沒(méi)有點(diǎn)擊確定,我的組件不應(yīng)該混淆我要拜訪的人。在這里,類組件的實(shí)現(xiàn)很明顯是錯(cuò)誤的。

所以為什么我們的例子中類組件會(huì)有這樣的表現(xiàn)?

讓我們來(lái)仔細(xì)看看我們類組件中的方法:showMessage

showMessage=()={

alert('你選擇了'+ps.user);

};

這個(gè)類方法從中讀取數(shù)據(jù)。在React中Props是不可變的,所以他們永遠(yuǎn)不會(huì)改變。然而,this是,而且永遠(yuǎn)是,可變的。

事實(shí)上,這就是類組件存在的意義。React本身會(huì)隨著時(shí)間的推移而改變,以便你可以在渲染方法以及生命周期方法中得到最新的實(shí)例。所以如果在請(qǐng)求已經(jīng)發(fā)出的情況下我們的組件進(jìn)行了重新渲染,將會(huì)改變。

我們的組件屬于一個(gè)擁有特定props和state的特定渲染。

然而,調(diào)用一個(gè)回調(diào)函數(shù)讀取的timeout會(huì)打斷這種關(guān)聯(lián)。我們的回調(diào)并沒(méi)有與任何一個(gè)特定的渲染綁定在一起,所以它失去了正確的props。

二、閉包讓類組件成為擁有特定props和state的渲染

我們想要以某種方式修復(fù)擁有正確props的渲染與讀取這些props的回調(diào)之間的聯(lián)系。它們?cè)陬惖哪硞€(gè)地方被弄丟了。

一種方法是在調(diào)用事件之前讀取,然后將他們顯式地傳遞到timeout回調(diào)函數(shù)中去:

importReactfrom'react';

classProfilePageextendsReact.Component{

showMessage=(user)={

alert('你選擇了'+user);

handleClick=()={

const{user}=ps;

setTimeout(()=this.showMessage(user),3000);

render(){

returnbuttonthis.handleClick}確定/button

exportdefaultProfilePage;

這種方法會(huì)起作用。然而,這種方法使得代碼明顯變得更加冗長(zhǎng),并且隨著時(shí)間推移容易出錯(cuò)。如果我們需要的不止是一個(gè)props怎么辦?如果我們還需要訪問(wèn)state怎么辦?

然而,如果我們能利用JavaScript閉包的話問(wèn)題將迎刃而解。

通常來(lái)說(shuō)我們會(huì)避免使用閉包,但是在React中,props和state是不可變的,這就消除了閉包的一個(gè)主要缺陷。

這就意味著如果你在一次特定的渲染中捕獲那一次渲染所用的props或者state,你會(huì)發(fā)現(xiàn)他們總是會(huì)保持一致,就如同你的預(yù)期那樣。

classProfilePageextendsReact.Component{

render(){

constprops=ps;

constshowMessage=()={

alert('你選擇了'+props.user);

consthandleClick=()={

setTimeout(showMessage,3000);

returnbuttonhandleClick}確定/button

}

你在渲染的時(shí)候就已經(jīng)捕獲了props。這樣,在它內(nèi)部的任何代碼(包括)都保證可以得到這一次特定渲染所使用的props。上面的例子是正確的,但是看起來(lái)很奇怪。如果你在方法中定義各種函數(shù),而不是使用class的方法,那么使用類的意義在哪里?

所以這個(gè)時(shí)候我們就明白了函數(shù)式組件和類組件的區(qū)別:

functionProfilePage({user}){

constshowMessage=()={

alert('Followed'+user);

consthandleClick=()={

setTimeout(showMessage,3000);

return(

buttonhandleClick}Follow/button

}

當(dāng)父組件使用不同的props來(lái)渲染時(shí),React會(huì)再次調(diào)用函數(shù)。但是我們點(diǎn)擊的事件處理函數(shù),屬于具有自己的值的上一次渲染,并且回調(diào)函數(shù)也能讀取到這個(gè)值。它們都保持完好無(wú)損。

三、區(qū)分useState與useRef的使用

使用Hooks,同樣的原則也適用于狀態(tài)。看這個(gè)例子:

functionMessageThread(){

const[message,setMessage]=useState('');

constshowMessage=()={

alert('Yousaid:'+message);

consthandleSendClick=()={

setTimeout(showMessage,3000);

consthandleMessageChange=(e)={

setMessage(e.target.value);

return(

inputvalue={message}onChange={handleMessageChange}/

buttonhandleSendClick}Send/button

}

如果我發(fā)送一條特定的消息,組件不應(yīng)該對(duì)實(shí)際發(fā)送的是哪條消息感到困惑。這個(gè)函數(shù)組件的變量捕獲了我們?cè)跒g覽器中執(zhí)行單擊處理函數(shù)的那一次渲染。所以當(dāng)我點(diǎn)擊發(fā)送時(shí)那一刻輸入框中的內(nèi)容就會(huì)被設(shè)置為彈出的值。

因此我們知道,在默認(rèn)情況下React中的函數(shù)會(huì)捕獲props和state。但是如果我們想要讀取并不屬于這一次特定渲染的,最新的props和state呢?

在函數(shù)式組件中,你也可以擁有一個(gè)在所有的組件渲染幀中共享的可變變量。它被成為ref:

functionMyComponent(){

constref=useRef(null);

//你可以通過(guò)ref.current來(lái)獲取保存的值.

//...

}

在很多情況下,你并不需要它們,并且分配它們將是一種浪費(fèi)。但是,如果你愿意,你可以這樣手動(dòng)地來(lái)追蹤這些值:

functionMessageThread(){

const[message,setMessage]=useState('');

constlatestMessage=useRef('');

constshowMessage=()={

alert('Yousaid:'+latestMessage.current);

consthandleSendClick=()={

setTimeout(showMessage,3000);

consthandleMessageChange=(e)={

setMessage(e.target.value);

latestMessage.current=e.target.value;

}

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論