在使用React開發專案過程中,踩過很多坑,在踩坑填坑過程中也學到了不少知識。現就將之前遇到的問題總結下來,一來可以讓自己對這些知識點加深印象,二來也可以幫助更多的人在遇到同樣的問題時可以少走彎路。
元件名命名問題
類名首字母必須大寫,多個單片語合要用帕斯卡命名法(首字母大寫,其它單詞首字母也要大寫)
state更新問題
例如下面的例子中,結果是state沒更新;因為this.state.value是物件型別資料,和value指向的是同一個記憶體地址,引用的是同一個資料;對value的操作實際上就是操作原 this.state.value,所以value和this.state.value相同,對比下,沒有改變;所以在這裡的解決辦法就是:
var value=this.state.value.slice();複製一個this.state.value出來給value,這樣value改變了,就可以跟this.state.value作對比了。
getInitialState: function(){
return {value: {foo: 'bar'}};
},
onClick: function(){
var value = this.state.value; //應該這樣: var value = this.state.value.slice();
value.foo += 'bar';
this.setState({value: value});
}
複製程式碼
this指向問題
componentDidMount() {
QueryStore.on('sync', this.handleQuerySync);
this.initializeWithProps();
}
複製程式碼
this.handleQuerySync的 this 並不是指向當前元件,指向的是QueryStore,解決辦法:(當然es6的箭頭函式也可以解決this指向問題)
......
constructor(props, context) {
super(props, context);
this.state = {};
this.handleQuerySync = this.handleQuerySync.bind(this);
}
componentDidMount() {
QueryStore.on('sync', this.handleQuerySync);
this.initializeWithProps();
}
......
複製程式碼
render 返回格式
render 中 return的內容要麼是空,要麼就是一個節點,所以當有很多節點需要return時,需要用一個節點包裹起來。
js物件中的 key問題
看下面的程式碼,函式中傳入變數key
var BindingMixin = {
handleChange: function(key){
var that = this;
return function(event){
var newState = {};
newState[key] = event.target.value;
that.setState(newState);
//that.setState({
//key: event.target.value
//})
}
}
};
複製程式碼
上面註釋掉的程式碼是錯誤的,因為js物件中的 key值 不可以是變數
多次設定state問題
如下例子:
this.setState({
data: datas
});
this.setState({
data: datas
});
複製程式碼
如果兩次設定狀態,datas的值沒有改變,是不會觸發 render函式的; Javascrippt是基於事件驅動模型,假如在連續兩次 this.setState() 之後,React發現DOM沒有變更,此時React並不會觸發render方法
react 元件開發時遇到的問題
<Menu
vertical={true}
inverted={false}
placement={false} >
<Menu.Item title={<span>Home</span>} \>
<Menu.Item title="Home List1" />
<Menu.Item title="Home List2" />
<Menu.Item title={<a href="">Home List3</a>} /\>
</Menu.Item>
<Menu.Item title={<span><a href="">List</a></span>} /\>
</Menu>
複製程式碼
如上面的程式碼,如何把Menu 的屬性傳到子節點元件 Menu.Item 中去呢? 解決方法是:
renderList = (children, props) => {
const extraProps = {
inverted: props.inverted,
vertical: props.vertical
};
return (
React.Children.map(children, (child) => {
return React.cloneElement(child, extraProps);
})
);
};
......
複製程式碼
外層元件渲染子節點元件時,克隆子節點,並把需要的屬性傳過去;這樣內層的子元件就可以拿到這些屬性;這裡傳過去的物件,不限於屬性,方法也可以傳過去;
內層元件如何複用外層元件的方法?
解決辦法: 上面說了,父元件渲染子元件時,用克隆子元件的方法,順帶把需要的屬性傳過去,其實還可以把父元件的 this 物件傳過去,這樣在子元件裡,就可以方便呼叫父元件的方法;如下程式碼:
//外層父元件
......
renderTreeNode = (child) => {
const defaultExpandAll = this.props.defaultExpandAll;
const extraProps = {
root: this,
defaultExpandAll: defaultExpandAll
};
return React.cloneElement(child, extraProps);
};
......
//內層子元件這樣呼叫
......
newChildren = () => {
let props = this.props;
let children = this.props.children;
return (
<ul className={styles.subTree} >
{React.Children.map(children, (item, index) => {
return props.root.renderTreeNode(item, index);
})}
</ul>
);
};
......
複製程式碼
dangerouslySetInnerHTML
var Test = React.createClass({
getInitialState: function() {
return {html: '<a href="#">這是一段html程式碼</a><a href="#">2</a><a href="#">3</a>};
},
render: function() {
return (
<div>{this.state.html}</div>
);
}
});
React.render(<Test />, document.getElementById('example'));
複製程式碼
解析出來的還是這樣的一段程式碼
<a href="#">這是一段html程式碼</a><a href="#">2</a><a href="#">3</a>'<br><br>
因為react不會自動幫你解析你的html程式碼,不合時宜的使用 innerHTML 可能會導致 cross-site scripting (XSS) 攻擊;
var Test = React.createClass({
getInitialState: function() {
return {html: '<a href="#">這是一段html程式碼</a><a href="#">2</a><a href="#">3</a>};
},
render: function() {
return (
<div dangerouslySetInnerHTML={{__html: this.state.html}}></div>
);
}
});
React.render(<Test />, document.getElementById('example'));
複製程式碼
這麼做的意義在於,{__html:...} 背後的目的是表明它會被當成 "type/taint" 型別處理。 這種包裹物件,可以通過方法呼叫返回淨化後的資料,隨後這種標記過的資料可以被傳遞給 dangerouslySetInnerHTML
其它一些遇到的問題
-
元件被解除安裝後,store裡的資料並不會被清空;必要時得在元件掛著時清空store的資料
-
父元件監聽資料變化就可以了,不需要每個子元件自己又監聽一遍,這樣容易出現bug,而且效能也不好,可以通過props向子元件傳遞;
-
關於列表key
遍歷列表時給每個子專案賦key時,不要直接給 index, 因為如果增加或者刪除子專案時,index 都會變,導致出問題; 也不可以用 index+ string,這樣因為如果增加或者刪除子專案時,所有子專案都會走更新流程,原因是index 在變; 所以在給子專案賦值時,要給唯一不變的數最好。
- 關於store中的資料有變化,但是元件中的監聽函式沒有監聽到資料變化
這樣的問題出現過很多次了,不要鑽牛角尖,去鬱悶為啥資料有變化監聽不到呀,為啥呀!其實,資料變化了,監聽不到,本質原因就是沒有監聽;可能其他的程式碼解除安裝了監聽函式。