# 浅析React类组件(ES6)

# React类组件(组件名首字母大写)
//创建类组件		组件名首字母大写
class  MyCom extends React.Component {
    render(){
        return (
            <div>类组件</div>
        )
    }
}
let com=<MyCom/>
ReactDOM.render(com,document.getElementById('app'));
# react类组件的构造方法 constructor():
constructor(props){
    super(props);               
    this.state = {
    }
}
  • 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(),重写的构造函数中参数有没有propsrender()中都可以使用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( )-----super( )的基本含义

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返回一个可渲染的值。不会进行自动添加。

# React中自定义事件this指向问题

this是基于函数的执行环境(也就是上下文)绑定的,React组件生命周期函数中this的上下文就是组件实例。(而js的变量是通过词法作用域来绑定的)

  • 可以看关于this的一篇文章总结的很到位。
    • 1.函数在调用时,JavaScript会默认给this绑定一个值;
    • 2.this的绑定和定义的位置(编写的位置)没有关系;
    • 3.this的绑定和调用方式以及调用的位置有关系;
    • 4.this是在运行时被绑定的;

你必须谨慎对待 JSX回调函数中的this,类的自定义方法默认是不会绑定 this 的。首先调用 constructor()函数, this.statethis上下文就是该实例对象;同理,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调用时,会发现他的thisundefined;你应该为和这个方法绑定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)}`
	})
}
Last Updated: 7/15/2020, 10:34:45 PM