一缎罢、props
1崇棠、什么是props?
定義:props是父子組件之間通信的紐帶哆档,它表示的是父組件傳遞過(guò)來(lái)的自定義屬性和children插佛。
props是一個(gè)對(duì)象,通過(guò)props可以訪問(wèn)到父組件傳遞過(guò)來(lái)的自定義屬性和children。
props是只讀的(不能修改它)
通過(guò)props渡讼,可以向子組件傳遞ReactNode(ReactElement混驰、基本數(shù)據(jù)類型、數(shù)組映皆、JSX對(duì)象)、普通對(duì)象、函數(shù)等韧衣。
2假残、React的兩種組件
什么組件?組件就是一個(gè)段可以被復(fù)用的代碼塊抹竹。組件化的意義:封裝、快速開發(fā)。
進(jìn)一步理解組件:組件實(shí)際就是一個(gè)“函數(shù)”痢艺,它接收props作為入?yún)⒒粒祷赜糜谝晥D渲染的JSX元素。因?yàn)閜rops是只讀的喳整,所以每一個(gè)React組件都是一個(gè)“純函數(shù)”。(什么是純函數(shù)?入?yún)⒉荒芨模o相同入?yún)r(shí)總是返回唯一的結(jié)果躬充。)
提示:雖然props不能修改,但可以參與業(yè)務(wù)邏輯運(yùn)算。
(一)函數(shù)式組件(無(wú)狀態(tài)組件)
const Hello = (props) => (<div></div>)
特點(diǎn):它只有props梳杏,沒有state狀態(tài),也沒有this斑鸦、生命周期诫钓、ref场梆、上下文等特性。所以它的性能較好。
提示:自 React v16.8 以后端逼,我們可以通過(guò) Hooks API 來(lái)模擬上述缺失的React特性而昨。
(二)類組件(有狀態(tài)組件)
class Hello extends React.Component { // this.props }
特點(diǎn):它有props漆改,也有state狀態(tài)唆铐、this、生命周期筛婉、ref、上下文等特性粱栖。相對(duì)于函數(shù)式組件其性能較差。
提示:自 React v16.8 以后渠退,類組件越來(lái)越少使用了≈ぞ牛現(xiàn)在市場(chǎng)中主流是Hooks+函數(shù)式組件猜惋。
3私股、父子組件
什么是 props.children 偿曙?它代表是自定義組件內(nèi)部所嵌套的ReactNode列表。
在自定義屬性時(shí)喧笔,不要把屬性名命名為 children牌借,因?yàn)樗刑厥夂x晒旅。
在props.children向子組件傳遞children時(shí)硕淑,建議傳遞ReactNode列表寥袭,不要傳遞普通數(shù)據(jù)抓韩。如果要傳遞數(shù)據(jù),建議使用自定義props苍日。
4拦耐、父子組件通信:父?jìng)髯邮褂米远x屬性,子傳父通過(guò)自定義事件疗琉。(從Vue的角度來(lái)理解父子組件)
父組件給的props如果是“普通數(shù)據(jù)”坚俗,用于渲染恩闻、用于邏輯操作。
父組件給的props如果是“函數(shù)”剧董,在子組件中可調(diào)用并向父組件返回?cái)?shù)據(jù)幢尚。
父組件給的props如果“JSX對(duì)象”,在子組件中直接參與渲染翅楼。
5尉剩、props是“組件化(組合)”的語(yǔ)法基礎(chǔ)。
二毅臊、state
1理茎、描述
state 是React組件自身的數(shù)據(jù),具有“響應(yīng)式”的特性(當(dāng)state變量被this.setState()修改時(shí)管嬉,視圖會(huì)自動(dòng)更新)皂林。
這里的“響應(yīng)式”和vue響應(yīng)式是完全不同的,React中沒有“數(shù)據(jù)支持宠蚂、依賴收集”等工作式撼。
1、定義state
在類組件中才有state(函數(shù)式組件中沒有state)求厕,必須在constructor這個(gè)生命周期中定義state著隆。
state必須“先定義扰楼、再使用”。state變量一般是基本數(shù)據(jù)類型美浦、數(shù)組弦赖、普通對(duì)象。不能定義其它的數(shù)據(jù)類型浦辨。
2蹬竖、使用state
在類組件中,使用this.state來(lái)訪問(wèn)所有的state變量流酬。
3币厕、state的特點(diǎn)
當(dāng)使用this.setState()這個(gè)專屬方法來(lái)修改state時(shí),這會(huì)觸發(fā)render()運(yùn)行并返回新的“Fiber”芽腾,進(jìn)一步執(zhí)行“協(xié)調(diào)運(yùn)行”(找到最小化的臟節(jié)點(diǎn)集合)旦装,最后一次“提交”更新DOM。
state是當(dāng)前組件的“自有數(shù)據(jù)”摊滔,可以通過(guò)props傳遞給后代組件阴绢,但不能傳遞給父組件。這就是React中“單向數(shù)據(jù)流”(自上而下)艰躺。
4呻袭、如何優(yōu)雅地修改state變量?
修改state變量必須使用this.setState()這個(gè)專屬方法腺兴。不要直接修改state左电,因?yàn)橹苯有薷膕tate不會(huì)觸發(fā)render()。
每次修改state時(shí)都要考慮“新值與舊值是否有”页响,如果有關(guān)使用this.setState(fn,callback)這種語(yǔ)法券腔,如果無(wú)關(guān)使用this.setState({},callback)這種語(yǔ)法。
示例:this.setState({name:'GP8'}) this.setState(state=>({count:state.count+1}))
5拘泞、this.setState()異步性
在合成事件(on*開頭的系列事件、生命周期鉤子)中枕扫,this.setState()是異步的陪腌。
在微任務(wù)函數(shù)體中(Promise.then)中,this.setState()是同步的烟瞧。
在非合成事件中(定時(shí)器诗鸭、DOM事件)中,this.setState()是同步的参滴。
this.setState() 為什么默認(rèn)是異步强岸?
因?yàn)殚_發(fā)者在同一個(gè)“合成事件”中有可能多次調(diào)用this.setState(),如果它同步的砾赔,這會(huì)導(dǎo)致多次render()蝌箍,這顯然是一種性能損耗青灼。所以,React在設(shè)計(jì)this.setState()把它變成異步的妓盲,這樣的好處是更好保證this.setState()的淺合并杂拨,以節(jié)省性能。
什么是合成事件悯衬?
on*事件處理器弹沽、生命周期鉤子都是合成事件。合成事件是React官方專門封裝一組API筋粗,這些合成事件是“可控的”策橘,React就可以放心地把合成事件中的this.setState()變成異步的,目的是為了對(duì)多個(gè)this.setState()進(jìn)行淺合并娜亿,以節(jié)省性能丽已。
this.setState()在合成事件中是異步的。那我們?nèi)绾沃肋@個(gè)異步任務(wù)完成了暇唾?
方案一:this.setState(fn|{}, callback) 在callback被調(diào)用時(shí)就說(shuō)明這個(gè)異步工作完成了促脉。
方案二:componentDidUpdate() 當(dāng)這個(gè)生命周期被觸發(fā)時(shí),說(shuō)明這個(gè)異步工作完成了策州。
建議:React官方建議瘸味,方案二更靠譜,方案一盡量少用够挂。
測(cè)試this.setState()的同步性:在非合成事件中旁仿,它都是同步的。如果一定要給個(gè)解釋孽糖,React無(wú)法操控“非合成事件”枯冈,所以沒有辦法把this.setState()變成異步的,所以也不存在性能優(yōu)化办悟。
場(chǎng)景一:在定時(shí)器中尘奏,this.setState()是同步的。
場(chǎng)景二:用dom病蛉、ref的方式綁定事件炫加,在事件處理器中,this.setState()也是同步的铺然。
場(chǎng)景三:在new Promise().then()中俗孝,this.setState()是同步的。(異議:后面再用真實(shí)ajax測(cè)試)
6魄健、this.setState() 淺合并
理解:在同一個(gè)更新周期(合成事件)中赋铝,如果多次調(diào)用this.setState(),React會(huì)自動(dòng)將它們合并沽瘦,以節(jié)省性能革骨。
三农尖、事件
事件綁定原則:盡可能地使用合成事件來(lái)綁定事件。
合成事件:https://zh-hans.reactjs.org/docs/events.html
1苛蒲、如何綁定事件卤橄?
語(yǔ)法一:使用ES5的方式來(lái)綁定事件 onClick={this.handle.bind(this)}
語(yǔ)法二:使用ES6的方式來(lái)綁定事件 onClick={()=>this.handle()}
建議:使用“語(yǔ)法二”來(lái)綁定事件
2、如何拿到事件對(duì)象臂外?
ES5方式綁定事件窟扑,事件處理器的最后一個(gè)參數(shù)永遠(yuǎn)都事件對(duì)象。
ES6方式綁定事件漏健,需要手動(dòng)傳遞事件對(duì)象嚎货。
3、事件處理器如何自定義傳遞參數(shù)蔫浆?
ES5方式事件傳參殖属,onClick={this.handle.bind(this, 'arg', ...)}
ES6方式事件傳參,onClick={ev=>this.handle('arg', ev)}
4瓦盛、如何阻止冒泡洗显、默認(rèn)事件?
用事件對(duì)象的api來(lái)實(shí)現(xiàn)(二階段的知識(shí))
ev.stopPropagation()
ev.preventDefault()
5原环、如何監(jiān)聽鍵盤事件挠唆?
用事件對(duì)象的api來(lái)實(shí)現(xiàn)(二階段的知識(shí))?ev.keyCode
四、條件渲染
條件渲染:元素的顯示與隱藏嘱吗,這里巧用的都是JSX語(yǔ)法玄组。
1、單一元素的條件渲染
語(yǔ)法:{ bol && <jsx> }
2谒麦、兩個(gè)元素的條件渲染
語(yǔ)法: { bol ? <jsx1> : <jsx2> }
3俄讹、多個(gè)元素的條件渲染
語(yǔ)法:建議封裝“自定義的渲染函數(shù)” function renderThing() { return <jsx> }
4、動(dòng)態(tài)class
語(yǔ)法:className={'類名的拼接'}
5绕德、動(dòng)態(tài)style
語(yǔ)法:style={ css樣式的鍵值對(duì) }
五患膛、列表渲染
列表渲染:React官方建議使用map()進(jìn)行渲染
語(yǔ)法基礎(chǔ):JSX支持對(duì)數(shù)組的渲染。
為什么官方建議使用map()方法來(lái)實(shí)現(xiàn)列表渲染耻蛇?
語(yǔ)法:const newList = list.map(fn)剩瓶,
特點(diǎn):map()方法的特點(diǎn),對(duì)源數(shù)據(jù)進(jìn)行fn處理城丧,返回一個(gè)新的jsx數(shù)組。
六豌鹤、表單綁定
表單綁定:除了文件上傳以外亡哄,都要使用受控表單。
1布疙、兩類表單
受控表單蚊惯,表單/類表單的value或checked由state控制著愿卸。
非受控表單,表單/類表單的value或checked與state完全無(wú)關(guān)截型。
原則:除了文件上傳以外趴荸,所有表單都必須是受控表單。
對(duì)于普通文本表單宦焦、select表單发钝,用value屬性來(lái)受控,用onChange取值波闹。
對(duì)于radio/checkbox表單酝豪,用checked屬性來(lái)受控,用onChange取值精堕。
對(duì)于自定義的“類表單”孵淘,我們建議用自定義屬性value來(lái)受控,用自定義onChange取值歹篓。
2瘫证、表單的單向綁定
意思是在React中表單的取值操作必須手動(dòng)完成。
最佳實(shí)踐:當(dāng)頁(yè)面中表單特別多時(shí)庄撮,我們只封裝一個(gè)change handler來(lái)取所有表單的值背捌。也就是對(duì)change handler方法的復(fù)用。復(fù)用的方式有很多重窟,可以自定義dataset载萌、自定義事件傳參來(lái)實(shí)現(xiàn)。