美文网首页
React:createClass 和 extends Comp

React:createClass 和 extends Comp

作者: WittyLu | 来源:发表于2018-06-19 21:28 被阅读0次

    原文链接

    写React的时候,你是应该用React.createClass语法还是ES6的class语法呢?或者都不?这篇文章将会解释一些二者之间的差异来帮助你做选择。

    React可以用ES5或ES6完美书写。

    使用JSX意味着你将通过Babel将JSX通过“build”转化为React.createElement调用。很多人利用这个特点在Babel的编译列表中添加一些es2015的语法以此来让ES6完全可用。

    如果你正在使用Quik或是React Heatpack,这已经为你配置好了(如果你还没有安装环境,请阅读quick start React)。

    比较 createClass 和 class

    以下是使用React.createClass和ES6的class书写相同的组件:

    var InputControlES5 = React.createClass({
      propTypes: {
        initialValue: React.PropTypes.string
      },
      defaultProps: {
        initialValue: ''
      }, // Set up initial state
      getInitialState: function() {
        return {
          text: this.props.initialValue || 'placeholder' 
        };
      },
      handleChange: function(event) {
        this.setState({
          text: event.target.value
        });
      },
      render: function() {
        return (
          <div>
            Type something:
            <input onChange={this.handleChange} 
              value={this.state.text} />
            </div> 
          );
        }
    });
    
    
    class InputControlES6 extends React.Component { 
      constructor(props) {
        super(props); 
        // Set up initial state
        this.state = {
          text: props.initialValue || 'placeholder' 
        };
        // Functions must be bound manually with ES6 classes
        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: ''
    };
    
    

    以下是一些关键的不同点:

    函数的绑定

    这或许是最大的一个变化点

    使用createClass, 每一个函数属性都会被React自动绑定。指的是this.whateverFn这样的函数在任何你需要调用的时候都会自动为你绑定正确的this

    在ES6的class中,就不同了: 函数不再被自动绑定。你需要手动去绑定它们。最好的地方就是和以上例子一样,在构造函数里。

    如果你不想非要手动打印所有的绑定操作,也可以通过react-autobind或者autobind-decorator来检查。

    另一种方式就是在你使用的地方通过内联来绑定:

    // Use `.bind`:
      render() { 
        return (
          <input onChange={this.handleChange.bind(this)}
            value={this.state.text} /> 
        );
    }
    // --- OR ---
    
    // Use an arrow function:
    render() {
      return (
        <input onChange={() => this.handleChange()} 
          value={this.state.text} />
      );
    }
    
    

    以上任意一种都可以,然而在效率上却不行了。每一次调用render(可以说是非常频繁!)一个新的函数都会被创建。与在构造函数里只绑定一次相比就慢一些。

    最终的选择是使用箭头函数直接替换函数在类中的声明,像这样:

    // the normal way
    // requires binding elsewhere
    handleChange(event) {
      this.setState({
        text: event.target.value
      });
    }
    // the ES7 way
    // all done, no binding required
    handleChange = (event) => { 
      this.setState({
        text: event.target.value
      });
    }
    
    

    通过这种方式,你不需要绑定任何东西。这都已经通过神奇的箭头函数被搞定了。像期望的那样,函数内部的this将会指向组件实例。

    唯一的注意的地方就是这仅是一个"试验性" 的特性,意味着这不是官方的ES6规范。但是这依旧可以通过设置babel为"stage-0"来支持。如果你喜欢这种语法(被称作“把handleChange设置为带event的箭头函数”),试试吧。

    构造函数应该调用super

    ES6类的constructor需要接收props并且调用super(props)。这是createClass所没有的一点。

    class和createClass的比较

    这个很明显,一个调用React.createClass并传入一个对象,另一个则是使用class继承React.Component

    小提示: 导入Component时如果在一个文件里包含多个组件,可以直接通过以下方式节省一些代码量:
    import React, {Component} from 'react'

    初始化State的设置

    createClass 接受一个只会在组件被挂载时才会调用一次的initialState函数。

    ES6 的class则使用构造函数。在调用super之后,可以直接设置state。

    propTypes 和 defaultProps 的设置

    使用createClass时,在传入的对象上定义一个propTypesdefaultProps作为属性。

    使用ES6的类,这些将会成为类本身的属性,因此它们可以在类定义之后补充上。

    如果你开启了ES7属性初始化,这里还有些捷径:

    class Person extends React.Component { 
      static propTypes = { 
        name: React.PropTypes.string, 
        age: React.PropTypes.string 
      }; 
      static defaultProps = { 
        name: '', 
        age: -1 
      }; 
      ...
    }
    
    

    第三种选择

    createClassclass以外,React也支持“无状态函数式组件”。基本上,这仅是一个不能有state的函数,并且它不能使用像componentWillMountshouldComponentUpdate这样的任何生命周期方法。无状态函数式组件对仅仅接受并依赖props渲染的简单组件来讲很棒,以下是几个例子:

    function Person({firstName, lastName}) { 
      return ( 
        <span>{lastName}, {firstName}</span> 
      );
    }
    
    

    这利用ES6的解构将传入的props分解开来,但也可以这么写:

    function Person(props) { 
      var firstName = props.firstName; 
      var lastName = props.lastName; 
      return ( 
        <span>{lastName}, {firstName}</span> 
      );
    }
    
    

    用哪个才对呢?

    Facebook已经声明了React.createClass将最终会被ES6的classes替代,但是他们也说“在我们找到当前mixin所使用的例子的替代者以及在语言上支持类属性的初始化器前,我们不打算废弃React.createClass”。

    在任何可以使用无状态函数式组件的地方使用它。简单而且会强制性地简化你的组件。

    对于一些需要state,生命周期方法或是通过ref来操作潜在的DOM节点的复杂组件来讲,请使用class。

    尽管知道这三种写法风格很棒,但在StackOverflow或者其他地方查找解决方案时可能仍会看到一些混杂着ES5和ES6写法的答案。ES6风格已经非常流行了但这不会是你看到的唯一一种写法。

    From:React: ES5 (createClass) 还是 ES6 (class)? (译)
    可参考:createClass 和 extends Component的区别

    相关文章

      网友评论

          本文标题:React:createClass 和 extends Comp

          本文链接:https://www.haomeiwen.com/subject/gipzeftx.html