React总结篇之二_设计高质量的React组件

一、易于维护组件的设计要素
1.组件划分的原则:高内聚低耦合
(1)高内聚:将逻辑紧密相关的内容放在一个组件内。React可以将展示内容的JSX、定义行为的JavaScript代码、甚至定义样式的css,都可以放在一个JavaScript文件中,因此React天生具有高内聚的特点。
(2)低耦合:不同组件之间的依赖关系要尽量弱化,也就是每个组件要尽量独立。


二、React组件的数据
1.数据分类:
React组件的数据分为两种:prop和state。无论prop或者state改变,都可能引发React的重新渲染。那在设计一个组件时,什么时候选择prop什么时候选择state呢?原则很简单:prop是组件的对外接口,state是组件的内部状态,对外用prop,内部用state。

2.Prop:property的缩写,是从外部传递给组件的数据,一个React组件通过定义自己能够接受的prop就定义了自己的对外公共接口。我们先从外部世界看prop是如何使用的:
<SampleButton id="sample" borderWidth={2} onClick={onButtonClick} style={{color:"red"}}/> 上面创建了名为SampleButton的组件实例,使用了名字分别为id、borderWidth、onClick和style的prop。此处注意:HTML组件属性的值都是字符串类型,即使是内嵌JavaScript,也依然是字符串形式表示代码。但React组件的prop所能支持的类型除了字符串、可以是任何一种JavaScript语句支持的数据类型,如:数字类型、函数类型、style的值是一个包含color字段的对象,当prop的类型不是字符串类型时,在JSX中必须用花括号{}将prop值包住,所以style的值有两层花括号,外层花括号代表的是JSX的语法,内层花括号表示这是一个对象常量。
Prop要反馈数据给外部世界,使用函数类型的prop,这等于父组件给了子组件一个回调函数,子组件在恰当的时机调用函数类型的prop,可以带上必要额参数,这样就把数据传递给外部世界。

3.React要求render函数只能返回一个元素!

4.组件内部接收传入的prop:
(1)首先是构造函数,如下:
class Counter extends Component {
constructor(props){
super(props);
this.onClickIncrementButon = this.onClickIncrementButon.bind(this);
this.onClickDecrementButon = this.onClickDecrementButon.bind(this);
this.state = {
count : props.initValue || 0
}
}
}
注意:组件定义自己的构造函数,一定要在构造函数的第一行通过super调用父类也就是React.Component的构造函数;如果未调用,那么组件实例被构造之后,类实例的所有成员函数就无法通过this.props访问到父组件传过来的props值。很明显,给this.props赋值是React.Component构造函数的工作之一。在Counter的构造函数中还给两个成员函数绑定了当前this的执行环境,因为ES6方法创建的React类并不自动给我们绑定this到当前实例对象。
(2)读取prop值:
在构造函数中可以通过props获得传入的prop值,在其他函数中可通过this.props访问传入prop的值。
const {caption} = this.props;
以上,我们使用了ES6的解构赋值语法,从this.props中获得了名为caption的prop值。

5.propTypes检查:
组件支持哪些prop;
每个prop应该是什么样的格式;
如:对于Counter组件的propTypes定义代码如下:
Counter.propTypes = {
caption : propTypes.string.isRquired,
initVlue : propTypes.number
}
其中要求caption必须是string类型,initVlue必须是number类型,另外,caption带上了isRquired,表示使用Counter组件必须指定caption,而initVlue如果没有也没关系。
propTypes虽然能在开发阶段发现代码中的问题,但是放在产品环境就不大合适了:首先,占用一些代码空间,耗CPU计算资源;其次,在产品环境下做propTypes检查没有什么帮助,在最终用户的浏览器Console中输出这些错误信息没什么意义。所以,最好的方式是,开发者在代码中定义propTypes,但在发布产品代码时,用一种自动的方式将propTypes去掉。现有的babel-react-optimize具有这个功能,可以通过npm安装,但是应该确保只在发布产品代码时使用它。

6.初始化state:
通常在组件类的构造函数结尾处初始化state,如下:
constructor(props){
......
this.state = {
count:props.initValue || 0
}
}
因为initValue是一个可选的props,考虑到父组件没有指定这个props值的情况,我们优先使用传入属性的initVlue,如果没有,就使用默认值0。
组件的state必须是一个JavaScript对象!!!
以上,可使用React的defaultProps功能,如下:
Counter.defaultProps = {0}

7.改变组件的state,如下:
onClickIncrementButton () {
this.setState({count : this.state.count + 1})
}
在代码中,this.state可以读取到组件当前的state。注意:改变组件state必须要使用this.setState函数而不能直接去修改this.state。直接修改this.state的值,虽然事实上改变了组件的内部状态,但只是野蛮的修改了state,并没有驱动组件进行重新渲染,这样就无法反应this.state值的变化;而this.setState()函数所做的事情,首先是改变this.state的值,然后驱动组件经历更新过程,这样才有机会让this.state里新的值出现在界面上。

猜你喜欢

转载自blog.51cto.com/chengyanli/2310861