谈一谈建立React Component的几种体式格局

当我们谈起React的时刻,多数会将注意力集合在组件之上,思索怎样将页面划分红一个个组件,以及怎样编写可复用的组件。但关于打仗React不久,还没有真正用它做一个完整项目的人来讲,明白怎样建立一个组件也并不那末简朴。在最最先的时刻我认为建立组件只须要挪用createClass这个api就可以了;但进修了ES6的语法后,又晓得了可以应用继续,经由过程extends React.component来建立组件;厥后在浏览他人代码的时刻又发明了PureComponent以及完整没有继续,仅仅经由过程返回JSX语句的体式格局建立组件的体式格局。下面这篇文章,就将一一引见这几种建立组件的要领,剖析其特性,以及怎样挑选运用哪种体式格局建立组件。

几种要领

1.createClass

假如你还没有运用ES6语法,那末定义组件,只能运用React.createClass这个helper来建立组件,下面是一段示例:

var React = require("react");
var Greeting = React.createClass({
  
  propTypes: {
    name: React.PropTypes.string //属性校验
  },

  getDefaultProps: function() {
    return {
      name: 'Mary' //默许属性值
    };
  },
  
  getInitialState: function() {
    return {count: this.props.initialCount}; //初始化state
  },
  
  handleClick: function() {
    //用户点击事宜的处置惩罚函数
  },

  render: function() {
    return <h1>Hello, {this.props.name}</h1>;
  }
});
module.exports = Greeting;

这段代码,包括了组件的几个症结组成部分,这类体式格局下,组件的props、state等都是以对象属性的体式格局组合在一起,个中默许属props和初始state都是返回对象的函数,propTypes则是个对象。这里另有一个值得注意的事变是,在createClass中,React对属性中的一切函数都举行了this绑定,也就是如上面的hanleClick实在相当于handleClick.bind(this)

2.component

由于ES6对类和继续有语法级别的支撑,所以用ES6建立组件的体式格局越发文雅,下面是示例:

import React from 'react';
class Greeting extends React.Component {

  constructor(props) {
    super(props);
    this.state = {count: props.initialCount};
    this.handleClick = this.handleClick.bind(this);
  }
  
  //static defaultProps = {
  //  name: 'Mary'  //定义defaultprops的另一种体式格局
  //}
  
  //static propTypes = {
    //name: React.PropTypes.string
  //}
  
  handleClick() {
    //点击事宜的处置惩罚函数
  }
  
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

Greeting.propTypes = {
  name: React.PropTypes.string
};

Greeting.defaultProps = {
  name: 'Mary'
};
export default Greating;

可以看到Greeting继续自React.component,在组织函数中,经由过程super()来挪用父类的组织函数,同时我们看到组件的state是经由过程在组织函数中对this.state举行赋值完成,而组件的props是在类Greeting上建立的属性,假如你对类的属性对象的属性的区分有所相识的话,也许能明白为何会这么做。关于组件来讲,组件的props是父组件经由过程挪用子组件向子组件通报的,子组件内部不应当对props举行修正,它更像是一切子组件实例同享的状况,不会由于子组件内部操纵而转变,因而将props定义为类Greeting的属性更加合理,而在面向对象的语法中类的属性一般被称作静态(static)属性,这也是为何props还可以像上面解释掉的体式格局来定义。关于Greeting类的一个实例对象的state,它是组件对象内部坚持的状况,经由过程用户操纵会修正这些状况,每一个实例的state也可以差别,彼此间不相互影响,因而经由过程this.state来设置。

用这类体式格局建立组件时,React并没有对内部的函数,举行this绑定,所以假如你想让函数在回调中坚持准确的this,就要手动对须要的函数举行this绑定,如上面的handleClick,在组织函数中对this 举行了绑定。

3.PureComponet

我们晓得,当组件的props或许state发生变化的时刻:React会对组件当前的Props和State离别与nextProps和nextState举行比较,当发明变化时,就会对当前组件以及子组件举行从新衬着,不然就不衬着。有时刻为了防止组件举行不必要的从新衬着,我们经由过程定义shouldComponentUpdate来优化机能。比方以下代码:

class CounterButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: 1};
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (this.props.color !== nextProps.color) {
      return true;
    }
    if (this.state.count !== nextState.count) {
      return true;
    }
    return false;
  }

  render() {
    return (
      <button
        color={this.props.color}
        onClick={() => this.setState(state => ({count: state.count + 1}))}>
        Count: {this.state.count}
      </button>
    );
  }
}

shouldComponentUpdate经由过程推断props.colorstate.count是不是发生变化来决议需不须要从新衬着组件,固然有时刻这类简朴的推断,显得有些过剩和榜样化,因而React就供应了PureComponent来自动帮我们做这件事,如许就不须要手动来写shouldComponentUpdate了:

class CounterButton extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {count: 1};
  }

  render() {
    return (
      <button
        color={this.props.color}
        onClick={() => this.setState(state => ({count: state.count + 1}))}>
        Count: {this.state.count}
      </button>
    );
  }
}

大多数情况下, 我们运用PureComponent可以简化我们的代码,而且进步机能,然则PureComponent的自动为我们增加的shouldComponentUpate函数,只是对props和state举行浅比较(shadow comparison),当props或许state本身是嵌套对象或数组等时,浅比较并不能取得预期的效果,这会致使现实的props和state发生了变化,但组件却没有更新的题目,比方下面代码有一个ListOfWords组件来将单词数组拼接成逗号分开的句子,它有一个父组件WordAdder让你点击按钮为单词数组增加单词,但他并不能一般事情:

class ListOfWords extends React.PureComponent {
  render() {
    return <div>{this.props.words.join(',')}</div>;
  }
 }
 
class WordAdder extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      words: ['marklar']
    };
    this.handleClick = this.handleClick.bind(this);
  }
  
  handleClick() {
    // 这个处所致使了bug
    const words = this.state.words;
    words.push('marklar');
    this.setState({words: words});
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick} />
        <ListOfWords words={this.state.words} />
      </div>
    );
  }
}

这类情况下,PureComponent只会对this.props.words举行一次浅比较,虽然数组内里新增了元素,然则this.props.words与nextProps.words指向的还是同一个数组,因而this.props.words !== nextProps.words 返回的就是flase,从而致使ListOfWords组件没有从新衬着,笔者之前就由于对此不太相识,而随便运用PureComponent,致使state发生变化,而视图就是不更新,调了良久找不到缘由~。

最简朴防止上述情况的体式格局,就是防止运用可变对象作为props和state,取而代之的是每次返回一个全新的对象,以下经由过程concat来返回新的数组:

handleClick() {
  this.setState(prevState => ({
    words: prevState.words.concat(['marklar'])
  }));
}

你可以斟酌运用Immutable.js来建立不可变对象,经由过程它来简化对象比较,进步机能。
这里还要提到的一点是虽然这里虽然运用了Pure这个词,然则PureComponent并非纯的,由于关于纯的函数或组件应当是没有内部状况,关于stateless component更相符纯的定义,不相识纯函数的同砚,可以拜见这篇文章

4.Stateless Functional Component

上面我们提到的建立组件的体式格局,都是用来建立包括状况和用户交互的庞杂组件,当组件本身只是用来展现,一切数据都是经由过程props传入的时刻,我们便可以运用Stateless Functional Component来疾速建立组件。比方下面代码所示:

import React from 'react';
const Button = ({
  day,
  increment
}) => {
  return (
    <div>
      <button onClick={increment}>Today is {day}</button>
    </div>
  )
}

Button.propTypes = {
  day: PropTypes.string.isRequired,
  increment: PropTypes.func.isRequired,
}

这类组件,没有本身的状况,雷同的props输入,必然会取得完整雷同的组件展现。由于不须要体贴组件的一些性命周期函数和衬着的钩子,所以不必继续自Component显得更简约。

对照

createClass vs Component

关于React.createClassextends React.Component本质上都是用来建立组件,他们之间并没有相对的优劣之分,只不过一个是ES5的语法,一个是ES6的语法支撑,只不过createClass支撑定义PureRenderMixin,这类写法官方已不再引荐,而是发起运用PureComponent。

pureComponent vs Component

经由过程上面临PureComponent和Component的引见,你应当已相识了两者的区分:PureComponent已定义好了shouldUpdateComponentComponent须要显现定义。

Component vs Stateless Functional component

  1. Component包括内部state,而Stateless Functional Component一切数据都来自props,没有内部state;

  2. Component 包括的一些性命周期函数,Stateless Functional Component都没有,由于Stateless Functional component没有shouldComponentUpdate,所以也无法控制组件的衬着,也等于说只如果收到新的props,Stateless Functional Component就会从新衬着。

  3. Stateless Functional Component 不支撑Refs

选哪一个?

这里仅列出一些参考:

  1. createClass, 除非你确切对ES6的语法一无所知,不然的话就不要再运用这类体式格局定义组件。

  2. Stateless Functional Component, 关于不须要内部状况,且用不到性命周期函数的组件,我们可以运用这类体式格局定义组件,比方展现性的列表组件,可以将列表项定义为Stateless Functional Component。

  3. PureComponent/Component,关于具有内部state,运用性命周期的函数的组件,我们可以运用两者之一,然则大部分情况下,我更引荐运用PureComponent,由于它供应了更好的机能,同时强迫你运用不可变的对象,坚持优越的编程习气。

参考文章

optimizing-performance.html#shouldcomponentupdate-in-action
pureComponent引见
react-functional-stateless-component-purecomponent-component-what-are-the-dif
4 different kinds of React component styles
react-without-es6
react-create-class-versus-component

    原文作者:布利丹牵驴子
    原文地址: https://segmentfault.com/a/1190000008402834
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞