React从入门到精通系列之(22)React.Component用法

二12、React.Component用法

组件(Components)容许您将UI拆分为独立的可重用的部分,并单独的考虑每一个部分。javascript

总览

React.Component是一个抽象基类。这意味着直接引用React.Component是毫无心义的。你能够实现一个它的子类,而且至少定义一个render()方法便可使用。java

你可使用ES6中class定义一个React组件:ajax

class Greeting extends React.Component {
    render() {
        return <h1>Hello, {this.props.name}</hr>;
    }
}

若是你尚未使用ES6,你可使用React.createClass()编程

组件的生命周期方法

每一个组件都有几个『生命周期方法』,您能够重写这些方法,已便在React执行过程当中的指定时间运行本身的代码。前缀为Will的生命周期方法会在在一些事情发生以前被调用,带有Did前缀的方法在某些事情发生以后被调用。浏览器

Mounting(加载组件)

当建立组件的实例并将其插入DOM时,会依次调用这些方法:服务器

  • constructor()网络

  • componentWillMount()函数式编程

  • render()函数

  • componentDidMount()性能

Updating(更新状态)

更新能够由prop或者state的改变引发。在从新渲染组件时依次调用这些方法:

  • componentWillReceiveProps()

  • shouldComponentUpdate()

  • componentWillUpdate()

  • render()

  • componentDidUpdate()

Unmounting(卸载组件)

当从DOM中删除组件时,将调用此方法:

  • componentWillUnmount()

其余API

每一个组件还提供了一些其余API:

  • setState()

  • forceUpdate()

组件属性

  • defaultProps

  • displayName

  • propTypes

实例内部属性

  • props

  • state


使用方法

render()

render() {
    // return React Elements
}

注意:render()方法是必须写的。

当这个方法被调用时,它会检测this.propsthis.state并返回一个React元素。此元素能够是本地DOM组件的形式,例如<div/>,也能够是您本身定义的一个复合组件。

你也能够返回nullfalse来表示你不想作任何渲染操做。当返回nullfalse时,ReactDOM.findDOMNode(this)将返回null

render()方法应该是纯的(pure function,见函数式编程),这意味着它并不会修改组件state,每次调用它时都会返回相同的结果,它不会直接与浏览器交互。若是您须要与浏览器直接交互,请改用componentDidMount()方法或者其余生命周期方法来执行你的逻辑。保持render()可让组件更容易去思考本身应该作什么。

提示
若是shouldComponentUpdate()返回false,那么render()不会被执行。


constructor()

constructor(props)

在装载组件(mounting)以前调用会React组件的构造函数。当实现React.Component子类的构造函数时,应该在任何其余语句以前调用super(props)。不然,this.props将在构造函数中未定义,这可能致使错误。

构造函数是初始化state的标准位置。若是不初始化state,而且不绑定组件内部方法的this指向,则不须要为React组件实现构造函数。

若是你知道你在作什么的话,你能够根据props来初始化state。这里有一个有效的React.Component子类构造函数的例子:

constructor(props) {
    super(props);
    this.state = {
        color: props.initialColor
    };
}

注意这种模式,由于它会将props复制一份在state中,这就可能致使一个意外的bug。因此不该该将props复制到state中。相反,你须要使用提高state的技巧,该技巧咱们在前面的文章提到过。

若是你使用props复制到state中,你还须要实现componentWillReceiveProps(nextProps)来保持state是最新的。这个时候使用提高state的方法反而会更容易,也能产生更少的bug。


componentWillMount()

componentWillMount()

componentWillMount()是在装载(mounting)发生以前被调用。它在render()以前调用,因此在此方法中的设置state不会形成从新渲染。另外,应该避免在此方法中引入有任何反作用的东西(见函数式编程)

在服务器渲染上这是惟一一个调用的生命周期钩子函数。通常来讲,咱们建议使用constructor()


componentDidMount()

componentDidMount()

componentDidMount()在组件装载到DOM后当即调用。若是须要进行DOM节点的初始化则应该在这里来执行该逻辑。若是须要从远程端点加载数据(ajax),那么这是处理网络请求的最好地方。在此方法中设置state会去从新渲染DOM。


componentWillReceiveProps()

componentWillReceiveProps(nextProps)

componentWillReceiveProps()在安装好的组件接收新props以前被调用。 若是你须要更新state用来响应props的更改(例如,重置它),你能够在此方法中比较this.propsnextProps并使用this.setState()来替换并重置state。

注意,即便props没有改变,React也能够调用这个方法,所以若是你只想处理props改变的状况,请确保比较当前值和下一个值是否不一样。 当父组件引发你的组件从新渲染时,就有可能会发生这种状况。

若是你只是调用this.setState(),那么componentWillReceiveProps()不会被调用。


shouldComponentUpdate()

shouldComponentUpdate(nextProps, netState)

使用shouldComponentUpdate()让React知道组件是否受当前state或props变化的影响。 默认行为是在每次state更改时都会去从新渲染DOM,在绝大多数状况下,你应该依赖于这个默认行为。

当接收到新的props或state时,shouldComponentUpdate()在渲染以前被调用。 默认为true对于初始渲染或使用forceUpdate(),不调用此方法。

返回false不会阻止子组件在state更改时从新渲染。

目前,若是shouldComponentUpdate()返回false,那么将不会调用componentWillUpdate()render()componentDidUpdate()。 注意,在未来React能够将shouldComponentUpdate()做为提示而不是严格的操做指令,返回false仍然可能致使组件的从新渲染。

若是你肯定某些组件在某些操做时有点缓慢,你可让它继承React.PureComponent,而不是继承React.Component

React.PureComponent实现了propsstate进行浅比较的shouldComponentUpdate()方法。 若是你肯定想人肉处理这个浅比较操做,你能够本身在这个函数中比较this.propsnextPropsthis.statenextState是否相同。相同返回false,不一样返回true,那么React就会根据返回值来确认是否跳过本次DOM渲染。


componentWilUpdate()

componentWillUpdate(nextProps, nextState)

当组件在收到新的props或state时,componentWillUpdate()在渲染以前会当即调用这个方法。 使用这个方法来判断是非须要从新渲染DOM。 第一次渲染DOM不调用此方法。

注意,this.setState()不会调用此方法。 若是你须要根据state和props来进行从新渲染DOM,请改用componentWillReceiveProps()

note
若是shouldComponentUpdate()返回false,则不会调用componentWillUpdate()


componentDidUpdate()

componentDidUpdate(prevProps, prevState)

componentDidUpdate()在从新渲染DOM以后被调用。 第一次渲染不调用此方法。

当组件已经从新渲染后,此方法是一个执行DOM操做的好机会,同时也是一个处理网络请求的好地方,前提是你须要比较当前props与以前的props是否相同(例如,若是props没有改变,那么可能不须要进行网络请求)。

note
若是shouldComponentUpdate()返回false,则不会调用componentDidUpdate()


componentWillUnmount()

componentWillUnmount()

componentWillUnmount()在组件被卸载和销毁以前当即被调用。 此方法能够执行任何有必要的清理工做,例如清理计时器,取消网络请求或清理在componentDidMount()中建立的DOM元素。


setState()

setState(nextState, callback)

将nextState和当前state进行浅合并。 这是用于从事件处理函数和服务器请求回调中触发UI从新渲染的主要方法。

第一个参数能够是一个对象(包含一个或多个要更新的state属性),也能够是返回将要引发从新渲染的对象(state和props)。

这里有一个简单的用法:

this.setState({myKey: 'my new value'});

它也能够传入一个带有参数的函数function(state,props)=> newState。 例如,假设咱们想要当前state中的myInteger加上props.step:

this.setState(prevState, props) => {
    return {myInteger: prevState.myInteger + props.step};
}

第二种参数是回调函数,一旦setState完成而且组件被从新渲染,它就会被执行。 一般咱们建议使用componentDidUpdate()代替这样的逻辑。

setState()不会当即改变this.state,但会建立并挂起state的修改。 因此在调用此方法中访问this.state可能会返回现有值。

不能保证对setState的因此调用都是同步操做,由于这样作是为了将屡次state修改合并为一次以便提升性能。

setState()总会从新渲染DOM,除非shouldComponentUpdate()回false。 若是你正在使用可突变对象,而且没法在shouldComponentUpdate()实现条件渲染逻辑,则只有当新state与先前state不一样时调用setState()才能避免没必要要的从新渲染。


forceUpdate()

component.forceUpdate(callback)

默认状况下,当组件的state或props改变时,组件将从新渲染。 若是你的render()方法依赖于一些其余数据,你能够告诉React组件须要经过调用forceUpdate()来从新渲染。

调用forceUpdate()会致使在组件上调用render(),跳过shouldComponentUpdate() 这将触发子组件的正常生命周期方法,包括每一个子组件的shouldComponentUpdate()方法。 若是标记更改,React仍将更新DOM。

一般你应该尽可能避免forceUpdate()的全部使用,而且只能从render()中的this.propsthis.state中读取。


类属性

defaultProps

defaultProps是类组件自己的属性,用来设置类组件的默认props。 能够用来给未传入值的props设置默认值。 例如:

class CustomButton extends React.Component {
    // ...
}
CustomButton.defaultProps = {
    color: 'blue';
}

若是props.color没有定义,就是将它设置为默认值blue

render() {
    return <CustomButton />; // props.color will be set to blue
}

若是props.color被设置为null,那么它将会被从新赋值为null:

render() {
    return <CustomButton color={null} />; // props.color will remain null
}

displayName

displayName字符串用于调试消息。 JSX自动设置此值;


propTypes

propTypes也是类组件自己上的一个属性,用来规范props应该是什么类型。 它是从props的名称到React.PropTypes中定义的类型的映射。 在开发模式下,当为prop设置一个不是指定格式的无效值时,会在JavaScript控制台中显示警告信息。 在生产模式下,为了提升效率,不会进行propTypes检查。

例如,此代码确保颜色prop是一个字符串:

class CustomButton extends React.Component {
    // ...
}
CustomButton.propTypes = {
   color: React.PropTypes.string
};

咱们建议尽量使用Flow,以便在编译时进行类型检查,而不是在运行时进行类型检查。 Flow在React中内置支持,所以能够轻松地在React应用程序上运行静态分析。

// @flow
function foo(x) {
  return x * 10;
}
foo('Hello, world!');

// @flow
function bar(x): string {
  return x.length;
}
bar('Hello, world!');

实例属性

props

this.props包含由此组件的调用者定义的props

特别地,this.props.children是一个特殊的props,一般由JSX表达式中的子标签而不是标签自己定义。

state

state包含特定于此组件的数据,可能随时间更改。 state是用户定义的,它应该是纯JavaScript对象。

若是你不在render()中使用它,它不该该设置state。 例如,您能够将定时器ID直接放在实例上。

永远不要直接改变this.state,由于调用setState()以后能够替换你所作的各类变化, 一般应该把this.state看做是不可变的。