在使用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中的数据有变化,但是组件中的监听函数没有监听到数据变化
这样的问题出现过很多次了,不要钻牛角尖,去郁闷为啥数据有变化监听不到呀,为啥呀!其实,数据变化了,监听不到,本质原因就是没有监听;可能其他的代码卸载了监听函数。