constructor(props){
super(props);
this.state = {liked:false}
//this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
liked:!this.state.liked
});
}
render里的代码:
...
let text = this.state.liked ? 'like' : 'haven\'t liked';
...
<p onClick={this.handleClick}>you{text}</p>
...
如果这句不加代码中的注释部分,则报这个错误:setState is not defined
如果是es5,则不需要加这个,因为看各教程中并没有写这句,故请教下高玩。。。
先讲结论:
这是因为ES6写法,也就是类(Class)的写法,React默认不会自动绑定类中的方法造成的。
React对ES5的语法是默认有自动绑定,所以不需要加这个。
而且,自动绑不绑定也是React决定要不要的
后说缘由:
React的元件从定义开始,到执行完成渲染到真实的DOM元素中,是一个很复杂的过程,这里面也包含了事件处理函式到底是要用什么方式来执行。事件处理函式原本就是一个很特别的回调函式,当在事件触发时是要执行从什么地方来的函式,是在元件自己本身定义的函式(方法)?还是上层元件定义的函式(方法)?或者来自外部的模组或函式?执行的对象又是谁?这些问题都要一起考量。
要讲到函式的
this
值与上下文(Context),先需要对JavaScript再科普一下,摘要出来在下面说明。在JavaScript中,函式一共有以下四种呼叫的样式,它们分别是:一般的函式呼叫(Function Invocation Pattern)
物件中的方法呼叫(Method Invocation Pattern)
建构函式呼叫(Constructor Invocation Pattern)
使用apply, call, bind方法呼叫(应用呼叫样式 Apply invocation pattern / 间接呼叫样式 Indirect Invocation Pattern)
对函式库或框架(或是对具熟练技术的开发者)来说,最具弹性的是最后一种,因为它可以提供最多的方便性,以间接的呼叫样式,在必要的时候才进行呼叫,也可以转换函式(方法的)上下文(Context)。当你真正理解为何
this
值的真正涵义时,你会发现以下几个事实,这可能会颠覆对于JavaScript中函式的原先想像:"函式定义是定义,呼叫是呼叫": 实际上在物件定义的所谓方法,你可以把它当作只是让开发者方便集中管理的函式定义。
对
this
值来说,它根本不关心函式是在哪里定义或是怎么定义的,它只关心是谁呼叫了它。所有的函式在呼叫时,其实都有一个拥有者物件来进行呼叫"。所以你可以说,其实所有函式都是物件中的"方法。所有的函式执行都是以
Object.method()
方式呼叫。回到React中,新版本(0.13后)允许我们可以使用ES6的类(Class)定义方式来定义组件,这称之为"建构函式呼叫样式",但原本的工厂样式(也就是使用
React.createClass
方法,或称为ES5语法方式)并没有因此而废止不用,也就是说这两种定义方式在基本使用上是可以得到相等结果的,只是里面所使用的语法细节有所不同。对于React来说,实际上它根本也不允许你在使用new来产生ES6+类定义的实体,那它的内部又是如何来呼叫或执行这些我们在类里面定义的方法的?答案已经很明显了,绝对不是单纯的"建构函式呼叫样式",它在程式码中混用了多种的函式呼叫样式,而且会使用最具弹性的那种"间接的呼叫样式",也就是说它明显的使用了
this
中"函式定义是定义,呼叫是呼叫"的作法。在React官方对建构式样式(ES6类别)定义方式与工厂样式(也就是使用
React.createClass
方法)的说明中,有一个非常大的差异,称为"Autobinding"(自动绑定),工厂样式中的this
值是会自动绑定的,但建构式样式(ES6类别)定义方式的this
值"不会"再自动绑定。自动绑不绑定最大的影响会在于当元件的render方法中,在React元素(JSX语法)中呼叫我们定义的函式(方法)时,最早之前版本的工厂样式也不会自动绑定,是后来加入的功能(v0.4, 2013),出自[React官网这里] (https://facebook.github.io/re...
由此得知,自动绑定并非一个JavaScript中的自然内部机制,而是由React自己所决定的的内部实作功能。但在v0.13(2015)版本中取消了ES6类别里面这个机制,理由除了像上面所说的,当在事件触发时要执行的回调函式,来源可能有很多种,对象或许并非单一。另一个主要的理由是为了不让开发者造成混乱,以为在ES6类别里这个机制是自然就有的,所以在建构式样式(ES6类别)后改成了你需要手动绑定。
要绑定类别中的方法(函式)可用下面两种语法,出自React官网这里:
第一种是在建构式中
constructor
加入绑定你定义的方法的语句:第二种是用箭头函式语法来宣告方法:
要注意的这个语法既非ES6也非ES7,暂且称它为ES7+或ES8,但babel工具可以正确的转译这个语法,所以你不需要担心会有执行上的问题。第二种需要加装
babel-plugin-transform-class-properties
,并在.babelrc
中配置到plugins
中,参考https://babeljs.io/docs/plugi...最后的结论是,JSX是React创的,babel是React养的,自动绑不绑定也是React决定要不要的。