我是靠谱客的博主 可靠小熊猫,这篇文章主要介绍React全家桶:类--类式组件--state属性--事件绑定--类中方法的this--props属性--ref--事件处理写在前面复习类相关的知识第11集 类式组件第12集 对state的理解第13集 初始化state第14集 react中事件绑定第15集 类中方法的this第16集解决类中this指向问题第17集 对setState的使用第18集 state的简写方式第19集总结state第20集 props的基本使用第21集 批量传递props第22集 对props进行限制第23集 pro,现在分享给大家,希望可以做个参考。

写在前面

在最近看了React之后,一直觉得学的懵懵然,虽然很多大佬的手写笔记,写的都很不错,但是我一直没有我想要的那种细无巨细,比如类式组件this指向问题的追根溯源,又比如三大实例属性简写的由来,总之我还是决定做一份事无巨细的笔记。

那就让我们开始吧!

复习类相关的知识

创建实例对象

复制代码
1
2
3
4
5
6
7
8
//创建一个Person类 class Person { } let person1 = new Person(); console.log(person1)
  • 输出分解

image.png

红色框代表new出来的实例对象

蓝色框代表这个实例对象是由Person这个类new出来的。

目的:为了区别实例是由哪个类new出来的

接收参数

  • 使用构造器方法(可以不写)

构造器也是在原型上的

复制代码
1
2
3
4
5
6
7
8
9
10
//创建一个Person类 class Person { //构造器方法 constructor(name,age){ //构造器中的this是谁?—— 类的实例对象 this.name = name this.age = age } }

注意: 构造器中的this是谁?—— 类的实例对象

  • 定义方法
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//创建一个Person类 class Person { //构造器方法 constructor(name,age){ //构造器中的this是谁?—— 类的实例对象 this.name = name this.age = age } //一般方法 speak(){ //speak方法放在了哪里?——类的原型对象上,供实例使用 //通过Person实例调用speak时,speak中的this就是Person实例 console.log(`我叫${this.name},我年龄是${this.age}`); } }

注意:

speak方法放在了哪里?——类的原型对象上,供实例使用

通过Person实例调用speak时,speak中的this就是Person实例

image.png

  • 继承

书写构造器之后必须书写super、必须放在带有使用this关键字的前面

super:调用父类的构造器

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//创建一个Student类,继承于Person类 class Student extends Person { constructor(name,age,grade){ super(name,age) this.grade = grade this.school = '尚硅谷' } //重写从父类继承过来的方法 speak(){ console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`); this.study() } study(){ //study方法放在了哪里?——类的原型对象上,供实例使用 //通过Student实例调用study时,study中的this就是Student实例 console.log('我很努力的学习'); } }
  • 调用方法

如果不重写方法,那么就会调用父类提供的方法,这个方法会通过原型链在person实例的原型对象上找到。

复制代码
1
2
3
4
5
6
7
8
class Student extends Person { constructor(name,age,grade){ super(name,age) this.grade = grade this.school = '尚硅谷' } }

image.png

  • 重写方法
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//创建一个Student类,继承于Person类 class Student extends Person { constructor(name,age,grade){ super(name,age) this.grade = grade this.school = '尚硅谷' } //重写从父类继承过来的方法 speak(){ console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`); this.study() } study(){ //study方法放在了哪里?——类的原型对象上,供实例使用 //通过Student实例调用study时,study中的this就是Student实例 console.log('我很努力的学习'); } }

image.png

蓝色框的方法在student实例的原型对象上、红色框的方法在person实例的原型对象上。

调用方法采用就近原则,通过原型链调用最先找到的那个方法。

-总结:

复制代码
1
2
3
4
5
6
1.类中的构造器不是必须要写的,要对实例进行一些初始化的操作,如添加指定属性时才写。 2.如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的。 3.类中所定义的方法,都放在了类的原型对象上,供实例去使用。

第11集 类式组件

类名或者函数名就是组件名

创建类式组件

  • 必须继承React内置一个类

必须继承React.Component

  • 可以省略构造器

传送门

https://react.docschina.org/

image.png

  • 书写必备的三个条件
  1. 必须继承React.Component
  2. 必学书写render方法
  3. redner必须有返回值
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/babel"> //1.创建类式组件 class MyComponent extends React.Component { render(){ //render中的this是谁?—— MyComponent的实例对象 <=> MyComponent组件实例对象。 console.log('render中的this:',this); return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2> } } //2.渲染组件到页面 ReactDOM.render(<MyComponent/>,document.getElementById('test')) </script>
  • render是放在哪里的?—— MyComponent的原型对象上,供实例使用。

image.png

  • 执行了ReactDOM.render(…之后,发生了什么?

    复制代码
    1
    2
    3
    4
    1.React解析组件标签,找到了MyComponent组件。 2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。 3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
  • render中的this是谁?

MyComponent的实例对象 <=> MyComponent组件实例对象。

console.log('render中的this:',this);

image.png

第12集 对state的理解

简单组件、复杂组件

有无“状态”,有就是复杂组件、无就是简单组件

组件实例的三大核心属性

state、prrops、refs

第13集 初始化state

组件三大核心属性:state

  • 向state属性传值(书写构造器)

1、构造器传值:接受props

传送门

https://react.docschina.org/

image.png

2、必须调用super

复制代码
1
2
super(props)

如果书写构造器不调用就会报错

image.png

  • 给state赋值是一个对象
复制代码
1
2
3
//初始化状态 this.state = {isHot:false,wind:'微风'}
  • 渲染到页面
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script type="text/babel"> //1.创建组件 class Weather extends React.Component{ constructor(props){ super(props) //初始化状态 this.state = {isHot:false} } render(){ return <h1 今天天气很{isHot ? '炎热' : '凉爽'}</h1> } } //2.渲染组件到页面 ReactDOM.render(<Weather/>,document.getElementById('test')) </script>

第14集 react中事件绑定

原生事件的绑定

  • 3种类型
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<body> <button id="btn1">按钮1</button> <button id="btn2">按钮2</button> <button onclick="demo()">按钮3</button> </body> <script type="text/javascript" > const btn1 = document.getElementById('btn1') btn1.addEventListener('click',()=>{ alert('按钮1被点击了') }) const btn2 = document.getElementById('btn2') btn2.onclick = ()=>{ alert('按钮2被点击了') } function demo(){ alert('按钮3被点击了') } </script>
  • 实现效果

image.png

  • 在React依然可以使用原生绑定事件(只要能绑定到render方法返回的标签就行)

实际中不会这样使用

image.png

  • on类api得驼峰命名

image.png

1、为onClick赋值一个方法必须使用{} 并且不能带()。

必须使用{}原因:

使用{},是因为这里还是将函数赋值给onClick,不然会被解析为字符串。简单来说就是这里要使用js表达式了。

不能带()原因:这里就为了函数赋值给onClick回调,而不是将函数的返回值传递给onClick来回调

不然一渲染就会直接调用这个函数。而且onClick会回调函数的返回值,而不是函数本身。

image.png

第15集 类中方法的this

  • babel开启严格模式

this是undefined

image.png

image.png

  • 在render中的this就是组件实例对象,因为是组件实例对象调用的redner方法。

  • 使用外作用域定义变量取到组件实例对象的this

image.png

  • 将函数方法书写到类式组件中

image.png

  • onClick不能直接调用方法(组件实例对象调用-添加this)

image.png

但是这里changeWeather方法中的this指向还是undefined

类中方法的this指向

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script type="text/javascript" > class Person { constructor(name,age){ this.name = name this.age = age } study(){ //study方法放在了哪里?——类的原型对象上,供实例使用 //通过Person实例调用study时,study中的this就是Person实例 console.log(this); } } const p1 = new Person('tom',18) p1.study() //通过实例调用study方法 const x = p1.study x() // 直接调用study </script>

image.png

  • 类中定义的所有方法,在局部作用域都开启了严格模式

  • 函数中开启严格模式

image.png

image.png

  • onClick是直接回调这个函数(不是组件实例对象调用的)

image.png

  • 直接强行new一个类式组件的实例对象

image.png

这里的this指向就是组件实例对象

image.png

  • 由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用

  • 类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<script type="text/babel"> //1.创建组件 class Weather extends React.Component{ //构造器调用几次? ———— 1次 constructor(props){ console.log('constructor'); super(props) //初始化状态 this.state = {isHot:false,wind:'微风'} //解决changeWeather中this指向问题 this.changeWeather = this.changeWeather.bind(this) } //render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数 render(){ console.log('render'); //读取状态 const {isHot,wind} = this.state return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1> } //changeWeather调用几次? ———— 点几次调几次 changeWeather(){ //changeWeather放在哪里? ———— Weather的原型对象上,供实例使用 console.log('changeWeather'); //获取原来的isHot值 const isHot = this.state.isHot //严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。 this.setState({isHot:!isHot}) console.log(this); //严重注意:状态(state)不可直接更改,下面这行就是直接更改!!! //this.state.isHot = !isHot //这是错误的写法 } } //2.渲染组件到页面 ReactDOM.render(<Weather/>,document.getElementById('test')) </script>

第16集解决类中this指向问题

使用bind

bind : 生成新函数、改变this指向

复制代码
1
2
3
//解决changeWeather中this指向问题 this.changeWeather = this.changeWeather.bind(this)

image.png

解析过程:在组件对象的原型上找到函数,使用bind创建了一个一模一样的函数,但是讲函数的this修改为组件实例对象。并且将这个新函数作为一个值,赋值给了实例对象的一个叫changeWeather的方法。这样实例对象自身就会有一个changeWeather的方法。

注意:左边的changeWeather 在 实例对象身上、右边的changeWeather是原型对象上的。这段代码核心就是将原型对象上的方法加工改变this添加的实例对象上。

image.png

第17集 对setState的使用

  • 对state对象的值修改必须使用setSate内置api(在React.component)

image.png

复制代码
1
2
3
4
5
6
7
console.log('changeWeather'); //获取原来的isHot值 const isHot = this.state.isHot //严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。 this.setState({isHot:!isHot}) console.log(this);
  • 修改对象值是局部修改

严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。

  • 调用次数

构造器调用几次? ———— 1次(创建实现对象时调用)

render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数

changeWeather调用几次? ———— 点几次调几次

第18集 state的简写方式

核心解决手段来源:类中可以直接写赋值语句

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Car { constructor(name,price){ this.name = name this.price = price // this.wheel = 4 } //类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1 a = 1 wheel = 4 static demo = 100 } const c1 = new Car('奔驰c63',199) const s1 = new Student('1','2');

简写方法

  • 由于自定义函数太多了,大量使用bind。

将函数作为一个值直接赋值到一个属性上。

image.png

image.png

注意: 还是会报错

image.png

解决方法,将function改为箭头函数模式

复制代码
1
2
3
4
5
6
//自定义方法————要用赋值语句的形式+箭头函数 changeWeather = ()=>{ const isHot = this.state.isHot this.setState({isHot:!isHot}) }

原因:在箭头函数中,this引用的是定义箭头函数的上下文(红宝书p300)

  • 注意不允许这么写
复制代码
1
2
3
4
5
changeWeather()=>{ const isHot = this.state.isHot this.setState({isHot:!isHot}) }

简写state

直接使用赋值语句

复制代码
1
2
3
//初始化状态 state = {isHot:false,wind:'微风'}

第19集总结state

1. state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)

2. 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)

第20集 props的基本使用

传递组件属性

image.png

image.png

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script type="text/babel"> //创建组件 class Person extends React.Component{ render(){ // console.log(this); const {name,age,sex} = this.props return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age+1}</li> </ul> ) } } //渲染组件到页面 ReactDOM.render(<Person name="jerry" age={19} sex="男"/>,document.getElementById('test1')) ReactDOM.render(<Person name="tom" age={18} sex="女"/>,document.getElementById('test2')) const p = {name:'老刘',age:18,sex:'女'} // console.log('@',...p); // ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3')) ReactDOM.render(<Person {...p}/>,document.getElementById('test3')) </script>

第21集 批量传递props

展开运算符

传送门

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<script type="text/javascript" > let arr1 = [1,3,5,7,9] let arr2 = [2,4,6,8,10] console.log(...arr1); //展开一个数组 let arr3 = [...arr1,...arr2]//连接数组 //在函数中使用 function sum(...numbers){ return numbers.reduce((preValue,currentValue)=>{ return preValue + currentValue }) } console.log(sum(1,2,3,4)); //构造字面量对象时使用展开语法 let person = {name:'tom',age:18} let person2 = {...person} //console.log(...person); //报错,展开运算符不能展开对象 person.name = 'jerry' console.log(person2); console.log(person); //合并 let person3 = {...person,name:'jack',address:"地球"} console.log(person3); </script>

批量传入props

react+babel 可以允许使用展开运算符展开对象。

  • 仅用于标签属性的传递

第22集 对props进行限制

对标签属性传递的类型进行限制

  • 在组件上添加propTypes属性

在React每次创建组件实例对象的时候就会访问组件本身的propTypes属性以便于限制props

  • 不同版本不同写法
复制代码
1
2
3
4
5
6
7
8
9
10
11
//对标签属性进行类型、必要性的限制 Person.propTypes = { // 15版本 name: React.PropTypes.string, // 16版本 name:PropTypes.string.isRequired, //限制name必传,且为字符串 sex:PropTypes.string,//限制sex为字符串 age:PropTypes.number,//限制age为数值 speak:PropTypes.func,//限制speak为函数,不使用function就是为了防止与关键字发生冲突 }

16版本之后

复制代码
1
2
3
<!-- 引入prop-types,用于对组件标签属性进行限制 --> <script type="text/javascript" src="../js/prop-types.js"></script>

引入一个依赖包就产生一个全局对象,这里会产生一个propTypes全局对象。

属性默认值

复制代码
1
2
3
4
5
6
//指定默认标签属性值 Person.defaultProps = { sex:'男',//sex默认值为男 age:18 //age默认值为18 }

第23集 props的简写方式

props是只读的

简写props

  • 将类似限制、默认值书写到类式组件内部

在类的原型上添加属性(使用static关键字)

第24集 类式组件中的构造器与props

  • 构造器传送门

https://zh-hans.reactjs.org/docs/react-component.html#constructor

-实际使用

image.png

image.png

类中的构造器的作用

  • 如果不使用构造器接受props和使用super接受props,就无法使用实例对象访问props
复制代码
1
2
3
4
5
6
7
constructor(props){ //构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props // console.log(props); super(props) console.log('constructor',this.props); // super constructor里面缺一个没传props参数都不可,否则就是undefined }

第25集 函数式组件使用props

函数式组件没有实例对象,但是可以接受参数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/babel"> //创建组件 function Person (props){ const {name,age,sex} = props return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age}</li> </ul> ) } //渲染组件到页面 ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1')) </script>

对props进行限制

  • 对组件添加属性
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
Person.propTypes = { name:PropTypes.string.isRequired, //限制name必传,且为字符串 sex:PropTypes.string,//限制sex为字符串 age:PropTypes.number,//限制age为数值 } //指定默认标签属性值 Person.defaultProps = { sex:'男',//sex默认值为男 age:18 //age默认值为18 }

第26集 props总结

  • 理解

1. 每个组件对象都会有props(properties的简写)属性

2. 组件标签的所有属性都保存在props中

  • propsTypes

propsTypes是React要求的属性名,这个属性用来保存一个对象进而对props进行限制。

PropsTypes是使用prop-types库进限制(需要引入prop-types库)产生的全局对象

第27集 字符串形式的ref

  • 使用原生id属性事件绑定

image.png

  • 使用ref标识
复制代码
1
2
<input ref="input1" type="text" placeholder="点击按钮提示数据"/>&nbsp;

image.png

复制代码
1
2
3
4
5
6
//展示左侧输入框的数据 showData = ()=>{ const {input1} = this.refs console.log(input1.value) }

image.png

第28集 回调形式的ref

过时APl:String类型的Refs

传送门

https://zh-hans.reactjs.org/docs/refs-and-the-dom.html

  • 回调形式的ref
复制代码
1
2
<input ref={c => this.input1 = c } type="text" placeholder="点击按钮提示数据"/>&nbsp;

回调的箭头函数接收的参数正好就是ref属性所在的标签

image.png

  • 上述代码的执行过程

在创建实例对象之后,实例对象调用render方法直接回调箭头函数。将作为参数的标签本身赋值到实例对象上的一个属性上。

这里就是将input标签赋值给实例对象的input属性上。

第29集 回调ref中调用次数的问题

传送门

https://zh-hans.reactjs.org/docs/refs-and-the-dom.html

image.png

  • 第一次初始化渲染页面调用render

回调ref中调用1次

  • 更新过程

回调ref中调用2次本质:

1.初始化调用的回调函数已经被释放,状态更新后再次调用这个方法时就是一个新的方法。

2.由于不确定之前的函数接受到了什么,做了什么动作,为此就传入了null进行第一次调用。

3.在调用第二次的时候就传入了当前节点。

  • 实现结果

image.png

  • jsx注释方法
复制代码
1
2
{/*<input ref={(c)=>{this.input1 = c;console.log('@',c);}} type="text"/><br/><br/>*/}
  • 将 ref 的回调函数定义成 class 的绑定函数的方式
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<script type="text/babel"> //创建组件 class Demo extends React.Component{ state = {isHot:false} showInfo = ()=>{ const {input1} = this alert(input1.value) } changeWeather = ()=>{ //获取原来的状态 const {isHot} = this.state //更新状态 this.setState({isHot:!isHot}) } saveInput = (c)=>{ this.input1 = c; console.log('@',c); } render(){ const {isHot} = this.state return( <div> <h2>今天天气很{isHot ? '炎热':'凉爽'}</h2> {/*<input ref={(c)=>{this.input1 = c;console.log('@',c);}} type="text"/><br/><br/>*/} <input ref={this.saveInput} type="text"/><br/><br/> <button onClick={this.showInfo}>点我提示输入的数据</button> <button onClick={this.changeWeather}>点我切换天气</button> </div> ) } } //渲染组件到页面 ReactDOM.render(<Demo/>,document.getElementById('test')) </script>

第31集 createRef的使用

创建一个专属容器

image.png

  • 这里的myRef是一个对象,里面的current属性保存的是ref属性所在的标签

image.png

第31集 总结 refs

  • 一共有4种方式使用refs

第32集 React中的事件处理

1. 通过onXxx属性指定事件处理函数(注意大小写)

复制代码
1
2
3
4
1) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件---为了更好的兼容性 2) React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)---为了更高效

2. 通过event.target得到发生事件的DOM元素对象 — 避免过度使用ref

  • 事件委托(原理:事件冒泡)

所有的事件都添加到了最外层的标签上

这里就是div

image.png

  • 避免过度使用ref

发生事件的元素正好就是要操作的元素。就可以使用event.target替代

复制代码
1
2
3
4
5
6
7
//展示右侧输入框的数据 showData2 = (event)=>{ alert(event.target.value); } <input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>&nbsp;

最后

以上就是可靠小熊猫最近收集整理的关于React全家桶:类--类式组件--state属性--事件绑定--类中方法的this--props属性--ref--事件处理写在前面复习类相关的知识第11集 类式组件第12集 对state的理解第13集 初始化state第14集 react中事件绑定第15集 类中方法的this第16集解决类中this指向问题第17集 对setState的使用第18集 state的简写方式第19集总结state第20集 props的基本使用第21集 批量传递props第22集 对props进行限制第23集 pro的全部内容,更多相关React全家桶:类--类式组件--state属性--事件绑定--类中方法的this--props属性--ref--事件处理写在前面复习类相关的知识第11集内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(69)

评论列表共有 0 条评论

立即
投稿
返回
顶部