react之组件

564 阅读5分钟

组件的定义

React组件你可以把它看作是一个带有props属性集合和state状态集合并且构造出一个虚拟DOM结构的对象。

组件是React的核心、精髓。组件有输入、输出以及自身状态,分别对应props、render、state。

定义组件的三种方式

  1. 函数式定义的无状态组件

创建无状态函数式组件形式是从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) 
  1. 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) 与高阶组件》。

  1. 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: ''
};

注意事项

  1. 组件名字的首字母必须要大写,否则会报错!这与HTML元素名的写法是不同的。
  2. 组件当中只能包含一个顶层标签,否则也会报错
  3. 通过函数来定义一个组件,该函数名即是组件的名字
    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类中的方法和属性。

注意:

  1. 无论是使用函数或是类来声明一个组件,它决不能修改它自己的 props。
  2. 所有 React 组件都必须是纯函数,并禁止修改其自身 props 。
  3. React是单项数据流,父组件改变了属性,那么子组件视图会更新。
  4. 属性 props 是外界传递过来的,状态 state 是组件本身的,状态可以在组件中任意修改
  5. 组件的属性和状态改变都会更新视图。

受控组件和非受控组件

受控组件

组件渲染出的状态与他的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的流程:

  1. 可以通过初始state中设置表单的默认值
  2. 每当表单的值发生变化时,调用onChange事件处理器
  3. 事件处理器通过事件对象e拿到改变后的状态,并更新组件的state
  4. 一旦通过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定义的组件

参考文献:

React创建组件的三种方式及其区别