React创建组件的方法;Class组件为什么要绑定this?

在写这个问题之前,我们先要学习2个知识点;

  • 1 ES6 Class的基本语法
  • 2 React创建组件的方法;

ES6 Class的基本语法

在ES6 引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
我这里不做过多的介绍,具体请参考ECMAScript 6 入门(阮一峰)

(1) ES6 Class 编写对象

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

以上的代码等价于:

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

在这里会有2个概念: 类的实例和对象的属性

接下来我们用一段代码解释这两个东西;

//定义类
class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    toString() {
        return '(' + this.x + ', ' + this.y + ')';
    }
}
// 实例化Point Class
var point = new Point(2, 3);
console.log(point.toString()) // (2, 3)
console.log(point.hasOwnProperty('x')) // true
console.log(point.hasOwnProperty('y')) // true

// 判断对象的实例上是否有 toStirng 属性
console.log(point.hasOwnProperty('toString')) // false

// 判断对象的属性上是否存在 toString 属性
console.log(point.__proto__.hasOwnProperty('toString')) // true

基于上面的代码我们可以得知:

  • 实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)
  • 上面代码中,x和y都是实例对象point自身的属性(因为定义在this变量上),所以hasOwnProperty方法返回true,而toString是原型对象的属性(因为定义在Point类上),
  • 所以hasOwnProperty方法返回false。这些都与 ES5 的行为保持一致。

(2) this的指向

类的方法内部如果含有this,它默认指向类的实例;但是,必须非常小心,一旦单独使用该方法,很可能报错。

class Logger {
  printName(name = 'there') {
    this.print(`Hello ${name}`);
  }

  print(text) {
    console.log(text);
  }
}

const logger = new Logger();
// ES6 解构
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined

上面代码中,printName方法中的this,默认指向Logger类的实例。但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境(由于 class 内部是严格模式,所以 this 实际指向的是undefined),从而导致找不到print方法而报错。

因此在如果这个方法被单独提出来使用,我们的通常的做法就是在构造方法中绑定this,这样就不会找不到print方法了。

class Logger {
  constructor() {
    this.printName = this.printName.bind(this);
  }

  // ...
}

另一种方法是使用箭头函数

class Obj {
  constructor() {
    this.getThis = () => this;
  }
}

const myObj = new Obj();
myObj.getThis() === myObj // true

箭头函数内部的this总是指向定义时所在的对象,
它的定义生效的时候,是在构造函数执行的时候。
这时,箭头函数所在的运行环境,肯定是实例对象,所以this会总是指向实例对象

第三种是使用还有一种解决方法是使用Proxy,获取方法的时候,自动绑定this。具体请看:ES6 Class Proxy

那么以上就是this在ES6中Class的基本介绍;详细的学习请参考ECMAScript 6 入门(阮一峰),那么接下来我们就来看看React中如何使用this;首先会从组件的创建开始来说;

React创建组件的写法

1.函数组件(无状态组件)

定义组件最简单的方式就是编写 JavaScript 函数:
(1) 语法

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

(2) 特点

  • 它是为了创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到state状态的操作。
  • 组件不能访问this对象
    无状态组件由于没有实例化过程,所以无法访问组件this中的对象,例如:this.ref、this.state等均不能访问。若想访问就不能使用这种形式来创建组件
  • 它不能访问生命周期方法

2 es5方式React.createClass组件(有状态组件)

React.createClass是react刚开始推荐的创建组件的方式,这是ES5的原生的JavaScript来实现的React组件
(1)语法

var myCreate = React.createClass({
    defaultProps: { 
        //code
    },
    getInitialState: function() {
        return {
            //code
        };
    },
    render: function() {
        return (
            <div>
                //code
            </div>
        );
    }
});

(2) 特点

与无状态组件相比,React.createClass和后面要描述的React.Component都是创建有状态的组件,这些组件是要被实例化的,并且可以访问组件的生命周期方法。但是随着React的发展,React.createClass形式自身的问题暴露出来:

  • React.createClass会自绑定函数方法(不像React.Component只绑定需要关心的函数)导致不必要的性能开销,增加代码过时的可能性。
  • React.createClass的mixins不够自然、直观;React.Component形式非常适合高阶组件(Higher Order Components–HOC),它以更直观的形式展示了比mixins更强大的功能,并且HOC是纯净的JavaScript,不用担心他们会被废弃。HOC可以参考无状态组件(Stateless Component) 与高阶组件

3.Class组件(有状态组件)

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

(2)优点:

  • 成员函数不会自动绑定this,需要开发者手动绑定,否则this不能获取当前组件实例对象。
  • 状态state是在constructor中像初始化。
  • props属性类型和组件默认属性作为组件类的属性,不是组件实例的属性,所以使用类的静态属性
  • 能很好的实现代码复用
  • 能很好的管理组件的生命周期

React.createClass与React.Component区别

(1) 函数的this绑定

React.createClass创建的组件,其每一个成员函数的this都有React自动绑定,任何时候使用,直接使用this.method即可,函数中的this会被正确设置。

const Contacts = React.createClass({  
  handleClick() {
    console.log(this); // React Component instance
  },
  render() {
    return (
      <div onClick={this.handleClick}></div>
    );
  }
});

而用React.Component创建的组件,其成员函数不会自动绑定this,需要开发者手动绑定,否则this不能获取当前组件实例对象。

class Contacts extends React.Component {  
  constructor(props) {
    super(props);
  }
  handleClick() {
    console.log(this); // null
  }
  render() {
    return (
      <div onClick={this.handleClick}></div>
    );
  }

在这里就可以看到;因为我们使用了ES6的Class方式来创建组件,那么如何在内部去访问属性方法;就需要显式的在需要绑定的地方绑定this;

当然,React.Component有三种手动绑定方法:

  • 可以在构造函数中完成绑定,
  • 在调用时使用method.bind(this)来完成绑定,
  • 还可以使用箭头函数来绑定

那么我们以上面的handleClick函数为例子;

在构造函数中绑定;

constructor(props) {
       super(props);
       this.handleClick = this.handleClick.bind(this); //构造函数中绑定
  }

在调用时候的进行绑定

 <div onClick={this.handleClick.bind(this)}></div> //使用bind来绑定

使用箭头函数来绑定

    <div onClick={()=>this.handleClick()}></div> //使用arrow function来绑定

基本上就这些吧;以后碰上了再写;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值