react笔记_07类组件

news2024/11/28 8:36:30

目录

    • 复习
      • 展开运算符
    • 组件
      • 什么叫做组件?
      • 分类
      • 类组件
        • es6新增构造函数
        • 语法
        • 类组件渲染
        • 类组件的this指向
        • 类组件的三大属性
          • state
            • 作用
            • 语法-初始化数据
            • 语法-修改state数据
            • 语法-获取state中的数据
            • 案例
          • props
            • propTypes属性(prop-types库)
            • defaultProps属性
          • refs
            • [1] 字符串形式的ref
            • [2] 回调形式的ref
            • createRef形式的ref
        • 类组件的生命周期

复习

展开运算符

<script>
  let arr1 = [1, 3, 5, 7, 9]
  let arr2 = [2, 4, 6, 8, 10]
  // 【1】展开一个数组
  console.log(...arr1); 
  // 【2】合并数组
  let arr3 = [...arr1, ...arr2]

  // 【3】在函数接收参数使用中使用
  function sum(...numbers) {
    return numbers.reduce((preValue, currentValue) => {
      return preValue + currentValue
    })
  }
  console.log(sum(1, 2, 3, 4));

  // 【4】构造字面量对象时使用展开语法
  let person = {name: 'tom', age: 18}
  let person2 = {...person}

  // 【5】合并修改
  let person3 = {...person, name: 'jack', address: "地球"}
  console.log(person3)// {address: "地球", age: 18, name: "jack"}

  // 注意:展开运算符不能展开对象
  //console.log(...person); //报错,
</script>

总结:
展开运算符可以用来展开数组、合并数组、构造字面量对象时使用展开语法、合并修改,但是却不可以展开对象

组件

什么叫做组件?

用来实现局部功能效果的代码和资源的集合叫做组件(html/css/js/image等)

分类

在react中组件分为函数式组件与类式组件;

今天主要了解的是类式组件~

类组件

es6新增构造函数

es6新增的构造函数-class关键字

语法

在react中 类组件必须继承于React.Component这个组件(React.Component组件中存在生命周期函数等方法)

import React from 'react'
class 组件名 extends React.Component{
  render(){
    return vodom
  }
}
  • [1] 每一个类组件强制存在一个render函数,这个函数的返回值为jsx元素(vdom)
  • [2] vdom必须存在一个根标签,最外层多个标签并列是不合法的;
  • [3] 在vdom中可以插入js表达式,表达式返回的结果会相应的渲染到页面上面

类组件渲染

  • [1]查看组件首字母大/小写:

    若是首字母小写则默认为html标签,会去寻找对应的html标签并渲染,若是没有找到对应的html标签则会报错;

    若是首字母大写则默认为组件,会去寻找对应的组件并渲染,若是没有找到对应的组件就会报错;

    tips: 组件的组件名 首字母必须 大写,否则会被认作html标签

  • [2]开始渲染(此处以类组件为例)

    (1)通过new关键字去实例化对象-> 在通过new关键字去实例化对象时会自动调用constructor构造器创建实例化对象并修改this指向;
    (2)在获取到实例化对象之后,react会通过实例化对象调用render函数获取vdom并渲染;

    tips: 若是想看详细渲染、更新、销毁过程可见类组件的生命周期

类组件的this指向

this指向的原则是:谁调用指向谁

接下来我将尽可能的列举出所有类组件中方法调用,并说明方法的this指向

import React from 'react'

class App extends React.Component{
  render(){
    // 在渲染过程中也讲述过,render函数是获取到实例化对象之后由实例化对象调用的,因此this指向的是实例化对象
    console.log('render-this', this)
    return (
      <div>
        <p onClick={this.say}>111</p>
        <p onClick={this.say2}>222</p>
      </div>
    )
  }

  say(){
    // 该方法的调用是绑定在vdom上;
    // 在渲染-获取vdom时若是发现vdom上存在事件绑定则会执行被绑定的代码得到的值在事件被触发时直接调用/执行,因此this指向undefined(严格模式下)
    console.log('恭喜发财', this)
  }

  say2 = ()=>{
    // 该函数为箭头函数,需要通过作用域链寻找this,因此this指向实例化对象
    console.log('恭喜发财*2', this)
    this.say3()
  }

  say3(){
    // 该函数是实例化对象直接调用,因此this指向实例化对象
    console.log('恭喜发财*3', this)
  }
}

export default App;

类组件的三大属性

react的三大属性其实是实例化对象的三大属性,由于函数组件是没有实例化的,因此将这三大属性称为类组件的三大属性。

state
作用

用于存储数据,状态(数据)驱动试图

语法-初始化数据

state必须是一个对象

  • 若需要声明constructor函数则可以将state初始化写在constructor中

    class App extends React.Component{
      constructor(){
        super()
        this.state={
          ishot:true
        }
      }
      render(){
        return (
          <div>
            <p>今天天气{this.state.ishot?'炎热':'凉爽'}</p>
          </div>
        )
      }
    }
    

    此时页面显示‘今天天气炎热’

  • 若是不需要声明constructor函数则可以直接将state初始化在类中

    class App extends React.Component{
      state={
        ishot:true
      }
      render(){
        return (
          <div>
            <p>今天天气{this.state.ishot?'炎热':'凉爽'}</p>
          </div>
        )
      }
    }
    
语法-修改state数据

若是直接通过点语法去修改state中的数据,虽然数据变化了,但是却不会重新渲染数据

class App extends React.Component{
  state={
    name:'chaochao',
    ishot:true
  }
  render(){
    return (
      <div>
        <p>今天天气{this.state.ishot?'炎热':'凉爽'}</p>
        <p onClick={this.editstate}>改变状态</p>
      </div>
    )
  }
  editstate = ()=>{
    this.state.ishot = !this.state.ishot
    console.log('state', this.state.ishot) // false、true、false...
  }
}

可以发现,虽然每次打印ishot的值发生了变化,但是页面显示的文本一直是‘今天天气炎热’不变。

在react中可以用过setstate函数去修改state中的值,修改方式如下
语法

setState(Object/Function,[callback])
  • 方式1

    setState({属性名:属性值})
    
  • 方式2

    setState((state,props)=>{
    return {属性名: 属性值}
    })
    

    若是第一个参数为函数:当调用setState函数时,react会自动调用该函数,并将当前state与props传入,因此在该函数中是可以获取当前实例对象的state 与props的。

使用时机-什么时候使用对象/函数呢?

  • 若是新状态不依赖于原状态 -> 推荐使用对象式的state
  • 若是新状态依赖于原状态 -> 推荐使用函数式的state(因为这样不需要获取state中的数据了)
  • 举例说明:增加count的值需要依赖于当前state推荐使用函数
    class App extends React.Component{
      state={
        name:'chaochao',
        ishot:true,
        count:0
      }
      render(){
        return (
          <div>
            <p>{this.state.count}</p>
            <p onClick={this.editstate}>改变状态</p>
          </div>
        )
      }
      editstate = ()=>{
        // this.setState({count: ++this.state.count})
        this.setState(state=> ({count: ++state.count}))
      }
    }
    
    对象式的setState是函数式的setState的语法糖

注意点

[1] 使用setState去修改数据是替换还是合并?

  • 使用内置API setState去修改state中的数据,这个数据的修改不是替换而是合并
  • 举例说明
    • 在初始化时数据state = {isHot:false, xxx:111} 有两条数据
    • 当通过this.setState({isHot:true})去修改数据
    • 再次获取数据时 {isHot:true, xxx:111} xxx不会被覆盖
语法-获取state中的数据

直接通过点语法去获取state中的数据即可。需要注意的是setstate修改state中的数据是异步的,因此获取state中数据时也要注意时机。

举例说明

class App extends React.Component{
  state={
    name:'chaochao',
    ishot:true,
    count:0
  }
  render(){
    return (
      <div>
        <p>{this.state.count}</p>
        <p onClick={this.editstate}>改变状态</p>
      </div>
    )
  }
  editstate = ()=>{
    this.setState(state=> ({count: state.count+1}))
    console.log('state', this.state.count)
  }
}

上述案例中 在第一次点击时 页面显示的数值是1,而打印的还是之前的值0。

这是因为setState更新数据是异步的,若是想要在通过setState修改数据后,立即拿到修改后的数据,可以使用setState的第二个参数

   this.setState(stateChange,[callback])

第二个参数是一个回调函数,该回调函数的执行时机是在 在此次数据更新的render函数调用之后执行 : setState->render -> callback

editstate = ()=>{
  this.setState(state=> ({count: state.count+1}),()=>{
    console.log('state', this.state.count)
  })  
}

此时第一次点击,控制台打印的就是1了

案例

案例:默认显示文本 今天天气炎热,当点击文本时显示 今天天气凉爽

class App extends React.Component{
  state={
    ishot:true
  }
  render(){
    const {ishot} = this.state
    return (
      <div>
        <p onClick={this.editstate}>今天天气{ishot?'炎热':'凉爽'}</p>
      </div>
    )
  }
  editstate = ()=>{
    this.setState(state=> ({ishot: !state.ishot}))
  }
}
props

和vue相同,props在react中的作用也是进行父子传值。

  • 在父组件中: 将需要传递给子组件的数据以 属性 的形式添加在子组件标签上
    <子组件 属性名1=属性值1 属性名2=属性值2 .../>
    
  • 在子组件中:通过实例化对象的props属性进行接收
    this.props // 将接收到props这个对象中
    

示例如下:

import React from 'react'

class People extends React.Component{
 render(){
   console.log('props', this.props) // {name: 'chaochao', age: 18, area: '中国'}
   return 111
 }
}

class App extends React.Component{
 render(){
   return (
     <div>
       <People name='chaochao' age={18} area='中国'/>
     </div>
   )
 }
}

export default App;

同样的,我们可以约定规范 如传递数据的数据类型、是否可以为空、设置默认值等。

propTypes属性(prop-types库)

在 React v15.5 版本之前,在React上存在PropTypes函数用于进行props属性的类型交验。

从 React v15.5 开始 ,React.PropTypes 助手函数已被弃用,更推荐使用 prop-types 库 来定义contextTypes。

使用语法如下:

  • 下载prop-types库
      npm i prop-types
    
  • 引入prop-types库
      import PropTypes from 'prop-types'
    
  • 给类组件添加propTypes属性进行属性限制,限制规则如下
    PropTypes.number // 数据为数字类型
    PropTypes.string // 数字为字符串类型
    PropTypes.bool // 数据为boolean值
    PropTypes.symbol // 数据为symbol值
    PropTypes.array // 数据为数组类型
    PropTypes.func // 数据为函数类型
     PropTypes.element // 数据为React元素
     PropTypes.instanceOf(Message) //prop 是类的一个实例
     PropTypes.oneOf(['News', 'Photos']) // prop是一个枚举
     PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
      PropTypes.instanceOf(Message)
    ]) // prop是多种类型之一
    PropTypes.func.isRequired // prop是函数类型且必填
    PropTypes.any.isRequired // prop可以是任意类型但必填
    
  • 语法如下:
      static propTypes = {
        属性值: 规则限制
      }
    
      Component.propTypes = {
        属性值: 规则限制
      }
    
  • 举例说明
    import React from 'react'
    import PropTypes from 'prop-types'
    import './App.css';
    
    // 子组件 - 希望name属性值为字符串类型且必填,sex属性为字符串类型默认值为‘weizhi’(默认值后面讲解defaultProps属性时再进行设置), age属性值为数字类型
    class People extends React.Component{
      static propTypes = {
        name: PropTypes.string.isRequired,
        sex: PropTypes.string,
        age: PropTypes.number
      }
      render(){
        // console.log('props', this.props)
        return (
          <>
            son
          </>
        )
      }
    }
    
    class App extends React.Component{
      render(){
        return (
          <div>
            <People name='chaochao' sex='nv' age='18'/>
          </div>
        )
      }
    }
    
    
    export default App;
    
    此时name属性、sex属性赋值没有问题,但是age属性的赋值却不符合要求,因此在控制台会给出警告(但是不会报错),如下:
    在这里插入图片描述
defaultProps属性

propTypes属性用于规范prop的类型,defaultProps属性用于设置属性默认值,语法如下:

 static propTypes = {
   属性值: 规则限制
 }
Component.propTypes = {
 属性值: 规则限制
}

上面案例为sex添加默认值如下

import React from 'react'
import PropTypes from 'prop-types'
import './App.css';

// 子组件- 希望name属性值为字符串类型且必填,sex属性为字符串类型默认值为‘weizhi’, age属性值为数字类型
class People extends React.Component{
  static propTypes = {
    name: PropTypes.string.isRequired,
    sex: PropTypes.string,
    age: PropTypes.number
  }
  static defaultProps = {
    sex:'weizhi'
  }
  render(){
    console.log('props', this.props) // {name: 'chaochao', age: 18, sex: 'weizhi'}
    return (
      <>
        son
      </>
    )
  }
}

class App extends React.Component{
  render(){
    return (
      <div>
        <People name='chaochao' age={18}/>
      </div>
    )
  }
}
refs

在react中尽量不要直接操作dom,如果要操作dom,可以使用refs;
定义ref的形式有3种

[1] 字符串形式的ref

字符串形式的ref与Vue中ref的使用相同~

每个类实例化对象身上都存在一个refs属性,该属性为一个对象。

若是想要获取某个dom,则可以给该vdom上添加ref属性-属性值为字符串。添加之后就会将该dom以键值队的形式添加到refs对象中。

若是没有给任何vdom添加ref属性,则该实例化对象的refs属性为一个空对象。

获取dom元素需要等待dom元素渲染完毕,在render里面是获取不到dom元素的,如下:

class App extends React.Component{
  render(){
    console.log('refs', this.refs) // {}
    return (
      <div ref='box'></div>
    )

  }
}

在渲染完毕之后就可以正常获取dom元素了

class App extends React.Component{
  render(){
    return (
      <div ref='box'>
        <button onClick={this.getValue}>点我显示数据</button>
      </div>
    )

  }
  getValue=()=>{
    console.log('refs', this.refs) // refs {box: div}
  }
}

需要注意的是该形式在官方不推荐使用,因为使用此方式定义ref若是多次定义—效率有很大的问题。
若是使用字符串形式获取dom,则会在控制台提示如下
在这里插入图片描述

[2] 回调形式的ref

在了解回调形式的ref之前需要先了解什么是回调?

  • [1] 定义了一个函数
  • [2] 没有主动调用函数
  • [3] 函数最终执行了

什么是回调形式的ref呢?

若是想获取dom元素,就在vdom上添加ref属性只不过属性值是一个函数。

在渲染vdom时,若是发现ref属性值是一个函数,react会调用这个函数并且将该dom作为参数传入。

class App extends React.Component{
  render(){
    return (
      <div ref={dom => {
        console.log('dom', dom)
        this.box = dom // 获取到dom元素进行赋值
      }}>
        <button onClick={this.getValue}>点我显示数据</button>
      </div>
    )

  }
  getValue=()=>{
    console.log('box', this.box) // dom元素
  }
}

但是像以上这种将回调函数写在行内的会存在一个问题:更新时重新调用render函数时会重新调用该回调函数两次

class App extends React.Component{
  state = {
    hot: true
  }
  render(){
    return (
      <div ref={dom => {
        console.log('dom', dom)
        this.box = dom // 获取到dom元素进行赋值
      }}>
      <button onClick={()=>{
        this.setState({hot: false})
      }}>点我修改hot</button>
      </div>
    )

  }
}

在上述案例中,当我点击“点我修改hot”时,发现回调函数执行了两次结果如下:
在这里插入图片描述
第一次获取的dom是个空值,第二次获取真实dom。

原来这个问题产生的根本原因是将回调函数写在了行内

  • 当将函数写在行内时
    • 渲染-> 执行render函数时-> 发现ref绑定的是一个函数,会自动调用该函数并将该dom元素作为参数传入;
    • 更新 ->重新调用render函数,此次执行过程中会调用2次该函数—第一次传入的参数为null,第二次传入的才是dom
      没有造成实质的影响,因为这两次调用过程很短暂;
  • 不将回调函数写在行内
    • 渲染-> 执行render函数时-> 发现ref绑定的是一个函数,会自动调用该函数并将该dom元素作为参数传入;
    • 更新 -> 不调用此函数;
createRef形式的ref

在React上存在createRef方法,该方法被调用后会返回一个对象

{
  current:... 
}

该容器可以存储ref所标识的节点(存储在current属性中),该容器是专人专用的(一个容器仅能存储一个dom)

this.input = React.createRef() // 产生一个容器
<input ref={ this.input }> //  存储
const {current} = this.input // 容器的current属性表示当前的dom元素

举例说明

class App extends React.Component{
  box = React.createRef()
  render(){
    return (
      <div ref={this.box}>
      <button onClick={()=>{
        console.log('box', this.box.current)
      }}>点我修改hot</button>
      </div>
    )
  }
}

类组件的生命周期

生命周期

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/719862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搞定HashMap

搞定HashMap 1.Map是个啥&#xff1f; HashMap隶属于Java中集合这一块&#xff0c;我们知道集合这块有list&#xff0c;set和map&#xff0c;这里的HashMap就是Map的实现类&#xff0c;那么在Map这个大家族中还有哪些重要角色呢&#xff1f; 上图展示了Map的家族&#xff0c;…

Cernox 温度传感器碳陶瓷基体结构

Cernox 温度传感器具有高灵敏度、稳定性好、遵循单一电阻与温度曲线&#xff0c;磁场性能优良和耐辐射等特性。适用于低温系统中1.5-375K范围内的测量。传感器在及其严格的质量控制下制造&#xff0c;并在强磁场、中子伽马辐射、热循环和机械耐久条件下证明长期稳定性。与其他可…

基于springboot+mysql+jsp高校社团管理系统

基于springbootmysqljsp高校社团管理系统 一、系统介绍二、所用技术三、功能展示三、其它系统四、获取源码 一、系统介绍 管理员&#xff1a;登录注册、个人中心&#xff08;个人信息、密码修改、注销&#xff09;、近期活动&#xff08;所有活动、文体类活动、学术类活动、公…

微服务学习1——微服务环境搭建

微服务学习1——微服务环境搭建 &#xff08;参考黑马程序员项目&#xff09; 个人仓库地址&#xff1a;https://gitee.com/jkangle/springboot-exercise.git 微服务就是将单体应用进一步拆分&#xff0c;拆成更小的服务&#xff0c;拆完之后怎么调用&#xff0c;主流的技术有…

【分布式】zabbix 6.0部署讲解

目录 一、 序章二、zabbix概念2.1 zabbix是什么&#xff1f;2.2 zabbix 监控原理2.3 zabbix 6.0 新特性2.4 zabbix 6.0 功能组件 三、zabbix 6.0 部署部署服务端3.1 部署 Nginx PHP 环境并测试3.1.1 安装nginx3.1.2 安装php3.1.3 修改 Nginx 配置3.1.4 修改 php 配置3.1.5 创建…

Python +selenium 自动化之元素定位

selenium之八大元素定位&#xff1a; 1、通过ID的方式定位 id是页面的唯一标识 例如&#xff1a;找到百度的搜索输入框 driver.findElement(By.id("kw")) 2、通过tagName的方式定位 用标签名定位非常少 ---一般会重复 driver.findElements(By.tagName(&qu…

Vue2 Diff 算法简易版

背景 最近复习的过程中&#xff0c;准备对比一下Vue2和Vue3的diff算法区别&#xff0c;好知道两者直接的差异和优缺点。刚好看了网上的文章&#xff0c;但是对方写的代码不太正确&#xff0c;所以特意记录一下我的学习过程~ 双端比较法 Vue2采用的双端比较法&#xff0c;即新…

MBD开发 STM32 Timer

开两个定时器 一快一慢 两个中断都要使能 没有自动更新&#xff0c;切换下timerx就好了&#xff0c;但是触发UP要手动勾选

剑指offer27.二叉树的镜像

这道题很简单&#xff0c;写了十多分钟就写出来了&#xff0c;一看题目就知道这道题肯定要用递归。先交换左孩子和右孩子&#xff0c;再用递归交换左孩子的左孩子和右孩子&#xff0c;交换右孩子的左孩子和右孩子&#xff0c;其中做一下空判断就行。以下是我的代码&#xff1a;…

爬虫入门指南(8): 编写天气数据爬虫程序,实现可视化分析

文章目录 前言准备工作爬取天气数据可视化分析完整代码解释说明 运行效果完结 前言 天气变化是生活中一个重要的因素&#xff0c;了解天气状况可以帮助我们合理安排活动和做出决策。本文介绍了如何使用Python编写一个简单的天气数据爬虫程序&#xff0c;通过爬取指定网站上的天…

Pandas+Pyecharts | 双十一美妆销售数据分析可视化

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 数据信息2.3 筛选有销量的数据 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 双十一前后几天美妆订单数量3.2 双十一前后几天美妆销量3.3…

【Linux】线程终结篇:线程池以及线程池的实现

linux线程完结 文章目录 前言一、线程池的实现二、了解性知识 1.其他常见的各种锁2.读者写者问题总结 前言 什么是线程池呢&#xff1f; 线程池一种线程使用模式。线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#xff0c;等待着…

智能、安全、高效,看移远如何助力割草机智能化升级

提到割草机&#xff0c;大家可能首先会想到其噪声大、费人力、安全性不足等问题。智能割草机作为一种便捷、高效的智能割草设备&#xff0c;能够自主完成草坪修剪工作&#xff0c;很好地解决传统割草机的痛点问题。 随着人们对家庭园艺以及生活质量要求的逐步提高&#xff0c;割…

向量数据库:新一代的数据处理工具

在我们的日常生活中&#xff0c;数据无处不在。从社交媒体的帖子到在线购物的交易记录&#xff0c;我们每天都在产生和处理大量的数据。为了有效地管理这些数据&#xff0c;我们需要使用数据库。数据库是存储和管理数据的工具&#xff0c;它们可以按照不同的方式组织和处理数据…

python实现简单贪吃蛇

import math import pygame import time import numpy as np # 此模块包含游戏所需的常量 from pygame.locals import *# 设置棋盘的长宽 BOARDWIDTH 90 BOARDHEIGHT 50 # 分数 score 0# 豆子 class Food(object):def __init__(self):self.item (4, 5)# 画出食物def _draw(…

qtav源码包编译(qt5.15+msvc2019)、使用vlc media player串流生成rtsp的url并且在qml客户端中通过qtav打开

QTAV源码包编译 下载源码 下载依赖库&#xff08;里面有ffmepg等内容&#xff09; https://sourceforge.net/projects/qtav/files/depends/QtAV-depends-windows-x86x64.7z/download下载源码包 https://github.com/wang-bin/QtAV更新子模块 cd QtAV && git submod…

vmware postgresql大杂烩

Vmware 窗口过界&#xff1a; https://blog.csdn.net/u014139753/article/details/111603882 vmware, ubuntu 安装&#xff1a; https://zhuanlan.zhihu.com/p/141033713 https://blog.csdn.net/weixin_41805734/article/details/120698714 centos安装&#xff1a; https://w…

【Go】短信内链接拉起小程序

一、 需求场景 (1) 业务方&#xff0c;要求给用户发送的短信内含有可以拉起我们的小程序指定位置的链接&#xff1b; 【XXX】尊敬的客户&#xff0c;您好&#xff0c;由于您XX&#xff0c;请微信XX小程序-微信授权登录-个人中心去XX&#xff0c;如已操作请忽略&#xff0c;[…

Jenkins2.346新建项目时没有Maven项目选项解决办法

解决办法&#xff1a;需要安装Maven Integration 系统管理-->管理插件-->可选插件-->过滤输入框中输入搜索关键字&#xff1a; Maven Integration&#xff0c;下载好后安装。

Mysql:创建和管理表(全面详解)

创建和管理表 前言一、基础知识1、一条数据存储的过程2、标识符命名规则3、MySQL中的数据类型 二、创建和管理数据库1、创建数据库2、使用数据库3、修改数据库4、删除数据库 三、创建表1、创建方式12、创建方式23、查看数据表结构 四、修改表1、追加一个列2、修改一个列3、重命…