您好,登錄后才能下訂單哦!
通過 Medium 中的一篇文章來學(xué)習(xí) React.js 的基本原理
你有沒有注意到在 React 的 logo 中隱藏著一個(gè)六角星?只是順便提下...
去年我寫了一本簡短的關(guān)于學(xué)習(xí) React.js 的書,有 100 頁左右。今年,我要挑戰(zhàn)自己 —— 將其總結(jié)成一篇文章,并向 Medium 投稿。
這篇文章不是講什么是 React 或者 你該怎樣學(xué)習(xí) React。這是在面向那些已經(jīng)熟悉了 JavaScript 和 DOM API 的人的 React.js 基本原理介紹
本文采用嵌入式 jsComplete 代碼段,所以為了方便閱讀,你需要一個(gè)合適的屏幕寬度。
下面所有的代碼都僅供參考。它們也純粹是為了表達(dá)概念而提供的例子。它們中的大多數(shù)有更好的實(shí)踐方式。
您可以編輯和執(zhí)行下面的任何代碼段。使用?Ctrl+Enter?執(zhí)行代碼。每一段的右下角有一個(gè)點(diǎn)擊后可以在 jsComplete/repl 進(jìn)行全屏模式編輯或運(yùn)行代碼的鏈接。
1 React 全部都是組件化的
React 是圍繞可重用組件的概念設(shè)計(jì)的。你定義小組件并將它們組合在一起形成更大的組件。
無論大小,所有組件都是可重用的,甚至在不同的項(xiàng)目中也是如此。
React 組件最簡單的形式,就是一個(gè)普通的 JavaScript 函數(shù):
function?Button?(props)?{?//?這里返回一個(gè)?DOM?元素,例如: ?return?<button?type="submit">{props.label}</button>; }//?將按鈕組件呈現(xiàn)給瀏覽器ReactDOM.render(<Button?label="Save"?/>,?mountNode)復(fù)制代碼
例 1:編輯上面的代碼并按 Ctrl+Enter 鍵執(zhí)行(譯者注:譯文暫時(shí)沒有這個(gè)功能,請?jiān)L問原文使用此功能,下同)
括號(hào)中的 button 標(biāo)簽將稍后解釋?,F(xiàn)在不要擔(dān)心它們。ReactDOM 也將稍后解釋,但如果你想測試這個(gè)例子和所有接下來的例子,上述 render 函數(shù)是必須的。(React 將要接管和控制的是 ReactDOM.render 的第 2 個(gè)參數(shù)即目標(biāo) DOM 元素)。在 jsComplete REPL 中,你可以使用特殊的變量 mountNode。
例 1 的注意事項(xiàng):
組件名稱首字母大寫,Button。必須要這樣做是因?yàn)槲覀儗⑻幚?HTML 元素和 React 元素的混合。小寫名稱是為 HTML 元素保留的。事實(shí)上,將 React 組件命名為 “button” 然后你就會(huì)發(fā)現(xiàn) ReactDOM 會(huì)忽略這個(gè)函數(shù),僅僅是將其作為一個(gè)普通的空 HTML 按鈕來渲染。
每個(gè)組件都接收一個(gè)屬性列表,就像 HTML 元素一樣。在 React 中,這個(gè)列表被稱為屬性。雖然你可以將一個(gè)函數(shù)隨意命名。
在上面 Button 函數(shù)組件的返回輸出中,我們奇怪地寫了段看上去像 HTML 的代碼。這實(shí)際上既不是 JavaScript 也不是 HTML,老實(shí)說,這甚至不是 React.js。然而它非常流行,以至于成為 React 應(yīng)用程序中的默認(rèn)值。這就是所謂的 JSX,這是一個(gè)JavaScript 的擴(kuò)展。JSX 也是一個(gè)折中方案!繼續(xù)嘗試并在上面的函數(shù)中返回其他 HTML 元素,看看它們是如何被支持的(例如,返回一個(gè)文本輸入元素)。
2 JSX 輸出的是什么?
上面的例 1 可以用沒有 JSX 的純 React.js 編寫,如下:
function?Button?(props)?{ ?return?React.createElement(?"button", ?{?type:?"submit"?}, ?props.label ?); }//?要使用?Button,你可以這么做ReactDOM.render( ?React.createElement(Button,?{?label:?"Save"?}), ?mountNode );復(fù)制代碼
例 2:不使用 JSX 編寫 React 組件
在 React 頂級 API 中,createElement 函數(shù)是主函數(shù)。這是你需要學(xué)習(xí)的 7 個(gè) API 中的 1 個(gè)。React 的 API 就是這么小。
就像 DOM 自身有一個(gè) document.createElement 函數(shù)來創(chuàng)建一個(gè)由標(biāo)簽名指定的元素一樣,React 的 createElement 函數(shù)是一個(gè)高級函數(shù),有和 document.createElement 同樣的功能,但它也可以用于創(chuàng)建一個(gè)表示 React 組件的元素。當(dāng)我們使用上面例 2 中的按鈕組件時(shí),我們使用的是后者。
不像 document.createElement,React 的 createElement 在接收第二個(gè)參數(shù)后,接收一個(gè)動(dòng)態(tài)參數(shù),它表示所創(chuàng)建元素的子元素。所以 createElement 實(shí)際上創(chuàng)建了一個(gè)樹。
這里就是這樣的一個(gè)例子:
const?InputForm?=?React.createElement(?"form", ?{?target:?"_blank",?action:?"https://google.com/search"?}, ?React.createElement("div",?null,?"Enter?input?and?click?Search"), ?React.createElement("input",?{?className:?"big-input"?}), ?React.createElement(Button,?{?label:?"Search"?}) );//?InputForm?使用?Button?組件,所以我們需要這樣做:function?Button?(props)?{?return?React.createElement(?"button", ?{?type:?"submit"?}, ?props.label ?); }//?然后我們可以通過?.render?方法直接使用?InputFormReactDOM.render(InputForm,?mountNode);復(fù)制代碼
例 3:React 創(chuàng)建元素的 API
上面例子中的一些事情值得注意:
InputForm 不是一個(gè) React 組件;它僅僅是一個(gè) React?元素。這就是為什么我們可以在 ReactDOM.render 中直接使用它并且可以在調(diào)用時(shí)不使用 <InputForm /> 的原因。
React.createElement 函數(shù)在前兩個(gè)參數(shù)后接收了多個(gè)參數(shù)。從第3個(gè)參數(shù)開始的參數(shù)列表構(gòu)成了創(chuàng)建元素的子項(xiàng)列表。
我們可以嵌套 React.createElement 調(diào)用,因?yàn)樗?JavaScript。
當(dāng)這個(gè)元素不需要屬性時(shí),React.createElement 的第二個(gè)參數(shù)可以為空或者是一個(gè)空對象。
我們可以在 React 組件中混合 HTML 元素。你可以將 HTML 元素作為內(nèi)置的 React 組件。
React 的 API 試圖和 DOM API 一樣,這就是為什么我們在 input 元素中使用 className 代替 class 的原因。我們都希望如果 React 的 API 成為 DOM API 本身的一部分,因?yàn)?,你知道,它要好得多?/p>
上述的代碼是當(dāng)你引入 React 庫的時(shí)候?yàn)g覽器是怎樣理解的。瀏覽器不會(huì)處理任何 JSX 業(yè)務(wù)。然而,我們更喜歡看到和使用 HTML,而不是那些 createElement 調(diào)用(想象一下只使用 document.createElement 構(gòu)建一個(gè)網(wǎng)站?。?。這就是 JSX 存在的原因。取代上述調(diào)用 React.createElement 的方式,我們可以使用一個(gè)非常簡單類似于 HTML 的語法:
const?InputForm?= ?<form?target="_blank"?action="https://google.com/search"> ?<div>Enter?input?and?click?Search</div> ?<input?className="big-input"?name="q"?/> ?<Button?label="Search"?/> ?</form>;//?InputForm?“仍然”使用?Button?組件,所以我們也需要這樣。//?JXS?或者普通的表單都會(huì)這樣做function?Button?(props)?{?//?這里返回一個(gè)?DOM?元素。例如: ?return?<button?type="submit">{props.label}</button>; }//?然后我們可以直接通過?.render?使用?InputFormReactDOM.render(InputForm,?mountNode);復(fù)制代碼
例 4:為什么在 React 中 JSX 受歡迎(和例 3 相比)
注意上面的幾件事:
這不是 HTML 代碼。比如,我們?nèi)匀豢梢允褂?className 代替 class。
我們?nèi)栽诳紤]怎樣讓上述的 JavaScript 看起來像是 HTML??匆幌挛以谧詈笫窃鯓犹砑拥?。
我們在上面(例 4)中寫的就是 JSX。然而,我們要將編譯后的版本(例 3)給瀏覽器。要做到這一點(diǎn),我們需要使用一個(gè)預(yù)處理器將 JSX 版本轉(zhuǎn)換為 React.createElement 版本。
這就是 JSX。這是一種折中的方案,允許我們用類似 HTML 的語法來編寫我們的 React 組件,這是一個(gè)很好的方法。
“Flux” 在頭部作為韻腳來使用,但它也是一個(gè)非常受歡迎的 應(yīng)用架構(gòu),由 Facebook 推廣。最出名的是 Redux,F(xiàn)lux 和 React 非常合適。
JSX,可以單獨(dú)使用,不僅僅適用于 React。
3 你可以在 JavaScript 的任何地方使用 JSX
在 JSX 中,你可以在一對花括號(hào)內(nèi)使用任何 JavaScript 表達(dá)式。
const?RandomValue?=?()?=>?<div> ?{?Math.floor(Math.random()?*?100)?} ?</div>; //?使用: ReactDOM.render(<RandomValue?/>,?mountNode);復(fù)制代碼
例 5:在 JSX 中使用 JavaScript 表達(dá)式
任何 JavaScript 表達(dá)式可以直接放在花括號(hào)中。這相當(dāng)于在 JavaScript 中插入 ${} 模板。
這是 JSX 內(nèi)唯一的約束:只有表達(dá)式。例如,你不能使用 if 語句,但三元表達(dá)式是可以的。
JavaScript 變量也是表達(dá)式,所以當(dāng)組件接受屬性列表時(shí)(不包括 RandomValue 組件,props 是可選擇的),你可以在花括號(hào)里使用這些屬性。我們在上述(例 1)的 Button 組件是這樣使用的。
JavaScript 對象也是表達(dá)式。有些時(shí)候我們在花括號(hào)中使用 JavaScript 對象,這看起來像是使用了兩個(gè)花括號(hào),但是在花括號(hào)中確實(shí)只有一個(gè)對象。其中一個(gè)用例就是將 CSS 樣式對象傳遞給響應(yīng)中的特殊樣式屬性:
const?ErrorDisplay?=?({message})?=>?<div?style={?{?color:?'red',?backgroundColor:?'yellow'?}?}>?{message} ?</div>; //?使用 ReactDOM.render(?<ErrorDisplay ?message="These?aren't?the?droids?you're?looking?for" ?/>, ?mountNode );復(fù)制代碼
例 6:一個(gè)對象傳遞特殊的 React 樣式參數(shù)
注意我解構(gòu)的只是在屬性參數(shù)之外的信息。這只是 JavaScript。還要注意上面的樣式屬性是一個(gè)特殊的屬性(同樣,它不是 HTML,它更接近 DOM API)。我們使用一個(gè)對象作為樣式屬性的值并且這個(gè)對象定義樣式就像我們使用 JavaScript 那樣(我們可以這樣做)。
你可以在 JSX 中使用 React 元素。因?yàn)檫@也是一個(gè)表達(dá)式(記住,一個(gè) React 元素只是一個(gè)函數(shù)調(diào)用):
const?MaybeError?=?({errorMessage})?=>?<div> ?{errorMessage?&&?<ErrorDisplay?message={errorMessage}?/>}?</div>; //?MaybeError?組件使用?ErrorDisplay?組件 const?ErrorDisplay?=?({message})?=>?<div?style={?{?color:?'red',?backgroundColor:?'yellow'?}?}>?{message} ?</div>; //?現(xiàn)在我們使用?MaybeError?組件: ReactDOM.render(?<MaybeError ?errorMessage={Math.random()?>?0.5???'Not?good'?:?''} ?/>, ?mountNode );復(fù)制代碼
例 7:一個(gè) React 元素是一個(gè)可以通過 {} 使用的表達(dá)式
上述 MaybeError 組件只會(huì)在有 errorMessage 傳入或者另外有一個(gè)空的 div 才會(huì)顯示 ErrorDisplay 組件。React 認(rèn)為 {true}、 {false}
{undefined} 和 {null} 是有效元素,不呈現(xiàn)任何內(nèi)容。
我們也可以在 JSX 中使用所有的 JavaScript 的集合方法(map、reduce 、filter、 concat 等)。因?yàn)樗麄兎祷氐囊彩潜磉_(dá)式:
const?Doubler?=?({value=[1,?2,?3]})?=>?<div> ?{value.map(e?=>?e?*?2)} ?</div>; //?使用下面內(nèi)容? ReactDOM.render(<Doubler?/>,?mountNode);復(fù)制代碼
例 8:在 {} 中使用數(shù)組
請注意我是如何給出上述 value 屬性的默認(rèn)值的,因?yàn)檫@全部都只是 JavaScript。注意我只是在 div 中輸出一個(gè)數(shù)組表達(dá)式。React 是完全可以的。它只會(huì)在文本節(jié)點(diǎn)中放置每一個(gè)加倍的值。
4 你可以使用 JavaScript 類寫 React 組件
簡單的函數(shù)組件非常適合簡單的需求,但是有的時(shí)候我們需要的更多。React 也支持通過使用 JavaScript 類來創(chuàng)建組件。這里 Button 組件(在例 1 中)就是使用類的語法編寫的。
class?Button?extends?React.Component?{ ?render()?{?return?<button>{this.props.label}</button>; ?} }//?使用(相同的語法)ReactDOM.render(<Button?label="Save"?/>,?mountNode);復(fù)制代碼
例 9:使用 JavaScript 類創(chuàng)建組件
類的語法是非常簡單的:定義一個(gè)擴(kuò)展的 React.Component 類(另一個(gè)你需要學(xué)習(xí)的 React 的頂級 API)。該類定義了一個(gè)單一的實(shí)例函數(shù) —— render(),并使函數(shù)返回虛擬 DOM 對象。每一次我們使用基于類的 Button 組件(例如,通過 <Button ... />),React 將從這個(gè)基于類的組件中實(shí)例化對象,并在 DOM 樹中使用該對象。
這就是為什么上面的例子中我們可以在 JSX 中使用 this.props.label 渲染輸出的原因,因?yàn)槊恳粋€(gè)組件都有一個(gè)特殊的稱為 props 的?實(shí)例?屬性,這讓所有的值傳遞給該組件時(shí)被實(shí)例化。
由于我們有一個(gè)與組件的單個(gè)使用相關(guān)聯(lián)的實(shí)例,所以我們可以按照自己的意愿定制該實(shí)例。例如,我們可以通過使用常規(guī) JavaScript 構(gòu)造函數(shù)來構(gòu)造它:
class?Button?extends?React.Component?{ ?constructor(props)?{?super(props);?this.id?=?Date.now(); ?} ?render()?{?return?<button?id={this.id}>{this.props.label}</button>; ?} }//?使用ReactDOM.render(<Button?label="Save"?/>,?mountNode);復(fù)制代碼
例 10:自定義組件實(shí)例
我們也可以定義類的原型并且在任何我們希望的地方使用,包括在返回的 JSX 輸出的內(nèi)部:
class?Button?extends?React.Component?{ ?clickCounter?=?0; ?handleClick?=?()?=>?{ ?console.log(`Clicked:?${++this.clickCounter}`); ?}; ?render()?{?return?( ?<button?id={this.id}?onClick={this.handleClick}> ?{this.props.label} ?</button> ?); ?} }//?使用ReactDOM.render(<Button?label="Save"?/>,?mountNode);復(fù)制代碼
例 11:使用類的屬性(通過單擊保存按鈕進(jìn)行測試)
注意上述例 11 中的幾件事情
handleClick 函數(shù)使用 JavaScript 新提出的 class-field syntax 語法。這仍然是 stage-2,但是這是訪問組件安裝實(shí)例(感謝箭頭函數(shù))最好的選擇(因?yàn)楹芏嘣颍?。然而,你需要使用類?Babel 的編譯器解碼為 stage-2(或者僅僅是類字段語法)來讓上述代碼工作。 jsComplete REPL 有預(yù)編譯功能。
//?錯(cuò)誤:onClick={this.handleClick()}//?正確:onClick={this.handleClick}復(fù)制代碼
5 React 中的事件:兩個(gè)重要的區(qū)別
當(dāng)處理 React 元素中的事件時(shí),我們與 DOM API 的處理方式有兩個(gè)非常重要的區(qū)別:
所有 React 元素屬性(包括事件)都使用?camelCase?命名,而不是?lowercase。例如是 onClick 而不是 onclick。
我們將實(shí)際的 JavaScript 函數(shù)引用傳遞給事件處理程序,而不是字符串。例如是 onClick={handleClick} 而不是 onClick="handleClick"。
React 用自己的對象包裝 DOM 對象事件以優(yōu)化事件處理的性能,但是在事件處理程序內(nèi)部,我們?nèi)匀豢梢栽L問 DOM 對象上所有可以訪問的方法。React 將經(jīng)過包裝的事件對象傳遞給每個(gè)調(diào)用函數(shù)。例如,為了防止表單提交默認(rèn)提交操作,你可以這樣做:
class?Form?extends?React.Component?{ ?handleSubmit?=?(event)?=>?{ ?event.preventDefault(); ?console.log('Form?submitted'); ?}; ?render()?{?return?( ?<form?onSubmit={this.handleSubmit}> ?<button?type="submit">Submit</button> ?</form> ?); ?} }//?使用ReactDOM.render(<Form?/>,?mountNode);復(fù)制代碼
例 12:使用包裝過的對象
6 每一個(gè) React 組件都有一個(gè)故事:第 1 部分
以下僅適用于類組件(擴(kuò)展 React.Component)。函數(shù)組件有一個(gè)稍微不同的故事。
首先,我們定義了一個(gè)模板來創(chuàng)建組件中的元素。
然后,我們在某處使用 React。例如,在 render 內(nèi)部調(diào)用其他的組件,或者直接使用 ReactDOM.render。
然后,React 實(shí)例化一個(gè)對象然后給它設(shè)置?props?然后我們可以通過 this.props 訪問。這些屬性都是我們在第 2 步傳入的。
因?yàn)檫@些全部都是 JavaScript,constructor 方法將會(huì)被調(diào)用(如果定義的話)。這是我們稱之為的第一個(gè):組件生命周期方法。
接下來 React 計(jì)算渲染之后的輸出方法(虛擬 DOM 節(jié)點(diǎn))。
因?yàn)檫@是 React 第一次渲染元素,React 將會(huì)與瀏覽器連通(代表我們使用 DOM API)來顯示元素。這整個(gè)過程稱為?mounting。
接下來 React 調(diào)用另一個(gè)生命周期函數(shù),稱為 componentDidMount。我們可以這樣使用這個(gè)方法,例如:在 DOM 上做一些我們現(xiàn)在知道的在瀏覽器中存在的東西。在此生命周期方法之前,我們使用的 DOM 都是虛擬的。
一些組件的故事到此結(jié)束,其他組件得到卸載瀏覽器 DOM 中的各種原因。在后一種情況發(fā)生時(shí),會(huì)調(diào)用另一個(gè)生命周期的方法,componentWillUnmount。
任何 mounted 的元素的狀態(tài)都可能會(huì)改變。該元素的父級可能會(huì)重新渲染。無論哪種情況,mounted 的元素都可能接收到不同的屬性集。React 的魔力就是這兒,我們實(shí)際上需要的正是 React 的這一點(diǎn)!在這一點(diǎn)之前,說實(shí)話,我們并不需要 React。
組價(jià)的故事還在繼續(xù),但是在此之前,我們需要理解我所說的這種狀態(tài)。
7 React 組件可以具有私有狀態(tài)
以下只適用于類組件。我有沒有提到有人叫表象而已的部件?dumb?
狀態(tài)類是任何 React 類組件中的一個(gè)特殊字段。React 檢測每一個(gè)組件狀態(tài)的變化,但是為了 React 更加有效,我們必須通過 React 的另一個(gè) API 改變狀態(tài)字段,這就是我們要學(xué)習(xí)的另一個(gè) API —— this.setState:
class?CounterButton?extends?React.Component?{ ?state?=?{?clickCounter:?0,?currentTimestamp:?new?Date(), ?}; ?handleClick?=?()?=>?{?this.setState((prevState)?=>?{?return?{?clickCounter:?prevState.clickCounter?+?1?}; ?}); ?}; ?componentDidMount()?{ ?setInterval(()?=>?{?this.setState({?currentTimestamp:?new?Date()?}) ?},?1000); ?} ?render()?{?return?(?<div> ?<button?onClick={this.handleClick}>Click</button> ?<p>Clicked:?{this.state.clickCounter}</p> ?<p>Time:?{this.state.currentTimestamp.toLocaleString()}</p> ?</div> ?); ?} }//?使用ReactDOM.render(<CounterButton?/>,?mountNode);復(fù)制代碼
例 13:setState 的 API
這可能是最重要的一個(gè)例子因?yàn)檫@將是你完全理解 React 基礎(chǔ)知識(shí)的方式。這個(gè)例子之后,還有一些小事情需要學(xué)習(xí),但從那時(shí)起主要是你和你的 JavaScript 技能。
讓我們來看一下例 13,從類開始,總共有兩個(gè),一個(gè)是一個(gè)初始化的有初始值為 0 的 clickCounter 對象和一個(gè)從 new Date() 開始的 currentTimestamp。
另一個(gè)類是 handleClick 函數(shù),在渲染方法中我們給按鈕元素傳入 onClick 事件。通過使用 setState 的 handleClick 方法修改了組件的實(shí)例狀態(tài)。要注意到這一點(diǎn)。
另一個(gè)我們修改狀態(tài)的地方是在一個(gè)內(nèi)部的定時(shí)器,開始在內(nèi)部的 componentDidMount 生命周期方法。它每秒鐘調(diào)用一次并且執(zhí)行另一個(gè)函數(shù)調(diào)用 this.setState。
在渲染方法中,我們使用具有正常讀語法的狀態(tài)上的兩個(gè)屬性(沒有專門的 API)。
現(xiàn)在,注意我們更新狀態(tài)使用兩種不同的方式:
通過傳入一個(gè)函數(shù)然后返回一個(gè)對象。我們在 handleClick 函數(shù)內(nèi)部這樣做。
通過傳入一個(gè)正則對象,我們在在區(qū)間回調(diào)中這樣做。
這兩種方式都是可以接受的,但是當(dāng)你同時(shí)讀寫狀態(tài)時(shí),第一種方法是首選的(我們這樣做)。在區(qū)間回調(diào)中,我們只向狀態(tài)寫入而不讀它。當(dāng)有問題時(shí),總是使用第一個(gè)函數(shù)作為參數(shù)語法。伴隨著競爭條件這更安全,因?yàn)?setstate 實(shí)際上是一個(gè)異步方法。
我們應(yīng)該怎樣更新狀態(tài)呢?我們返回一個(gè)有我們想要更新的的值的對象。注意,在調(diào)用 setState 時(shí),我們?nèi)慷紡臓顟B(tài)中傳入一個(gè)屬性或者全都不。這完全是可以的因?yàn)?setState 實(shí)際上?合并?了你通過它(返回值的函數(shù)參數(shù))與現(xiàn)有的狀態(tài),所以,沒有指定一個(gè)屬性在調(diào)用 setState 時(shí)意味著我們不希望改變屬性(但不刪除它)。
8 React 將要反應(yīng)
React 的名字是從狀態(tài)改變的反應(yīng)中得來的(雖然沒有反應(yīng),但也是在一個(gè)時(shí)間表中)。這里有一個(gè)笑話,React 應(yīng)該被命名為Schedule!
然而,當(dāng)任何組件的狀態(tài)被更新時(shí),我們用肉眼觀察到的是對該更新的反應(yīng),并自動(dòng)反映了瀏覽器 DOM 中的更新(如果需要的話)。
將渲染函數(shù)的輸入視為兩種:
通過父元素傳入的屬性
以及可以隨時(shí)更新的內(nèi)部私有狀態(tài)
當(dāng)渲染函數(shù)的輸入改變時(shí),輸出可能也會(huì)改變。
React 保存了渲染的歷史記錄,當(dāng)它看到一個(gè)渲染與前一個(gè)不同時(shí),它將計(jì)算它們之間的差異,并將其有效地轉(zhuǎn)換為在 DOM 中執(zhí)行的實(shí)際 DOM 操作。
9 React 是你的代碼
您可以將 React 看作是我們用來與瀏覽器通信的代理。以上面的當(dāng)前時(shí)間戳顯示為例。取代每一秒我們都需要手動(dòng)去瀏覽器調(diào)用 DOM API 操作來查找和更新 p#timestamp 元素,我們僅僅改變組件的狀態(tài)屬性,React 做的工作代表我們與瀏覽器的通信。我相信這就是為什么 React 這么受歡迎的真正原因;我們只是不喜歡和瀏覽器先生談話(以及它所說的 DOM 語言的很多方言),并且 React 自愿傳遞給我們,免費(fèi)的!
10 每一個(gè) React 組件都有一個(gè)故事:第 2 部分
現(xiàn)在我們知道了一個(gè)組件的狀態(tài),當(dāng)該狀態(tài)發(fā)生變化的時(shí)候,我們來了解一下關(guān)于這個(gè)過程的最后幾個(gè)概念。
當(dāng)組件的狀態(tài)被更新時(shí),或者它的父進(jìn)程決定更改它傳遞給組件的屬性時(shí),組件可能需要重新渲染。
如果后者發(fā)生,React 會(huì)調(diào)用另一個(gè)生命周期方法:componentWillReceiveProps。
如果狀態(tài)對象或傳遞的屬性改變了,React 有一個(gè)重要的決定要做:組件是否應(yīng)該在 DOM 中更新?這就是為什么它調(diào)用另一個(gè)重要的生命周期方法 shouldComponentUpdate 的原因 。此方法是一個(gè)實(shí)際問題,因此,如果需要自行定制或優(yōu)化渲染過程,則必須通過返回 true 或 false 來回答這個(gè)問題。
如果沒有自定義 shouldComponentUpdate,React 的默認(rèn)事件在大多數(shù)情況下都能處理的很好。
首先,這個(gè)時(shí)候會(huì)調(diào)用另一生命周期的方法:componentWillUpdate。然后,React 將計(jì)算新渲染過的輸出,并將其與最后渲染的輸出進(jìn)行對比。
如果渲染過的輸出和之前的相同,React 不進(jìn)行處理(不需要和瀏覽器先生對話)。
如果有不同的地方,React 將不同傳達(dá)給瀏覽器,像我們之前看到的那樣。
在任何情況下,一旦一個(gè)更新程序發(fā)生了,無論以何種方式(即使有相同的輸出),React 會(huì)調(diào)用最后的生命周期方法:componentDidUpdate。
生命周期方法是逃生艙口。如果你沒有做什么特別的事情,你可以在沒有它們的情況下創(chuàng)建完整的應(yīng)用程序。它們非常方便地分析應(yīng)用程序中正在發(fā)生的事情,并進(jìn)一步優(yōu)化 React 更新的性能。
感謝閱讀。如果您覺得這篇文章有幫助,請點(diǎn)擊下面的 。請關(guān)注我的更多關(guān)于 React.js 和 JavaScript 的文章。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。