摘要:對(duì)于最開(kāi)始關(guān)注的是的初始化以及在哪里請(qǐng)求。在進(jìn)行初始化,推薦在中進(jìn)行請(qǐng)求。是在組件即將被卸載前一刻的鉤子,一般用于取消中訂閱的事件等作用,清理一些不要的變量等,避免內(nèi)存泄漏。第二條的原因額,說(shuō)好的更新才調(diào),初始化不調(diào)用是符合邏輯的。
前言
在上篇文章React 導(dǎo)讀(一)中學(xué)習(xí)到了寫(xiě)第一個(gè) Web 組件,這篇文章將繼續(xù)之前的目錄,開(kāi)始新的知識(shí)點(diǎn)補(bǔ)充:
[x] React 如何編寫(xiě) Hello World!
[x] React 中三個(gè)最基礎(chǔ)、最重要的東西
[x] React 中的 JSX
[x] 你的第一個(gè) Web 組件
[ ]React 中最開(kāi)始需要關(guān)注的生命周期
[ ]React 一個(gè)組件集合的簡(jiǎn)單交互
[ ]React 開(kāi)始一個(gè)項(xiàng)目的一點(diǎn)建議
[ ]React 簡(jiǎn)單的項(xiàng)目結(jié)構(gòu)組織
五、React 中最開(kāi)始需要關(guān)注的生命周期其實(shí)在學(xué)習(xí) React 之前,就應(yīng)該了解目前前端推薦的是組件化開(kāi)發(fā)的方式,React 是讓組件化更加簡(jiǎn)單的庫(kù)。那么組件開(kāi)發(fā)必不可少的就是生命周期,說(shuō)直白一點(diǎn)就是運(yùn)行組件的過(guò)程是 React 來(lái)做,運(yùn)行過(guò)程中需要有一些代碼鉤子來(lái)讓我們?nèi)フ{(diào)用,在組件執(zhí)行的某一個(gè)地方去執(zhí)行我們自己寫(xiě)的代碼。這里先介紹擁有的生命周期鉤子,下面的方法 constructor 和 render 不屬于生命周期,我按功能分類了一下,也就是學(xué)習(xí)的時(shí)候不一定要按部就班,應(yīng)該以學(xué)習(xí)之后能真正寫(xiě)一些東西為目標(biāo):
(1) 與組件掛載相關(guān)的方法,包括構(gòu)造函數(shù)
constructor
componentWillMount
componentDidMount
componentWillUnmount
最常用的生命周期應(yīng)該是最后 2 個(gè),constructor 和 componentWillMount 目前先理解成能滿足的功能大體相同,如果這里解釋太復(fù)雜不太好。
對(duì)于最開(kāi)始關(guān)注的是:this.state 的初始化以及 ajax 在哪里請(qǐng)求。
this.state 在 constructor 進(jìn)行初始化,ajax 推薦在 componentDidMount 中進(jìn)行請(qǐng)求。
componentDidMount 就是在組件已經(jīng)掛載到 DOM 中后的鉤子,可以理解為 jQuery 中提供的 ready 方法。
componentWillUnmount 是在組件即將被卸載前一刻的鉤子,一般用于取消 componentDidMount 中訂閱的事件等作用,清理一些不要的變量等,避免內(nèi)存泄漏。
下面通過(guò)一個(gè)簡(jiǎn)單的例子說(shuō)明一下:
先有一個(gè) foods.json 文件來(lái)模擬請(qǐng)求的后臺(tái)數(shù)據(jù)。
[ { "id": 1, "name": "香蕉" }, { "id": 2, "name": "蘋(píng)果" }, { "id": 3, "name": "獼猴桃" } ]
// 1. 掛載相關(guān)的生命周期 class CycleMount extends React.Component { constructor() { super(); this.state = { foods: [] }; console.log("1. constructor 執(zhí)行了..."); } componentDidMount() { // 這里使用原生的 fetch API 進(jìn)行 ajax 請(qǐng)求,你也可以使用 $.ajax 進(jìn)行請(qǐng)求,原理是一樣的,重點(diǎn)是關(guān)注 setState 的地方 fetch("/mock/foods.json", { method: "GET", headers: new Headers({ "Accept": "application/json" }) } ).then(dataResult => { if(dataResult.status === 200) { return dataResult.json(); } else { return []; } }).then(data => { // 這里的 data 就是 foods.json 里面的數(shù)據(jù) // 調(diào)用 setState 來(lái)更新 render 里面調(diào)用的 this.state 的值 this.setState({ foods: data }); }); console.log("2. componentDidMount 執(zhí)行了..."); } render() { // foods 是一個(gè)數(shù)組,map 方法是數(shù)組自帶的方法,可以查詢相關(guān) api const foodItems = this.state.foods.map(food => { return (
上面有了完整的注釋,也能看到基本上項(xiàng)目中可能會(huì)將代碼寫(xiě)到何處,我也打了兩個(gè)日志,來(lái)識(shí)別到底是誰(shuí)先執(zhí)行,結(jié)果可以自己運(yùn)行一下,執(zhí)行順序就是我標(biāo)記的1,2。
好了,基本的學(xué)習(xí)了,可以自己動(dòng)手試試訂閱一個(gè)事件,然后在卸載的時(shí)候取消這個(gè)事件。
(2) 優(yōu)化相關(guān)
shouldComponentUpdate
這個(gè)方法比較重要,但是我這里不會(huì)介紹得太過(guò)于復(fù)雜,太復(fù)雜只會(huì)讓重要的部分不那么突出。這個(gè)方法的返回值是一個(gè) boolean 類型,分別代碼的意義:
true 組件應(yīng)該更新,執(zhí)行 render 方法以及相關(guān)生命周期;
false 組件狀態(tài)沒(méi)有更新,不執(zhí)行 render 等方法,意味著網(wǎng)頁(yè)界面不會(huì)改變。
那么它直觀上的作用是能夠通過(guò)返回值來(lái)決定界面是否改變,實(shí)際的意義就是當(dāng)我們知道當(dāng)前 oldState = this.state 的值和新的 newState = this.state 值完全相等的時(shí)候(或者是新傳入的 props)就不用再浪費(fèi)性能去重新渲染組件了。
API 上的定義是這樣的:
/* nextProps: 新的 props, nextState: 新的 state */ shouldComponentUpdate(nextProps, nextState): boolean
舉個(gè)例子來(lái)直觀說(shuō)明一下:
class ComponentOptimize extends React.Component { state = { count: 0 }; shouldComponentUpdate(nextProps, nextState) { // 當(dāng) count > 10 的時(shí)候就不能再重新渲染組件了 if(nextState.count > 10) { return false; } return true; } handleUpdateCount() { console.log("我點(diǎn)了一下哦!"); this.setState(prevState => { return { count: prevState.count + 1 }; }); } render() { return (); } }{this.state.count}
你會(huì)發(fā)現(xiàn) 10 過(guò)后界面就沒(méi)有再更新過(guò)了,這樣應(yīng)該很直觀了。
(3) Props 相關(guān)的生命周期
componentWillReceiveProps
這個(gè)主要是在組件的 props 傳入新的值后被調(diào)用,不管是不是傳的一樣的值或者 shouldComponentUpdate 返回了 false,看下例子吧:
class Cat extends React.Component { componentWillReceiveProps(nextProps) { console.log("改一次我執(zhí)行一次!"); } shouldComponentUpdate(nextProps, nextState) { // 改的名字一樣的時(shí)候 return this.props.name !== nextProps.name; } render() { console.log("貓改了一次名字!"); return (我有新名字了!{this.props.name}
); } } class App extends React.Component { state = { catName: "嚕嚕" }; handleChangeCatName() { const catNames = ["嚕嚕", "小白", "小黃", "小黑", "皮卡丘"]; const catIndex = this.getSomeOneIndex(); this.setState({ catName: catNames[catIndex] }); } getSomeOneIndex() { return Math.floor(Math.random() * 5 + 0); } render() { return ({/* 給 Cat 傳新的名字 */}); } }
最后肯定每次點(diǎn)擊按鈕都會(huì)輸出這句的結(jié)果 console.log("改一次我執(zhí)行一次!");。
(4) 更新組件相關(guān)
componentWillUpdate
componentDidUpdate
因?yàn)槎际侵v解 API,所以國(guó)際慣例的先看下 API 的定義吧:
// 組件更新前執(zhí)行 componentWillUpdate(nextProps, nextState) // 組件更新后執(zhí)行 componentDidUpdate(prevProps, prevState)
可以從定義中看出,它們都接受了兩個(gè)參數(shù):props && state,不過(guò)看變量前綴能夠聯(lián)想點(diǎn)什么。
暫時(shí)想不到什么實(shí)際項(xiàng)目的例子,隨便假設(shè)點(diǎn)內(nèi)容吧。不過(guò)這里需要注意的地方是:
1. 這兩個(gè)方法里面都不要調(diào)用 setState!
2. 第一次初始化組件 render 的時(shí)候不會(huì)執(zhí)行
3. shouldComponentUpdate 返回 false 不會(huì)執(zhí)行
第一條的原因:容易形成一個(gè)遞歸的調(diào)用,不作就不會(huì)死...所以盡量不要在這里調(diào)~目前還沒(méi)有碰到需要在這里調(diào)的需求。
第二條的原因:額,說(shuō)好的更新才調(diào),初始化不調(diào)用是符合邏輯的。
第三條的原因:額,這 2 個(gè)鉤子是與組件更新相關(guān)的,所以也符合邏輯的,組件是否更新就是靠 shouldComponentUpdate 返回值。
在上面 Cat 的例子中加入下面的代碼可以看下結(jié)果:
componentWillUpdate() { console.log("componentWillUpdate 執(zhí)行了!") } componentDidUpdate() { console.log("componentDidUpdate 執(zhí)行了!") }
(5)組件錯(cuò)誤
componentDidCatch
就是在組件發(fā)生異常的時(shí)候可能會(huì)被調(diào)用的鉤子,需要注意的有下面的地方:
只能在父級(jí)組件捕獲子組件的異常;
如果異常被 try...catch 包裹父級(jí)組件的鉤子就不會(huì)執(zhí)行了。
看個(gè)例子吧:
class Cat extends React.Component { componentWillReceiveProps(nextProps) { // 這里手動(dòng)拋一個(gè)異常,觸發(fā)我們的鉤子 componentDidCatch throw new Error("miao miao~"); } render() { let miao = this.props.name; return ({miao}); } } class App extends React.Component { state = { catName: "嚕嚕", isError: false, }; handleChangeCatName() { const catNames = ["嚕嚕", "小白", "小黃", "小黑", "皮卡丘"]; const catIndex = this.getSomeOneIndex(); this.setState({ catName: catNames[catIndex] }); } getSomeOneIndex() { return Math.floor(Math.random() * 5 + 0); } componentDidCatch(error, info) { console.log(error, info); if(error) { // 如果有錯(cuò)誤信息,就重新渲染一下組件,可能是更好的交互 this.setState({ isError: true }); } } render() { return (); } }{!this.state.isError ? : 不要奴才給我取名字了!
}
(6) 渲染相關(guān)
render
額...這個(gè)不想寫(xiě)了,先睡覺(jué)吧~應(yīng)該寫(xiě)了這么多個(gè)小例子也差不多了~可以動(dòng)手試試哦!還不清楚的可以 Google 一下,你就知道。
生命周期很重要,其實(shí)學(xué)到這里也差不多可以上手寫(xiě)點(diǎn)項(xiàng)目熟練一下了,其他的更多是思維和編程方面的東西,周期的篇幅多帶帶來(lái)一篇吧~其他主題之后再繼續(xù)吧!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/93570.html
摘要:一前言在導(dǎo)讀三中介紹了項(xiàng)目的背景功能需求項(xiàng)目結(jié)構(gòu)以及組件的劃分層次,接下來(lái)我們就來(lái)看下實(shí)際的代碼,這一篇文章會(huì)主要分享用到的基礎(chǔ)組件的封裝。 一、前言 在 React 導(dǎo)讀(三) 中介紹了項(xiàng)目的背景、功能需求、項(xiàng)目結(jié)構(gòu)以及組件的劃分層次,接下來(lái)我們就來(lái)看下實(shí)際的代碼,這一篇文章會(huì)主要分享用到的基礎(chǔ)組件的封裝。 二、基礎(chǔ)組件設(shè)計(jì) 我們?cè)谠O(shè)計(jì)組件之前本來(lái)是有一個(gè)流程和過(guò)程的,這里我寫(xiě)的組件...
摘要:需要有一定的基礎(chǔ)和的使用經(jīng)驗(yàn)。這就是屬性的作用。方法接收一個(gè)新對(duì)象來(lái)重新賦值。也接收一個(gè)函數(shù),這個(gè)回調(diào)函數(shù)這里我默認(rèn)有一個(gè)參數(shù),表示之前的的值,這個(gè)函數(shù)的返回值就是最新的。但是不同的是在組件內(nèi)部是只讀的。 前言 寫(xiě)這篇文章的主要目標(biāo)是讓初學(xué)者更快的上手 React 的項(xiàng)目開(kāi)發(fā),能有一個(gè)循循漸進(jìn)的理解過(guò)程。需要有一定的 JavaScript 基礎(chǔ)和 NPM 的使用經(jīng)驗(yàn)。不多說(shuō)了,下面會(huì)按...
摘要:場(chǎng)景為了更清晰的安排年前年后的工作和值班,現(xiàn)在要對(duì)過(guò)年期間人員請(qǐng)假的情況進(jìn)行統(tǒng)計(jì),并且進(jìn)行一個(gè)簡(jiǎn)單的管理。我們現(xiàn)在來(lái)訂閱一個(gè)名為的事件,用來(lái)表示表格中需要展示每條數(shù)據(jù)。 前言 React 導(dǎo)讀(一)React 導(dǎo)讀(二) 在之前 2 篇文章中中學(xué)習(xí)到了寫(xiě)第一個(gè) Web 組件以及常用的生命周期函數(shù)的使用,這篇文章將繼續(xù)之前的目錄,開(kāi)始新的知識(shí)點(diǎn)補(bǔ)充: [x] React 如何編寫(xiě) He...
摘要:最近買了深入理解的書(shū)籍來(lái)看,為什么學(xué)習(xí)這么久還要買這本書(shū)呢主要是看到核心團(tuán)隊(duì)成員及的創(chuàng)造者為本書(shū)做了序,作為一個(gè)粉絲,還是挺看好這本書(shū)能給我?guī)?lái)一個(gè)新的升華,而且本書(shū)的作者也非常厲害。 使用ES6開(kāi)發(fā)已經(jīng)有1年多了,以前看的是阮一峰老師的ES6教程,也看過(guò)MDN文檔的ES6語(yǔ)法介紹。 最近買了《深入理解ES6》的書(shū)籍來(lái)看,為什么學(xué)習(xí)ES6這么久還要買這本書(shū)呢?主要是看到Daniel A...
閱讀 3077·2021-11-18 10:07
閱讀 3853·2021-11-17 17:00
閱讀 2166·2021-11-15 18:01
閱讀 986·2021-10-11 10:58
閱讀 3503·2021-09-10 10:50
閱讀 3675·2021-08-13 15:05
閱讀 1279·2019-08-30 15:53
閱讀 2710·2019-08-29 13:01