组件的定义
React组件你可以把它看作是一个带有props属性集合和state状态集合并且构造出一个虚拟DOM结构的对象。
组件是React的核心、精髓。组件有输入、输出以及自身状态,分别对应props、render、state。
定义组件的三种方式
- 函数式定义的无状态组件
创建无状态函数式组件形式是从React 0.14版本开始出现的。它是为了创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到要state状态的操作。
在大部分React代码中,大多数组件被写成无状态的组件,通过简单组合可以构建成其他的组件等;这种通过多个简单然后合并成一个大应用的设计模式被提倡。
无状态函数式组件形式上表现为一个只带有一个render方法的组件类,通过函数形式或者ES6箭头function的形式在创建,并且该组件是无state状态的。具体的创建形式如下:
function HelloComponent(props, /* context */) {
return <div>Hello {props.name}</div>
}
ReactDOM.render(<HelloComponent name="Sebastian" />, mountNode)
- es5原生方式React.createClass定义的组件
var InputControlES5 = React.createClass({
propTypes: { // 定义传入props中的属性各种类型
initialValue: React.PropTypes.string
},
defaultProps: { // 组件默认的props对象
initialValue: ''
},
// 设置 initial state
getInitialState: function() { // 组件相关的状态对象
return {
text: this.props.initialValue || 'placeholder'
};
},
handleChange: function(event) {
this.setState({ // this represents react component instance
text: event.target.value
});
},
render: function() {
return (
<div>
Type something:
<input onChange={this.handleChange} value={this.state.text} />
</div>
);
}
});
InputControlES6.propTypes = {
initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
initialValue: ''
};
这是react以前推荐的用法,有以下缺点:
-
react.createClass会自绑定函数方法(不像React.Component只绑定需要关心的函数)导致不必要的性能开销,增加代码过时的可能性。
-
React.createClass的mixins不够自然、直观;React.Component形式非常适合高阶组件(Higher Order Components--HOC),它以更直观的形式展示了比mixins更强大的功能,并且HOC是纯净的JavaScript,不用担心他们会被废弃。HOC可以参考《无状态组件(Stateless Component) 与高阶组件》。
- es6形式的extends React.Component定义的组件 React.Component是以ES6的形式来创建react的组件的,是React目前极为推荐的创建有状态组件的方式,最终会取代React.createClass形式;相对于 React.createClass可以更好实现代码复用。将上面React.createClass的形式改为React.Component形式如下:
class InputControlES6 extends React.Component {
constructor(props) {
super(props);
// 设置 initial state
this.state = {
text: props.initialValue || 'placeholder'
};
// ES6 类中函数必须手动绑定
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
text: event.target.value
});
}
render() {
return (
<div>
Type something:
<input onChange={this.handleChange}
value={this.state.text} />
</div>
);
}
}
InputControlES6.propTypes = {
initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
initialValue: ''
};
注意事项
- 组件名字的首字母必须要大写,否则会报错!这与HTML元素名的写法是不同的。
- 组件当中只能包含一个顶层标签,否则也会报错
- 通过函数来定义一个组件,该函数名即是组件的名字
function MyComponent(){
// 返回的内容即是组件的内容
return <div>此时此刻我想吟诗一首!</div>;
}
函数组件和类组件(算是另一种叫法吧,知道就可以了)
函数组件
通过函数定义的组件就是函数组件,又叫无状态组件,
function HelloComponent(props, /* context */) {
return <div>Hello {props.name}</div>
}
ReactDOM.render(<HelloComponent name="Sebastian" />, mountNode)
类组件
通过es5原生方式React.createClass或es6形式的extends React.Component定义的组件叫类组件,因为都继承了React中Component类中的方法和属性。
注意:
- 无论是使用函数或是类来声明一个组件,它决不能修改它自己的 props。
- 所有 React 组件都必须是纯函数,并禁止修改其自身 props 。
- React是单项数据流,父组件改变了属性,那么子组件视图会更新。
- 属性 props 是外界传递过来的,状态 state 是组件本身的,状态可以在组件中任意修改
- 组件的属性和状态改变都会更新视图。
受控组件和非受控组件
受控组件
组件渲染出的状态与他的value或checked属性相对应,react通过这种方式消除了组件的局部状态,使整个状态可控。
// 表单组件
import React, { Component } from 'react'
export default class MyInput extends Component{
handleContentChange = (e)=>{
this.setState({
content: e.target.value
})
}
render(){
return(
<div>
<input
type="text"
value={this.state.value}
onChange={this.handleContentChange}
/>
</div>
)
}
}
受控组件更新state的流程:
- 可以通过初始state中设置表单的默认值
- 每当表单的值发生变化时,调用onChange事件处理器
- 事件处理器通过事件对象e拿到改变后的状态,并更新组件的state
- 一旦通过setState方法更新state,就会触发视图的重新渲染,完成表单组件的更新
非受控组件
如果一个表单组件没有value props(单选和复选按钮对应的是checked props)时,就可以称为非受控组件。
在非受控组件中,我们可以使用一个ref来从DOM获得表单值。而不是为每个状态更新编写一个事件处理程序。
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={(input) => this.input = input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
组件嵌套
定义一个组件,在另一个组件中引入并使用
// 父组件
import React, { Component } from 'react'
import Son from './Son.js' // 引入子组件
export default class Father extends Component{
render(){
return(
<div clasName="father">
<Son/>
<Son></Son> // 两种写发都可以
</div>
)
}
}
// 子组件
import React, { Component } from 'react'
export default class Son extends Component{
render(){
return(
<div clasName="son">
我是子组件
</div>
)
}
}
总结
创建组件,能用无状态组件最好用无状态组件,里面不能使用prop和state等,如果业务比较复杂的话,使用es6的extends React.Component定义的组件
参考文献: