# 浅析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()
,重写的构造函数中参数有没有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( )
-----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.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不会)
这里还是举个栗子来看一下区别:
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)}`
})
}