官網(wǎng)地址https://facebook.github.io/react/docs/hello-world.html
JSX
- 可以在JSX中插入任何表達(dá)式,表達(dá)式需要用
{}
包裹网杆,插入string羹饰,可以用""
- JSX分割成多行時,用
()
包裹起來碳却,避免自動分號插入的陷阱 - JSX的屬性采用駝峰式命名方式队秩,如HTML中的
class
,JSX命名為className
- JSX避免XSS (cross-site-scripting) 攻擊
- Babel通過調(diào)用
React.createElement()
來編譯JSX追城,React必須在JSX代碼的作用域內(nèi)刹碾,參考:深入JSX -
React.createElement()
創(chuàng)建的對象成為"React elements"
Rendering elements
- 元素是React應(yīng)用的最小組成單位
- React的元素都是對象,創(chuàng)建廉價
- 通過
ReactDOM.render()
將React元素渲染成DOM元素座柱,如ReactDOM.render(element, document.getElementById('root'));
- React elements是不可變( immutable)的迷帜,它代表某個時刻的UI改變UI的唯一方法就是創(chuàng)建一個新的element,然后把它傳遞給
ReactDOM.render()
- React DOM會將新創(chuàng)建的element以及它的children和前一個element相比色洞,只改變DOM中需要改變的部分來更新DOM
Components and Props
- Components將UI分割成獨立的戏锹、可復(fù)用的、可單獨思考的塊
- 可以使用函數(shù)或者類定義類火诸,分別稱為Function Component(函數(shù)組件)和Class Component(類組件)
Function Component:函數(shù)的入?yún)⒅荒苁且粋€props對象锦针,并且返回值是一個React元素
Class Component:class繼承React.Component,有一個render屬性,render返回一個自定義組件奈搜、DOM組件或者null和false(null和false表明不需要渲染任何東西) - 組件名的首個字母必須大寫悉盆,如<Welcome />,用于區(qū)分自定義元素(首個字母大寫)和DOM元素(首個字母小寫)
- Component返回元素必須是一個根元素
- 純函數(shù):不改變輸入值的函數(shù)馋吗,所有的組件必須是像純函數(shù)一樣焕盟,不改變props,props是只讀的
- props默認(rèn)值是"true"
- 可以使用……作為擴展操作來傳遞全部props對象宏粤,
<Greeting {...props} />
- 在開口標(biāo)簽和閉合標(biāo)簽之間的內(nèi)容是一種特殊的props:
props.children
-
props.children
可以是混合的JSX脚翘、{}
包裹的表達(dá)式或者函數(shù) - false, null, undefined, and true都是有效孩子,不會被渲染绍哎,需要渲染時来农,使用{String(myVariable)}轉(zhuǎn)化為string
6-10參考:深入JSX
State and Lifecycle
- 只有通過class方法定義的組件才有state屬性
- 在class的constructor中,通過
super(props)
繼承props崇堰,通過this.state = {……}
來初始化state沃于,只能通過setState來修改state - state的修改是異步的,setState的callback函數(shù)可以傳入兩個參數(shù):prevState, props(前一個狀態(tài)赶袄、參數(shù))
this.setState((prevState, props) => {……})
- 會對setState返回的對象與state做一個merge操作
- 生命周期鉤子
componentDidMount()
:組件插入DOM(render()
完成)時立刻執(zhí)行
componentWillUnmount()
:在組件即將從 DOM 中移除的時候立刻被調(diào)用 - 數(shù)據(jù)是從父組件到子組件單向流動的揽涮,可以將state作為props傳遞給子組件
Handling Events
- 命名事件方式不同:react->駝峰式(如
onClick
),DOM->小寫(如onclick
) - react傳遞函數(shù)(如:
onClick={activateLasers}
)給事件處理器而不是string(如:onclick="activateLasers()"
) - DOM調(diào)用return false來阻止默認(rèn)行為饿肺,在react中蒋困,必須顯示調(diào)用
preventDefault()
- 注意JSX事件回調(diào)函數(shù)中的
this
,可以在constructor
函數(shù)中綁定this.handleClick = this.handleClick.bind(this);
或者handleClick = () => {……}
或者button onClick={(e) => this.handleClick(e)}>
敬辣,這樣可以保證函數(shù)在實際使用時this
不時undefined
Conditional Rendering
- 使用js的if 或者條件運算符 創(chuàng)建符合當(dāng)前狀態(tài)的元素
- 在JSX中插入表達(dá)式雪标,&&操作符或者條件表達(dá)式編寫內(nèi)聯(lián)的if邏輯
- 根據(jù)條件隱藏(返回null)或者顯示組件
- 返回null,
componentWillUpdate()
和componentDidUpdate()
仍然會調(diào)用
componentWillUpdate(object nextProps, object nextState)
:在接收到新的 props 或者 state 之前立刻調(diào)用
componentDidUpdate(object prevProps, object prevState)
:在組件的更新已經(jīng)同步到 DOM 中之后立刻被調(diào)用
Lists and Keys
- 創(chuàng)建elements列表時溉跃,key是一個特殊的屬性
- react根據(jù)keys判斷數(shù)組的items(項)是否改增刪改
- 在兄弟節(jié)點中村刨,該節(jié)點的key是獨一無二的
- key應(yīng)該是穩(wěn)定的(例如不能是通過Math.random()生成)
- key是可預(yù)測的
- 添加一個ID屬性或者對部分內(nèi)容做哈希算法生成一個key,也可以將item在數(shù)組中的index作為key撰茎,確保index作為key時嵌牺,這個數(shù)組不會重新排序,重新排序可能會很慢
- 在JSX中插入
map()
龄糊,生成子組件列表
<pre>return ( <ul> { numbers.map((item, index) => { return <ListItem value={item} key={index} /> }) } </ul> )
</pre>
Forms
- controlled component:一個input表單元素逆粹,如果它的value是由React控制的,我們就叫它controlled component
- form表單炫惩,如
<input type="text" value={this.state.value} onChange={this.handleChange} />
僻弹,handleChange
事件通過setState
修改state
的值,最后修改表單的值他嚷。表單的值由React控制
Lifting State Up
多個不同的component之間可能需要共享一個state蹋绽,可將state提升至它們共同的最近的component祖先中(從上至下的數(shù)據(jù)流)
- state提升需要寫一個共同的模板芭毙,可能需要寫更多的代碼
- 如果有些數(shù)據(jù),既可以放在props又可以放在state中卸耘,那么建議不要放在state中
Composition vs Inheritance
react有強大的組合模型退敦,在react建議使用組合來代替繼承。新手在開發(fā)過程中經(jīng)常遇到的鹊奖,用組合代替繼承的案例有:
- 組件的孩子節(jié)點事先不知道苛聘,通過
props.children
傳入 - 組件預(yù)留一些“洞”(構(gòu)成組件的部分模塊開始未知,在使用時才知道)忠聚,可以在使用時通過props(props的屬性可以是component)傳入這些模塊(模塊可能是組件)
- 一個組件是另外一個組件的特例時
JSX In Depth
- JSX是
React.createElement(component, props, ...children)
的語法糖 - 可以使用點記法標(biāo)識一個JSX類型,如
<MyComponents.DatePicker color="blue" />
- React元素不能是普通表達(dá)式唱捣,如果想使用普通表達(dá)式两蟀,可以先賦值給一個大寫的變量,
SpecificStory = components[props.storyType]; return <SpecificStory />
- React元素和自定義組件必須大寫
Refs and the DOM
React提供了Refs(引用)震缭,用ref來獲取組件或者HTML元素的引用赂毯,ref有一個屬性是一個回調(diào)函數(shù),回調(diào)函數(shù)入?yún)⑹莚ef所在的HTML元素或者組件的引用拣宰,如<input type="text" ref={input => this.textInput = input} />
- refs使用場景:處理焦點党涕、文本選擇、媒體播放巡社,觸發(fā)強制性動畫膛堤, 集成第三方DOM庫
- 可以給DOM和類組件refs,函數(shù)組件沒有實例晌该,不適合使用ref屬性
- 不要過度使用Refs
Uncontrolled Components
- 使用uncontrolled components肥荔,可以更容易集成React和非React代碼,代碼可能會更加輕量朝群,但是會比較“臟”燕耿,盡量使用controlled components
- 在為form中每一個state變化寫一個事件處理器不如使用ref獲取DOM表單的值,對表單中的每一個元素姜胖,通過
ref={(input) => this.input = input}
來獲取引用 - defaultValue指定初始值誉帅,在checkbox和radio中,使用defaultChecked右莱,select使用defaultValue 蚜锨,如
<input defaultValue="Bob" …… />
Optimizing Performance
使用構(gòu)建工具優(yōu)化React應(yīng)用
使用chrome的Timeline剖析組件
virtual DOM:對被渲染成了UI的組件,React會構(gòu)建和保存該組件返回的React元素隧出,即virtual DOM
shouldComponentUpdate:生命周期函數(shù)
shouldComponentUpdate(nextProps, nextState)
默認(rèn)返回true踏志,如果返回一個false,就不會重新渲染組件-
組件渲染時胀瞪,從上而下遍歷該組件樹
a:如果節(jié)點N1的shouldComponentUpdate
方法返回false针余,N1及其子節(jié)點Ni(i可能是1饲鄙、2、……)都不會重新渲染圆雁,Ni的shouldComponentUpdate
也不會觸發(fā)忍级,停止遍歷寂玲,否則執(zhí)行b
b:依次遍歷子節(jié)點Ni搞隐,如果Ni不是葉子節(jié)點遥倦,對Ni執(zhí)行a操作描焰,否則執(zhí)行c
c:只有在Ni(葉子節(jié)點)的shouldComponentUpdate
返回true并且React比較Ni改變前后的值不相等時候省咨,才會重新渲染 ** React.PureComponent**:可使用
React.PureComponent
來代替shouldComponentUpdate
想鹰,React.PureComponent會做一個“淺比較”黔牵,所以對于props或者state修改前后斗蒋,淺比較值依舊相等的情況坚洽,不要使用React.PureComponent修改數(shù)組和對象戈稿,“淺比較”修改前后值依舊相等
對數(shù)組:可使用concat
和es6擴展語法,重新賦值如words: prevState.words.concat(['marklar'])
和words: [...prevState.words, 'marklar']
對對象:可使用object.assign或者對象擴展屬性重新賦值Object.assign({}, colormap, {right: 'blue'})
和{...colormap, right: 'blue'}
Immutable.js是另一個解決方案讶舰,它通過結(jié)構(gòu)化共享提供一個不變化鞍盗、持久化的集合
Reconciliation
React使用Diffing Algorithm(差分算法)來考慮如何有效的修改UI來最大程度的匹配現(xiàn)在的樹
- Diffing Algorithm的啟發(fā)式設(shè)想前提
a:兩個不同的元素會生成兩個不同的樹
b:開發(fā)者可以通過key暗示在不同的渲染中,哪個孩子元素是穩(wěn)定不變的 - Diffing算法
a:對于不同類型的根元素跳昼,React會銷毀舊的樹以及它的state般甲,并且安裝一顆新的樹
b:相同類型的DOM元素,保留相同的DOM元素鹅颊,只更新已更改的部分屬性(例如class敷存、style屬性等)
c:相同類型的Component元素,新舊Component是同一個對象實例挪略,維持一個state历帚,React更新組件的props來匹配新的元素(componentWillReceiveProps()和componentWillUpdate()事件會執(zhí)行)
d:React會同時遞歸比較新舊孩子列表,一旦有不同的地方杠娱,React就會改變
上述遞歸新舊孩子列表挽牢,如果節(jié)點只是挪動了位置,并沒有改變摊求,React不會意思到這一點禽拔,會造成不必要的銷毀與重建,React可以使用key來比較修改前后的孩子節(jié)點室叉。 - Tradeoffs
a:這個算法不會試著匹配不同組件類型的子樹睹栖,有相似輸出的組件類型的組件之間可能更應(yīng)該是同一個類型,事實也是這樣
b:key應(yīng)該是穩(wěn)定的茧痕,可預(yù)測的野来,和獨一無二的 - 生命周期事件
componentWillUnmount()
:在舊的DOM節(jié)點即將銷毀時調(diào)用
componentWillMount()
:即將安裝新的DOM時調(diào)用
componentDidMount()
:新的DOM安裝完成是調(diào)用
componentWillReceiveProps()
:組件即將更新props時調(diào)用
componentWillUpdate()
:組件接收到新的props或者state但還沒有render()時被執(zhí)行