React學(xué)習(xí)筆記之基礎(chǔ)用法

最近在學(xué)習(xí)React扛拨,并使用React做了一個(gè)cnode(歡迎大家給我star使套、issue美尸,一起學(xué)習(xí)討論進(jìn)步),現(xiàn)就記錄一下自己的React學(xué)習(xí)筆記骄瓣。

學(xué)習(xí)資料

React中文文檔

環(huán)境配置

React的環(huán)境配置很麻煩停巷,剛上手時(shí)可以使用React腳手架來(lái)進(jìn)行學(xué)習(xí)。推薦Create React App榕栏,或者可以使用我自己寫(xiě)的一個(gè)腳手架畔勤。

Jsx語(yǔ)法

簡(jiǎn)單來(lái)說(shuō),就是可以把html和js混在一起寫(xiě)扒磁,即html代碼里面可以有js代碼庆揪,js代碼里面可以有html。需要注意的是妨托,在html中遇到j(luò)s代碼缸榛,需要加花括號(hào),而在js代碼中遇到html代碼兰伤,需要加圓括號(hào)内颗。

創(chuàng)建組件

創(chuàng)建組件有兩種方式:

  • 函數(shù)創(chuàng)建
function Hello() {
  return <h1>Hello World</h1>;
}
  • ES6的class
class Hello extends React.Component {
  render() {
    return <h1>Hello World</h1>;
  }
}

不同之處:函數(shù)式組件沒(méi)有state,也不能使用生命周期函數(shù)敦腔。

注意:組件名稱必須以大寫(xiě)字母開(kāi)頭均澳。組件的返回值只能有一個(gè)根元素。

props與state
  • props
    props是只讀的符衔,組件絕對(duì)不能修改自己的props
  • state
    狀態(tài)與屬性十分相似负懦,但是狀態(tài)是私有的,完全受控于當(dāng)前組件柏腻。
    更新?tīng)顟B(tài)只有一個(gè)辦法:那就是調(diào)用this.setState()
    該方法有兩種調(diào)用方式
    // 接受一個(gè)對(duì)象為參數(shù)
    this.setState({
      loading: false
    })
    // 接受一個(gè)函數(shù)為參數(shù),函數(shù)的第一個(gè)參數(shù)為先前的狀態(tài),第二個(gè)參數(shù)為props
    this.setState((prevState, props) => ({
     loading: !prevState.loading
    }))
    // 除此之外纸厉,this.setState()還接受一個(gè)可選的回調(diào)函數(shù)作為第二個(gè)參數(shù)
    
條件加載

React的條件加載和JavaScript中的條件判斷一樣,我們可以使用條件運(yùn)算符(?:)五嫂,與運(yùn)算符(&&)等來(lái)進(jìn)行條件加載颗品。

循環(huán)加載

我們一般按如下的方式進(jìn)行循環(huán)加載

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li key={number.toString()}>
    {number}
  </li>
)
//一個(gè)元素的key最好是這個(gè)元素在列表中擁有的一個(gè)獨(dú)一無(wú)二的字符串肯尺。
//通常,我們使用來(lái)自數(shù)據(jù)的id作為元素的key躯枢。當(dāng)元素沒(méi)有確定的id時(shí)则吟,你可以使用他的序列號(hào)索引index作為key
操作表單
class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({value: event.target.value});
  }
  render() {
    return (
        <div>
          <label>Name:
            <input type="text" value={this.state.value} onChange={this.handleChange} />
          </label>
        </div>
    );
  }
}

一個(gè)簡(jiǎn)單操作表單元素的例子就是這樣。但是我們會(huì)發(fā)現(xiàn)這樣操作表單有一些小問(wèn)題锄蹂。假如該表單有很多表單元素氓仲,那么我們需要為每一個(gè)表單元素注冊(cè)一個(gè)change事件的處理函數(shù),這會(huì)讓組件顯得很臃腫得糜。不過(guò)不用擔(dān)心敬扛,遇到這種情況我們依然有解決辦法。那就是使用ref朝抖。

關(guān)于Ref

我們可以給DOM元素啥箭,類組件添加ref屬性,不能給函數(shù)式組件添加ref屬性治宣。
ref 屬性接受一個(gè)回調(diào)函數(shù)急侥,它在組件被加載或卸載時(shí)會(huì)立即執(zhí)行。
ref屬性也接受一個(gè)字符串侮邀,(不過(guò)未來(lái)可能會(huì)廢棄坏怪,推薦使用回調(diào))
ref 在加載時(shí)回調(diào)接收了底層的DOM元素或已經(jīng)加載的 React 實(shí)例作為參數(shù),在卸載時(shí)則會(huì)傳入 null绊茧。

class NameForm extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
        <div>
          <label>Name:
            <input type="text" ref={ input => this.input=input }/>
          </label>
        </div>
    );
  }
}
// 此時(shí)this.input指向inputDOM元素陕悬,我們可以使用this.input.value得到用戶的輸入。

除可以操作DOM之外按傅,ref還用于觸發(fā)強(qiáng)制動(dòng)畫(huà)捉超,處理焦點(diǎn)、文本選擇或媒體控制等唯绍。
不過(guò)我們應(yīng)該盡量避免使用ref拼岳。

事件處理
  • React事件綁定屬性的命名采用駝峰式寫(xiě)法。
  • 如果采用 JSX 的語(yǔ)法需要傳入一個(gè)函數(shù)作為事件處理函數(shù)况芒,而不是一個(gè)字符串惜纸。
  • 不能使用返回 false 的方式阻止默認(rèn)行為。
  • 事件對(duì)象是一個(gè)合成對(duì)象绝骚,所以不需要擔(dān)心跨瀏覽器的兼容性問(wèn)題耐版。
  • 事件處理程序會(huì)成為類的一個(gè)方法(類的方法默認(rèn)是不會(huì)綁定this 的),所以我們需要手動(dòng)綁定this压汪。
    手動(dòng)綁定this有兩種方法粪牲,一是在類的構(gòu)造函數(shù)中使用bind綁定,二是在DOM中使用bind綁定止剖。
    如果你的事件處理程序是箭頭函數(shù)腺阳,則不需要手動(dòng)綁定this落君。
  • 向事件處理程序傳遞參數(shù)有兩種方法,一是使用箭頭函數(shù)亭引,二是使用bind方法绎速。
<button onClick={(e) => this.confirm(id, e)}>確定</button>
<button onClick={this.confirm.bind(this, id)}>確定</button>
  • 事件處理程序的最后一個(gè)參數(shù)為事件對(duì)象(該事件對(duì)象是SyntheticEvent的實(shí)例)。
    如果由于某些原因焙蚓,你得使用一些底層的瀏覽器事件纹冤,只需用nativeEvent的屬性就能得到原生的事件對(duì)象。
DOM屬性

React實(shí)現(xiàn)了一套與瀏覽器無(wú)關(guān)的DOM系統(tǒng)购公,兼顧了性能和跨瀏覽器的兼容性萌京。
在React中,所有的DOM特性和屬性都是小駝峰命名法命名君丁。(aria-和data-屬性除外)
一些不同之處:

  • 使用className屬性指定一個(gè)CSS類。
  • style屬性接受一個(gè)鍵為小駝峰命名法命名的javascript對(duì)象作為值将宪。(注意:樣式屬性不會(huì)自動(dòng)補(bǔ)齊前綴的绘闷,瀏覽器前綴除了ms以外,都應(yīng)該以大寫(xiě)字母開(kāi)頭)
  • onChange函數(shù)较坛,無(wú)論form表單何時(shí)發(fā)生變化印蔗,這個(gè)事件都會(huì)被觸發(fā)。
  • dangerouslySetInnerHTML函數(shù)是替換瀏覽器DOM中的innerHTML接口的一個(gè)函數(shù)丑勤。
生命周期

組件的生命周期大致分為三個(gè)階段

  1. 裝配階段(這些方法會(huì)在組件實(shí)例被創(chuàng)建和插入DOM中時(shí)被調(diào)用)

    • constructor()
    • componentWillMount()
    • render()
    • componentDidMount()
  2. 更新階段(屬性或狀態(tài)的改變會(huì)觸發(fā)一次更新华嘹。當(dāng)一個(gè)組件在被重渲時(shí),這些方法將會(huì)被調(diào)用)

    • componentWillReceiveProps(nextProps)
    • shouldComponentUpdate(nextProps, nextState)
    • componentWillUpdate(nextProps, nextState)
    • render()
    • componentDidUpdate(prevProps, prevState)
  3. 卸載階段(當(dāng)一個(gè)組件被從DOM中移除時(shí)法竞,該方法被調(diào)用)

    • componentWillUnmount()

除此之外耙厚,組件還有一個(gè)方法forceUpdate(),調(diào)用forceUpdate()將會(huì)導(dǎo)致組件的 render()方法被調(diào)用岔霸,并忽略shouldComponentUpdate()薛躬。

注意點(diǎn):

  • shouldComponentUpdate()返回false,render()函數(shù)將不會(huì)被調(diào)用呆细。
  • 當(dāng)為一個(gè)React.Component子類定義構(gòu)造函數(shù)時(shí)型宝,你應(yīng)該在任何其他的表達(dá)式之前調(diào)用super(props)。否則絮爷,this.props在構(gòu)造函數(shù)中將是未定義趴酣,并可能引發(fā)異常。
  • defaultProps可以被定義為組件類的一個(gè)屬性坑夯,用以為類設(shè)置默認(rèn)的屬性岖寞。
常見(jiàn)問(wèn)題
  1. 使用React開(kāi)發(fā)必須使用JSX語(yǔ)法嗎?
    答:JSX并不是必須的柜蜈。每一個(gè)JSX元素都只是 React.createElement(component, props, ...children)的語(yǔ)法糖慎璧。
    因此床嫌,任何時(shí)候你用JSX語(yǔ)法寫(xiě)的代碼也可以用普通的 JavaScript 語(yǔ)法寫(xiě)出來(lái)。
  2. 使用React開(kāi)發(fā)必須使用ES6+語(yǔ)法嗎胸私?
    答:ES6+并不是必須的厌处。

虛擬DOM

  • 虛擬DOM具有batching(批處理)和高效的Diff算法。
  • batching把所有的DOM操作搜集起來(lái)岁疼,一次性提交給真實(shí)的DOM阔涉。diff算法時(shí)間復(fù)雜度也從標(biāo)準(zhǔn)的的Diff算法的O(n^3)降到了O(n)。
  • render執(zhí)行的結(jié)果得到的并不是真正的DOM節(jié)點(diǎn)捷绒,結(jié)果僅僅是輕量級(jí)的JavaScript對(duì)象瑰排,我們稱之為virtual DOM。
  • 我們利用虛擬DOM樹(shù)去構(gòu)造真實(shí)DOM樹(shù)暖侨,然后插入到文檔中椭住,當(dāng)數(shù)據(jù)變化時(shí),生成一個(gè)新的虛擬DOM樹(shù)字逗,比較新的虛擬DOM樹(shù)與舊的虛擬DOM樹(shù)京郑,得到差異葫掉,將差異應(yīng)用到真實(shí)DOM中。
  • Virtual DOM并沒(méi)有完全實(shí)現(xiàn)DOM俭厚,Virtual DOM最主要的還是保留了Element之間的層次關(guān)系和一些基本屬性。

React diff算法

  • 樹(shù)對(duì)比
    React 對(duì)樹(shù)的算法進(jìn)行了簡(jiǎn)潔明了的優(yōu)化挪挤,即對(duì)樹(shù)進(jìn)行分層比較,兩棵樹(shù)只會(huì)對(duì)同一層次的節(jié)點(diǎn)進(jìn)行比較扛门。
  • 組件對(duì)比
    • 如果是同一類型的組件幢码,按照原策略繼續(xù)比較 virtual DOM tree。
    • 如果不是尖飞,直接刪除舊組件症副,然后在該位置創(chuàng)建新組件。
    • 對(duì)于同一類型的組件政基,有可能其 Virtual DOM 沒(méi)有任何變化贞铣,如果能夠確切的知道這點(diǎn)那可以節(jié)省大量的 diff 運(yùn)算時(shí)間,因此 React 允許用戶通過(guò) shouldComponentUpdate() 來(lái)判斷該組件是否需要進(jìn)行 diff沮明。
  • 元素對(duì)比
    允許開(kāi)發(fā)者對(duì)同一層級(jí)的同組子節(jié)點(diǎn)辕坝,添加唯一 key 進(jìn)行區(qū)分,雖然只是小小的改動(dòng)荐健,性能上卻發(fā)生了翻天覆地的變化酱畅!
  • 總結(jié)
    • React 通過(guò)分層求異的策略琳袄,對(duì) tree diff 進(jìn)行算法優(yōu)化;
    • React 通過(guò)相同類生成相似樹(shù)形結(jié)構(gòu)纺酸,不同類生成不同樹(shù)形結(jié)構(gòu)的策略窖逗,對(duì) component diff 進(jìn)行算法優(yōu)化;
    • React 通過(guò)設(shè)置唯一 key的策略餐蔬,對(duì) element diff 進(jìn)行算法優(yōu)化碎紊;
性能優(yōu)化
  • 一般做法
    1. 使用工具來(lái)分析性能瓶頸。
    2. 嘗試使用優(yōu)化技巧解決這些問(wèn)題樊诺。
    3. 使用工具測(cè)試性能是否確實(shí)有提升仗考。
  • 具體實(shí)施
    很大程度上,React的性能優(yōu)化就是干掉無(wú)謂的渲染词爬。
    • 我們可以重寫(xiě) shouldComponentUpdate()方法秃嗜,對(duì)this.props與nextProps進(jìn)行比較,對(duì)this.state與nextState進(jìn)行比較顿膨,如果有改變锅锨,則返回true,否則返回false虽惭。
    • 組件繼承React.PureComponent橡类。(自動(dòng)幫我們進(jìn)行淺比較)
    • 使用pure-render-decorator裝飾器蛇尚。(自動(dòng)幫我們進(jìn)行淺比較)
    • 使用react-addons-shallow-compare芽唇。(自動(dòng)幫我們進(jìn)行淺比較)
    • 使用immutable.js。
    • 使用seamless-immutable取劫。
  • 性能分析工具
    • React.addons.Perf
    • react-perf-tool
參考

使用immutable優(yōu)化React
React性能優(yōu)化總結(jié)
React 源碼剖析系列 - 不可思議的 react diff

未完待續(xù)....

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末匆笤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谱邪,更是在濱河造成了極大的恐慌炮捧,老刑警劉巖惦银,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扯俱,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡殊校,警方通過(guò)查閱死者的電腦和手機(jī)为流,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)秀睛,“玉大人静汤,你說(shuō)我怎么就攤上這事√俾眨” “怎么了抹估?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)瓷式。 經(jīng)常有香客問(wèn)我语泽,道長(zhǎng),這世上最難降的妖魔是什么廊驼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任妒挎,我火速辦了婚禮西饵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘期虾。我一直安慰自己镶苞,他們只是感情好宙拉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著御板,像睡著了一般牛郑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上笙各,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天杈抢,我揣著相機(jī)與錄音仑性,去河邊找鬼。 笑死歼捐,一個(gè)胖子當(dāng)著我的面吹牛晨汹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播剥扣,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼朦乏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼氧骤!你這毒婦竟也來(lái)了筹陵?” 一聲冷哼從身側(cè)響起镊尺,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤庐氮,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后仙畦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡莱坎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年檐什,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乃正。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婶博。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凡蜻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出兑巾,到底是詐尸還是另有隱情忠荞,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布堂油,位于F島的核電站府框,受9級(jí)特大地震影響讥邻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜系宜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一盹牧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吆寨,春花似錦、人聲如沸啄清。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至啡莉,卻和暖如春旨剥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背魄咕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工蚌父, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喝滞。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓右遭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親狸演。 傳聞我的和親對(duì)象是個(gè)殘疾皇子僻他,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 3. JSX JSX是對(duì)JavaScript語(yǔ)言的一個(gè)擴(kuò)展語(yǔ)法吨拗, 用于生產(chǎn)React“元素”,建議在描述UI的時(shí)候...
    pixels閱讀 2,824評(píng)論 0 24
  • 深入JSX date:20170412筆記原文其實(shí)JSX是React.createElement(componen...
    gaoer1938閱讀 8,064評(píng)論 2 35
  • HTML模版 之后出現(xiàn)的React代碼嵌套入模版中哨鸭。 1. Hello world 這段代碼將一個(gè)一級(jí)標(biāo)題插入到指...
    ryanho84閱讀 6,232評(píng)論 0 9
  • 本筆記基于React官方文檔像鸡,當(dāng)前React版本號(hào)為15.4.0只估。 1. 安裝 1.1 嘗試 開(kāi)始之前可以先去co...
    Awey閱讀 7,705評(píng)論 14 128
  • 蕓蕓眾生着绷, 在這偌大的世界里, 收獲過(guò)幸福的歡笑吁脱, 享受過(guò)成功的喜悅彬向, 品嘗過(guò)失敗的淚水。 每個(gè)人都有著自己的保護(hù)...
    高蘇辛閱讀 391評(píng)論 0 4