我是靠谱客的博主 可靠小熊猫,最近开发中收集的这篇文章主要介绍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指向问题的追根溯源,又比如三大实例属性简写的由来,总之我还是决定做一份事无巨细的笔记。

那就让我们开始吧!

复习类相关的知识

创建实例对象

    //创建一个Person类
    class Person {
    
    }
    
    let person1 = new Person();
    console.log(person1)
  • 输出分解

image.png

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

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

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

接收参数

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

构造器也是在原型上的

//创建一个Person类
class Person {
        //构造器方法
        constructor(name,age){
                //构造器中的this是谁?—— 类的实例对象
                this.name = name
                this.age = age
        }
}

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

  • 定义方法
//创建一个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:调用父类的构造器

//创建一个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实例的原型对象上找到。

class Student extends Person {
        constructor(name,age,grade){
                super(name,age)
                this.grade = grade
                this.school = '尚硅谷'
        }
}

image.png

  • 重写方法
//创建一个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.如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的。

3.类中所定义的方法,都放在了类的原型对象上,供实例去使用。

第11集 类式组件

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

创建类式组件

  • 必须继承React内置一个类

必须继承React.Component

  • 可以省略构造器

传送门

https://react.docschina.org/

image.png

  • 书写必备的三个条件
  1. 必须继承React.Component
  2. 必学书写render方法
  3. redner必须有返回值
<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.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

	super(props)

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

image.png

  • 给state赋值是一个对象
//初始化状态
this.state = {isHot:false,wind:'微风'}
  • 渲染到页面
	<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种类型
<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指向

<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

<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指向

//解决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

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的简写方式

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

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改为箭头函数模式

//自定义方法————要用赋值语句的形式+箭头函数
    changeWeather = ()=>{
        const isHot = this.state.isHot
        this.setState({isHot:!isHot})
    }

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

  • 注意不允许这么写
changeWeather()=>{
    const isHot = this.state.isHot
    this.setState({isHot:!isHot})
}

简写state

直接使用赋值语句

//初始化状态
state = {isHot:false,wind:'微风'}

第19集总结state

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

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

第20集 props的基本使用

传递组件属性

image.png

image.png

<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

<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

  • 不同版本不同写法
//对标签属性进行类型、必要性的限制
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版本之后

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

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

属性默认值

//指定默认标签属性值
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
constructor(props){
        //构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
        // console.log(props);
        super(props)
        console.log('constructor',this.props); // super constructor里面缺一个没传props参数都不可,否则就是undefined
}

第25集 函数式组件使用props

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

<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进行限制

  • 对组件添加属性
 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标识
<input ref="input1" type="text" placeholder="点击按钮提示数据"/>&nbsp;

image.png

//展示左侧输入框的数据
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
<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注释方法
	{/*<input ref={(c)=>{this.input1 = c;console.log('@',c);}} type="text"/><br/><br/>*/}
  • 将 ref 的回调函数定义成 class 的绑定函数的方式
<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) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件---为了更好的兼容性

2) React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)---为了更高效

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

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

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

这里就是div

image.png

  • 避免过度使用ref

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

//展示右侧输入框的数据
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集 类式组件第12集 对state的理解第13集 初始化state第14集 react中事件绑定第15集 类中方法的this第16集解决类中this指向问题第17集 对setState的使用第18集 state的简写方式第19集总结state第20集 props的基本使用第21集 批量传递props第22集 对props进行限制第23集 pro所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部