constructor必须用super()初始化this,可以绑定事件到this
如果你在constructor中要使用this.props,就必须给super加参数,super(props);
constructor(){ super(); this.state = { xxx:this.props.xxx//构造函数里面用到了props }; }//这里如果在construct()和super()中不传入props参数,则会报错 //因为这里使用super()是重写了父类的构造函数(父类的构造函数本来是super(props,context))无论有没有constructor(),重写的构造函数中参数有没有props,render()中都可以使用this.props, 默认自带
如果组件没有声明constructor,react会默认添加一个空的constructor。
class News extends React.Component { render() { return ( <div> new组件:{this.props.text} <p>{this.state.text}</p> </div> ) } } //如果在继承时,子类中如果没有声明constructor,js会自动生成添加constructor并且调用父类的构造函数 //这里是父类的构造函数是super(props,context),并不是super()如果写super()则是不完全使用父类构造函数方法。ES6采用的是先创建父类的实例this(故要先调用 super( )方法),完后再用子类的构造函数修改this
constructor( )——构造方法
这是ES6对类的默认方法,通过 new 命令生成对象实例时自动调用该方法。 并且,该方法是类中必须有的,如果没有显示定义,则会默认添加空的constructor( )方法。super( ) ——继承
在class方法中,继承是使用 extends 关键字来实现的。 子类必须在 constructor( )调用 super( )方法,否则新建实例时会报错。 (如果子类没有显示定义构造方法,js则会默认加上构造方法并且里面用super自动调用父类的构造方法) 即: class son extends father{ constructor(){ super() } } 如果父类构造方法里面含参数,子类没有显示定义构造方法,js也会默认向子类构造方法中加上参数调用父类的构造方法,例如: class son extends father{ constructor(name,age){ super(name,age) } } 报错的原因是:子类是没有自己的 this 对象的,它只能继承自父类的 this 对象, 然后对其进行加工,而super( )就是将父类中的this对象继承给子类的。 没有 super,子类就得不到 this 对象。下面是子类显示定义了构造方法,但是并没有向子类构造方法传入父类构造方法本应该传入的形参:
class father { constructor(name, age) { this.name = name this.age = age } pick() { console.log(`年龄:${this.name}`, `年龄:${this.age}`) } } class son extends father { //显示定义了构造方法,但是没有向其中传入父类该有的形参 constructor(name){//这里我们只传入第一个参数 super(name) } pull() { console.log("jhhh ") } } Father = new father("baba", 40) Father.pick()//年龄:baba 年龄:40 Son = new son("erzi", 20) Son.pick()//年龄:erzi 年龄:undefined //可以看到此时子类虽然使用super继承使用了父类的构造方法,但是只会使用了父类的一个形参 class father { constructor(name, age) { this.name = name this.age = age } pick() { console.log(`年龄:${this.name}`, `年龄:${this.age}`) } } class son extends father { //此时子类直接继承父类,并没有显示定义构造方法 pull() { console.log("jhhh ") } } Father = new father("baba", 40) Father.pick()//年龄:baba 年龄:40 Son = new son("erzi", 20) Son.pick()//年龄:erzi 年龄:20 //此时我们可以知道如果子类没有显示定义构造方法, //则会默认补上父类的构造方法,而且构造方法的参数和父类都是一致的。总结:通过这个我们知道如果在react类组件中写出构造函数而且需要在构造函数中使用props属性,必须补上第一个形参作为补位,才能使用得到props的值。
而这里需要注意的是:react类组件在render()函数中无论构造函数有没有传入props形参,render()函数都可以使用到this.props的值
类组件需要注意js内置事件回调函数的this指向问题。
1. 类组件有自己的状态 2. 继承React.Component-会有生命周期和this 3. 内部需要一个render函数(类组件会默认调用render方法,但不会默认添加,需要手动填写render函数,并return一个能渲染的值。) 4. 类组件的基本架构 5. constructor里边添加自己的属性和状态、方法 a. 写了constructor就要写super b. 如果c里边没内容只有super,name可以不写 6. 添加状态this.state = {}; es7写法state = {}。非双向绑定 7. setState接收对象的情况、批量更新 8. setState接收函数的情况、state与penddingState 9. class里方法的写法 a. 方法里边this的指向undefined的情况 class Person { fn(){ console.log(this); } } var person = new Person(); var fn1 = person.fn;(这里是将值赋给fn1) fn1(); //undefined(fn1()当前的指向位置this指向undefined) b. bind改变this指向 c. 箭头函数继承this指向 d. 匿名函数传参 10. TodoList实战 11. 类组件注意: 注意绑定事件时,"on"后边事件名的首字母大写,如"change"要写成"Change"注意回调函数内部this的指向默认为undefined,要改变this指向 不能直接改变state的值、需要用函数setState来修改state的值类组件内部没有render函数报错:
因为看到class组件会默认调用render方法 如果看到函数组件,会自动在函数内部添加一个render方法,把函数的return返回值放到render中运行。 所以类组件内部必须有render函数,并return返回一个可渲染的值。不会进行自动添加。
this是基于函数的执行环境(也就是上下文)绑定的,React组件生命周期函数中this的上下文就是组件实例。(而js的变量是通过词法作用域来绑定的)
可以看关于this的一篇文章总结的很到位。 1.函数在调用时,JavaScript会默认给this绑定一个值;2.this的绑定和定义的位置(编写的位置)没有关系;3.this的绑定和调用方式以及调用的位置有关系;4.this是在运行时被绑定的;你必须谨慎对待 JSX回调函数中的this,类的自定义方法默认是不会绑定 this 的。首先调用 constructor()函数, this.state 的this上下文就是该实例对象;同理,render() 函数中this也是该实例。
在浏览器中回调函数中的this默认是指向window的,因为本质上是在函数内callback,并没有.前的对象调用,在**nodejs中的回调函数中的this默认是undefined**。(回调函数可以参看我之前的总结)
class Bar extends React.Component { constructor (){ super(); this.state = { value: 'react' } } changeValue (){ console.log(this) // undefined } render (){ console.log(this) // 该组件实例 return ( <div> <p>{this.state.value}</p> <button onClick={this.changeValue}>click me !</button> </div> ) } }当我们直接绑定this.changeValue调用时,会发现他的this是undefined;你应该为和这个方法绑定this。
解决方式:
①:使用 bind() 函数改变this的上下文(这里只能用bind,不能用call和apply,因为call和apply会立即执行,而bind不会)
call,apply,bind的用法以及区别
这里还是举个栗子来看一下区别:
var obj = { message: 'My name is: ' } function getName(firstName, lastName) { console.log(this.message + firstName + ' ' + lastName) } getName.bind(obj, ['Dot', 'Dolby'])//不会执行打印函数,而是返回一个改变了执行上下文this指向之后的函数 getName.bind(obj, ['Dot', 'Dolby'])()// My name is: Dot Dolby getName.apply(obj, ['Dot', 'Dolby'])// My name is: Dot Dolby getName.call(obj, 'Dot', 'Dolby')// My name is: Dot Dolby在这里就可以使用bind来改变回调函数上下文this的指向,并不需要让它马上执行
class Bar extends React.Component { constructor (){ super(); this.state = { value:'react' } } changeValue (e){ console.log(e) // 默认event this.setState({ value:`react ${parseInt(Math.random()*100)}` }) } render (){ return ( <div> <p>{this.state.value}</p> <button onClick={this.changeValue.bind(this)}>click me !</button> </div> ) } }也可以在constructor()中:this.changeValue = this.changeValue.bind(this)
②:es6的箭头函数 利用箭头函数将函数的this绑定到其定义时所在的上下文
<div> <p>{this.state.value}</p> <button onClick={(event) => this.changeValue(event)}>click me !</button> </div>或者
changeValue = (e) => { console.log(e) // 默认event this.setState({ value:`react ${parseInt(Math.random()*100)}` }) }