zoukankan      html  css  js  c++  java
  • React 组件构造方法: ES5 (createClass) 还是 ES6 (class)?

    写 React 组件的时候,应该使用 React.createClass 语法还是 ES6 的 class 语法?或两者都不?这篇文章解释了两者之间的一些差异,希望能帮你做决定。

    用 ES5 或 ES6 都可以完美地写 React 组件。

    使用 JSX 意味着你已经需要一个「构建」步骤,也就是 Babel 将 JSX 转译(transpile)为 React.createElement 调用。很多人充分利用这点, 仅仅向 Babel 的转译列表中添加一项 es2015,就可以自由使用 ES6 的全部特性。

    如果你在使用类似 Quik 或 React Heatpack 的工具,ES6 就已经为你配置好了。(如果你还没配置过环境可以读一下quick start React(英文))

    比较:createClass vs class

    下面是同一个组件分别使用 React.createClass 和 ES6 class 的例子:

    var InputControlES5 = React.createClass({
        propTypes: {
            initialValue: React.PropTypes.string
        },
        defaultProps: {
            initialValue: ''
        },
        // 设置 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);
    
            // 设置 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: ''
    };
    

    以下是几点关键区别:

    函数绑定

    这可能是最容易犯错的点(tripping point)。

    用 createClass 很简单:每一个成员函数都由 React 自动绑定。任何时候需要调用,直接使用 this.whateverFn 即可,函数中的 this 变量在函数调用时会被正确设置。

    用 ES6 class 需要当心:函数不是自动绑定的。你必须手动绑定。最好是在构造函数中做这事,就像上面的例子那样。

    如果你不想总是手动敲这些函数绑定的代码,可以看看 react-autobind 或 autobing-decorator

    另一个方法是行内绑定,像下面这样:

    // 使用 `.bind`:
    render() {
        return (
            <input onChange={this.handleChange.bind(this)}
               value={this.state.text} />
        );
    }
    
    // --- 或 ---
    
    // 使用胖箭头函数:
    render() {
        return (
            <input onChange={() => this.handleChange()}
               value={this.state.text} />
        );
    }
    

    以上任何一种方法都行的通,但都不如前文的方法有效率。因为每次render 方法被调用的时候(这个调用会相当频繁)就会有一个新的函数被创建。相比于在构造函数中做仅仅一次函数绑定,这个方法会慢一些。

    还有一个最终选项是将函数自身替换为胖箭头函数,像这样:

    // 通常的做法
    // 需要在别处绑定
    handleChange(event) {
        this.setState({
            text: event.target.value
        });
    }
    
    // ES7 做法
    // 搞定,不需要另外绑定
    handleChange = (event) => {
        this.setState({
            text: event.target.value
        });
    }
    

    使用这个方法,你不需要做任何绑定。胖箭头函数的魔法会帮你全部搞定。函数内部的 this 变量会像预期的那样指向组件实例。

    唯一的警告是,胖箭头函数是一个「实验性」的特性,也就是说并不在官方的 ES6 标准中。但是它受 Babel 支持,只要启用“stage-0” 预置(preset)即可。如果你喜欢胖箭头语法(读作「令 handleChange 为一个以事件为参数的胖箭头函数),试试看。

    构造函数是否调用 super 方法

    ES6 类构造器需要接受 props 作为参数并调用 super(call)createClass 并不需要这步,相比之下多了点例行公事(boilerplate)。

    class vs createClass

    这一点显而易见。后者以一个对象为参数调用 React.createClass 方法,前者使用 class 扩展 React.Component 类。

    专家提示: 如果你在一个文件中有多个组件,可以直接引入 Component 少打些字:import React, {Component} form 'react'

    Initial State 配置

    createClass 方法接受一个 getInitialState (译者注:原文误作 initialState)函数作为参数一部分,这个函数会在组件挂载(mount)时被调用一次。

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

    propTypes 和 defaultProps 的位置

    使用 createClass 的时候,将 propTypes 和 defaultProps 作为你传入的对象的属性。

    使用 ES6 class 的时候,这些变成了类本身的属性,所以他们需要在类定义完之后被加到类上。

    如果你开启了 ES7 的属性初始化器(property initializer),可以使用下面的简写法:

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

    忍者第三选项

    除了 createClass 和 class 外, React 还支持所谓的「无状态(stateless)函数组件」。本质上它就是一个函数,没有 state,并且不能使用任何诸如 componentWillMount 或 shouldComponentUpdate 的生命周期方法。对于接受某些 props 并直接基于这些 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 class 取代,不过他们也说「我们不会废弃 React.createClass,直到我们找到目前 mixin 用例的替代方案,并且在语言中支持类属性初始化器」。

    只要有可能,尽量使用无状态函数组件。他们很简单,也会迫使你保持 UI 组件简单。

    对于需要 state、生命周期方法、或(通过 refs)访问底层 DOM 节点的复杂组件,使用 class。

    不过了解全部三种风格总是有好处的。当你在 StackOverflow 或别的地方查问题的时候,你可能会看到 ES5 和 ES6 两种风格的答案。ES6 风格正在积聚人气,但并不是唯一的风格。

    总结

    可以使用多种方式写 React 组件,我希望这篇概述能帮助你理清这方面的一些困惑。

    本文根据@DAVE CEDDIA的《React: ES5 (createClass) or ES6 (class)?》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://daveceddia.com/react-es5-createclass-vs-es6-classes/

    著作权归作者所有。
    商业转载请联系作者获得授权,非商业转载请注明出处。
    原文: http://www.w3cplus.com/react/react-es5-createclass-vs-es6-classes.html © w3cplus.com

  • 相关阅读:
    启动django报错
    celery简单使用
    git简单使用
    selinux干扰mysql启动
    python操作xml文件时,带有^M符号
    获取服务器内网地址
    WebStorm激活
    linux nohup python 后台运行无输出问题
    安装FTP
    sql server还原数据库代码
  • 原文地址:https://www.cnblogs.com/aivnfjgj/p/6507344.html
Copyright © 2011-2022 走看看