1胶征、Component
React的首要思想是通過(guò)組件(Component)來(lái)開(kāi)發(fā)應(yīng)用。所謂組件,簡(jiǎn)單說(shuō),指的是能完成某個(gè)特功能的獨(dú)立的柠新、可重用的代碼。
基于組件的應(yīng)用開(kāi)發(fā)是廣泛使用的軟件開(kāi)發(fā)模式镰烧,用分而治之的方法把一個(gè)大的應(yīng)用分解成若干小的組件乔询,每個(gè)組件只關(guān)注于某個(gè)小范圍的特定功能,但是把組件組合起來(lái)逢倍,就能夠構(gòu)成一個(gè)功能龐大的應(yīng)用捧颅。如果分解功能的過(guò)程足夠巧妙,那么每個(gè)組件可以在不同場(chǎng)景下重用较雕,那樣不光可以構(gòu)建龐大的應(yīng)用隘道,還可以構(gòu)建出靈活的應(yīng)用。打個(gè)比方郎笆,每個(gè)組件是一塊磚谭梗,而一個(gè)應(yīng)用是一座樓,想要一次鍛造就創(chuàng)建一座樓是不現(xiàn)實(shí)的宛蚓。實(shí)際上激捏,總是先鍛造很多磚,通過(guò)排列組合這些磚凄吏,才能構(gòu)建偉大的建筑远舅。
任何一個(gè)復(fù)雜的應(yīng)用,都是由一個(gè)簡(jiǎn)單的應(yīng)用發(fā)展而來(lái)痕钢,當(dāng)應(yīng)用還很簡(jiǎn)單的時(shí)候图柏,因?yàn)楣δ芎苌伲赡苤挥幸粋€(gè)組件就足夠了任连,但是蚤吹,隨著功能的增加,把越來(lái)越多的功能放在一個(gè)組件中就會(huì)顯得臃腫和難以管理。
就和一個(gè)人最好一次只專(zhuān)注做一件事情一樣裁着,也應(yīng)該盡量保持一個(gè)組件只做一件事繁涂。當(dāng)開(kāi)發(fā)者發(fā)現(xiàn)一個(gè)組件功能太多代碼量太大的時(shí)候,就要考慮拆分這個(gè)組件二驰,用多個(gè)小的組件來(lái)代替扔罪。每個(gè)小的組件只關(guān)注實(shí)現(xiàn)單個(gè)功能,但是這些功能組合起來(lái)桶雀,也能滿足復(fù)雜的實(shí)際需求矿酵。
這就是“分而治之”的策略,把問(wèn)題分解為多個(gè)小問(wèn)題矗积,這樣即容易解決也方便維護(hù)坏瘩,雖然“分而治之”是一個(gè)好策略,但是不要濫用漠魏,只有必要的時(shí)候才去拆分組件倔矾,不然可能得不償失。
拆分組件最關(guān)鍵的就是確定組件的邊界柱锹,每個(gè)組件都應(yīng)該是可以獨(dú)立存在的哪自,如果兩個(gè)組件邏輯太緊密,無(wú)法清晰定義各自的責(zé)任禁熏,那也許這兩個(gè)組件本身就不應(yīng)該被拆開(kāi)壤巷,作為同一個(gè)組件也許更合理。
雖然組件是應(yīng)該獨(dú)立存在的瞧毙,但是并不是說(shuō)組件就是孤島一樣的存在胧华,不同組件之間總是會(huì)有通信交流,這樣才可能合起來(lái)完成更大的功能宙彪。
作為軟件設(shè)計(jì)的通則矩动,組件的劃分要滿足高內(nèi)聚和低耦合的原則。
高內(nèi)聚指的是把邏輯緊密相關(guān)的內(nèi)容放在一個(gè)組件中释漆。用戶界面無(wú)外乎內(nèi)容悲没、交互和樣式。傳統(tǒng)上男图,內(nèi)容由HTML表示示姿,交互行放在JavaScript代碼文件中,樣式放在CSS文件中定義逊笆。這雖然滿足一個(gè)功能模塊的需要栈戳,卻要放在三個(gè)不同的文件中,這樣其實(shí)不滿足高內(nèi)聚的原則难裆。React卻不是這樣子檀,展示內(nèi)容的JSX、定義行為的JavaScript代碼,甚至定義樣式的CSS命锄,都可以放在一個(gè)JavaScript文件中,因?yàn)樗鼈儽緛?lái)就是為了一個(gè)目的而存在的偏化,所以說(shuō)React天生具有高內(nèi)聚的特點(diǎn)脐恩。
低耦合指的是不同組件之間的依賴(lài)關(guān)系要盡量弱化,也就是每個(gè)組件要盡量獨(dú)立侦讨。保持整個(gè)系統(tǒng)的低耦合度驶冒,需要對(duì)系統(tǒng)中的功能有充分的認(rèn)識(shí),然后根據(jù)功能點(diǎn)劃分模塊韵卤,讓不同的組件去實(shí)現(xiàn)不同的功能骗污。
2、類(lèi)定義/函數(shù)定義組件
類(lèi)定義組件:
使用ES6 class 來(lái)定義一個(gè)組件:
import React, { Component } from 'react';
class Title extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>
}
}
或者你也可以這樣寫(xiě):
import React from 'react';
class Title extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>
}
}
在代碼的第一行沈条,我們從react庫(kù)中引入了React和Component需忿,Component作為所有組件的基類(lèi),提供了很多組件共有的功能蜡歹,class Title extends Component {}
屋厘,Title組件的父類(lèi)就是Component。
仔細(xì)看上面的代碼會(huì)發(fā)現(xiàn)我們導(dǎo)入的Component類(lèi)在Title組件定義中被使用了月而,可是導(dǎo)入的React卻沒(méi)有被使用汗洒,試著刪除第一行的React網(wǎng)頁(yè)會(huì)立刻報(bào)錯(cuò)。
原因是在使用JSX的范圍內(nèi)必須有React父款。也就是說(shuō)溢谤,在使用JSX的代碼文件中,即使代碼并沒(méi)有直接使用React憨攒,也一定要導(dǎo)入這個(gè)React世杀,這是因?yàn)镴SX最終會(huì)被轉(zhuǎn)譯成依賴(lài)于React的表達(dá)式。
函數(shù)定義組件:
定義一個(gè)組件最簡(jiǎn)單的方式是使用JavaScript函數(shù):
// 函數(shù)定義組件
function Title(props) {
return <h1>Hello, {props.name}</h1>
}
// 箭頭函數(shù)語(yǔ)法
const Title = props => <h1>Hello, {props.name}</h1>
// 解構(gòu)賦值語(yǔ)法
const Title = ({name}) => <h1>Hello, {name}</h1>
該函數(shù)是一個(gè)有效的React組件肝集,它接收一個(gè)單一的“props”對(duì)象并返回了一個(gè)React元素玫坛。我們之所以稱(chēng)這種類(lèi)型的組件為函數(shù)定義組件,是因?yàn)閺淖置嫔蟻?lái)看包晰,它就是一個(gè)JavaScript函數(shù)湿镀。
補(bǔ)充:在React出現(xiàn)之初,使用的是React.createClass方式來(lái)創(chuàng)造組件類(lèi)伐憾,這種方式已經(jīng)被廢棄了勉痴。
3、React組件的數(shù)據(jù)
React組件的數(shù)據(jù)分為兩種树肃,props和state蒸矛,無(wú)論props或者state的改變,都可能已發(fā)組件的重新渲染。props是組件的對(duì)外接口雏掠,state是組件的內(nèi)部狀態(tài)斩祭,對(duì)外用props,內(nèi)部用state乡话。
React的props:
在React中摧玫,props是從外部傳遞給組件的數(shù)據(jù),一個(gè)React組件通過(guò)定義自己能夠接受的props就定義了自己的對(duì)外公共接口绑青。
每個(gè)React組件都是獨(dú)立存在的模塊诬像,組件之外的一切都是外部世界,外部世界就是通過(guò)props和組件對(duì)話的闸婴。
我們先從外部世界來(lái)看