React基本概念(三)
操作底層DOM的使用場景:當需要與一個沒有使用React的第三方類庫進行整合,或執行一個React沒有原生支持的操作時。
訪問受控的DOM節點:
想要訪問受React控制的DOM節點,首先必須能夠訪問到負責控制這些DOM的組件。這可以通過為子組件添加一個ref屬性來實現。
eg:
var DoodleArea = React.createClass({
render: function () {
return <canvas ref="mainCanvas"
}
});
這樣可以通過this.refs.mainCanvas訪問到<canvas>組件。同時必須保證每個子組件的ref值在所有子組件中是唯一的,如果有兩個子組件ref值相同則操作將失效。
一旦通過this.refs.mainCanvas訪問到canvas子組件,就可以通過它的getDOMNode()方法訪問到底層的DOM節點。但不能在render方法中調用getDOMNode()。因為render方法完成並且React執行更新之前,底層的DOM節點可能不是最新的(甚至尚未創建)。直到組件被掛載才能調用getDOMNode()方法,即componentDidMount事件處理器被觸發時。
註意:componentDidMount內部並不是getDOMNode()方法的唯一執行環境,事件處理器也可以在組件掛載後觸發,所以也可以在事件處理器中調用getDOMNode().
使用this.refs.getDOMNode()方法會對React產生性能上的障礙,只有在沒有其他方法能夠實現需要的功能時才能考慮使用。
整合非React類庫:
沒有使用React構建的JavaScript類庫,一些類庫不需要使用DOM,如果要使用它們,保持狀態和React的狀態之間的同步是成功整合的關鍵。
eg:autocomplelte類庫:
autocomplete({
target: document.getElementById("cities"),
data: [
"San Francisco",
"St. Louis",
"Amsterdam",
"Los Angeles"
],
events: {
select: function (city) {
alert("You have selected the city of " + city);
}
}
});
該autocomplete函數需要一個目標DOM節點、一個用作數據展現的字符串清單,以及一些時間監聽器
使用該類庫的React組件:
var AutocompleteCities = React.createClass({
render: function () {
/*/DOM節點*/
return <div id="cities" ref="autocompleteTarget"/>
},
getDefaultProps: function () {
return {
/*字符串清單*/
data: [
"San Francisco",
"St. Louis",
"Amsterdam",
"Los Angeles"
]
};
},
/* 事件監聽器*/
handleSelect: function (city) {
alert("You have selected the city of " + city);
},
componentDidMount: function () {
autocomplete({
target: this.refs.autocompleteTarget.getDOMNode(),
data: this.props.data,
events: {
select: this.handleSelect
}
});
}
});
componentDidMount方法只會為每個節點調用一次。因此我們不用擔心在一個節點上兩次調用autocomplete方法產生的影響。
也就是說該組件可能被移除,然後在其他DOM節點上重新渲染,如果在componentDidMount方法內導致了DOM節點無法被移除,有可能導致內存泄漏或者其他問題。為確保此現象的發生,可以指定一個componentWillUnmount監聽器,用於在組件的DOM節點移除時清理自身。
侵入式插件:
修改除了自己子元素以外的依附元素(如父元素)的插件。
面對這類侵入式插件,保護好React的最好方式就是把DOM操控權完全交給我們自己。在componentDidMount方法中做一些初始化工作。這裏也需要去完成清理工作。
還需要進行處理更新。可通過兩種方式觸發:
-- 模擬卸載器而後重新掛載(更高效)
eg:
componentDidUpdate: function () {
this.componentWillUnmount();
this.componentDidMount();
}
-- 使用插件的更新操作API(更有效、清晰)
React基本概念(三)