React提供了強(qiáng)大的抽象,讓你在大多數(shù)應(yīng)用場(chǎng)景中不再直接操作DOM,但是有時(shí)你需要簡(jiǎn)單地調(diào)用底層的API,或者借助于第三方庫(kù)或已有的代碼。
React是很快的,因?yàn)樗鼜牟恢苯硬僮鱀OM。React在內(nèi)存中維護(hù)一個(gè)快速響應(yīng)的DOM描述。render()方法返回一個(gè)DOM的描述,React能夠利用內(nèi)存中的描述來(lái)快速地計(jì)算出差異,然后更新瀏覽器中的DOM。
另外,React實(shí)現(xiàn)了一個(gè)完備的虛擬事件系統(tǒng),盡管各個(gè)瀏覽器都有自己的怪異行為,React確保所有事件對(duì)象都符合W3C規(guī)范,并且持續(xù)冒泡,用一種高性能的方式跨瀏覽器(and everything bubbles consistently and in a performant way cross-browser)。你甚至可以在IE8中使用一些HTML5的事件!
大多數(shù)時(shí)候你應(yīng)該呆在React的“虛擬瀏覽器”世界里面,因?yàn)樗阅芨雍?,并且容易思考。但是,有時(shí)你簡(jiǎn)單地需要調(diào)用底層的API,或許借助于第三方的類(lèi)似于jQuery插件這種庫(kù)。React為你提供了直接使用底層DOM API的途徑。
為了和瀏覽器交互,你將需要對(duì)DOM節(jié)點(diǎn)的引用。每一個(gè)掛載的React組件有一個(gè)getDOMNode()方法,你可以調(diào)用這個(gè)方法來(lái)獲取對(duì)該節(jié)點(diǎn)的引用。
注意:
getDOMNode()僅在掛載的組件上有效(也就是說(shuō),組件已經(jīng)被放進(jìn)了DOM中)。如果你嘗試在一個(gè)未被掛載的組件上調(diào)用這個(gè)函數(shù)(例如在創(chuàng)建組件的render()函數(shù)中調(diào)用getDOMNode()),將會(huì)拋出異常。
為了獲取一個(gè)到React組件的引用,你可以使用this來(lái)得到當(dāng)前的React組件,或者你可以使用refs來(lái)指向一個(gè)你擁有的組件。它們像這樣工作:
var MyComponent = React.createClass({
handleClick: function() {
// Explicitly focus the text input using the raw DOM API.
this.refs.myTextInput.getDOMNode().focus();
},
render: function() {
// The ref attribute adds a reference to the component to
// this.refs when the component is mounted.
return (
<div>
<input type="text" ref="myTextInput" />
<input
type="button"
value="Focus the text input"
onClick={this.handleClick}
/>
</div>
);
}
});
React.render(
<MyComponent />,
document.getElementById('example')
);
為了學(xué)習(xí)更多有關(guān)Refs的內(nèi)容,包括如何有效地使用它們,參考我們的更多關(guān)于Refs文檔。
組件的生命周期包含三個(gè)主要部分:
React提供生命周期方法,你可以在這些方法中放入自己的代碼。我們提供will方法,會(huì)在某些行為發(fā)生之前調(diào)用,和did方法,會(huì)在某些行為發(fā)生之后調(diào)用。
getInitialState(): object在組件被掛載之前調(diào)用。狀態(tài)化的組件應(yīng)該實(shí)現(xiàn)這個(gè)方法,返回初始的state數(shù)據(jù)。componentWillMount()在掛載發(fā)生之前立即被調(diào)用。componentDidMount()在掛載結(jié)束之后馬上被調(diào)用。需要DOM節(jié)點(diǎn)的初始化操作應(yīng)該放在這里。componentWillReceiveProps(object nextProps)當(dāng)一個(gè)掛載的組件接收到新的props的時(shí)候被調(diào)用。該方法應(yīng)該用于比較this.props和nextProps,然后使用this.setState()來(lái)改變state。shouldComponentUpdate(object nextProps, object nextState): boolean當(dāng)組件做出是否要更新DOM的決定的時(shí)候被調(diào)用。實(shí)現(xiàn)該函數(shù),優(yōu)化this.props和nextProps,以及this.state和nextState的比較,如果不需要React更新DOM,則返回false。componentWillUpdate(object nextProps, object nextState)在更新發(fā)生之前被調(diào)用。你可以在這里調(diào)用this.setState()。componentDidUpdate(object prevProps, object prevState)在更新發(fā)生之后調(diào)用。componentWillUnmount()在組件移除和銷(xiāo)毀之前被調(diào)用。清理工作應(yīng)該放在這里。_掛載的_復(fù)合組件也支持如下方法:
getDOMNode(): DOMElement可以在任何掛載的組件上面調(diào)用,用于獲取一個(gè)指向它的渲染DOM節(jié)點(diǎn)的引用。forceUpdate()當(dāng)你知道一些很深的組件state已經(jīng)改變了的時(shí)候,可以在該組件上面調(diào)用,而不是使用this.setState()。在 Facebook,我們支持老版本的瀏覽器,包括 IE8。我們已經(jīng)擁有適當(dāng)?shù)?polyfills 很長(zhǎng)一段時(shí)間了,能夠允許我們寫(xiě)有遠(yuǎn)見(jiàn)的 JS。這意味著在我們的代碼庫(kù)中沒(méi)有黑客,我們?nèi)匀豢梢云诖覀兊拇a“工作”。例如,不用寫(xiě) +new Date(),我們可以只寫(xiě) Date.now()。由于開(kāi)源的 React 和我們內(nèi)部使用的是一樣的,所以我們采取了使用超前思維 JS 的這種理念。
除了那種理念,我們也確立了我們的立場(chǎng),作為一個(gè) JS 庫(kù)的作者,不應(yīng)該把 polyfills 作為庫(kù)的一部分 shipping。如果每個(gè)庫(kù)都這么做,很有可能你會(huì)多次發(fā)送相同的 polyfill,這可能相當(dāng)于一部分無(wú)用代碼。如果你的產(chǎn)品需要支持老版本的瀏覽器,很有可能你已經(jīng)在使用類(lèi)似 es5-shim 的東西了。
來(lái)自 的 es5-shim.js 提供了 React 所需的如下方法:
Array.isArrayArray.prototype.everyArray.prototype.forEachArray.prototype.indexOfArray.prototype.mapDate.nowFunction.prototype.bindObject.keysString.prototype.splitString.prototype.trimes5-sham.js,同樣來(lái)自 ,提供了 React 所需的如下方法:
Object.createObject.freezeReact 的 unminified 構(gòu)建需要來(lái)自 的如下方法:
console.*當(dāng)使用 IE8 中的 HTML5 元素時(shí),包括 <section>,<article>, <nav>,<header> 和<footer>,包含 html5shiv 或類(lèi)似的一個(gè)腳本也是必須的。
雖然 React 非常擅長(zhǎng)抽象瀏覽器的差異,但是一些瀏覽器是有限制的或呈現(xiàn)出怪異的行為,對(duì)于這種行為我們不能找到解決方案。
在 IE8 中,onScroll 事件并不 buddle,并且 IE8 沒(méi)有一個(gè) API 定義處理程序來(lái)捕獲一個(gè)事件的階段,這意味著 React 沒(méi)有辦法監(jiān)聽(tīng)這些事件。目前在 IE8 中,事件處理程序被忽略了。
更多信息請(qǐng)看 onScroll 在 IE8 中不起作用的 GitHub 問(wèn)題。