React:类组件(上)

kerwin老师我来了

类组件的创建

class组件,js里的类命名首字符大写,类里面包括构造函数,方法

组件类要继承React.Component才有效

必须包含render方法

import React from 'react'
class App extends React.Component{
    render() {
        return <div>hello react Component</div>
    }
}
export default App

在index.js里引入并使用标签,就算使用一个类组件了

组件返回的内容必须是封闭的,必须包括在一个完整的标签里

react16.8之前函数组件又叫无状态组件,在之后引入了hooks,函数式组件就有了状态

组件的嵌套

一个页面里只有一个根组件

声明三次组件


import React, { Component } from "react"
//export {Component},es6的模块化导出,也就是之前说过的默认导出,命名导出

//声明类组件
class Navbar extends Component {
    render() {
        return <div>navbar</div>
    }
}
//声明函数组件
function Swiper() {
    return <div>Swiper</div>
}
//箭头函数组件
const Tabbar = () => <div>Tabbar</div>

 class App extends Component{
    render(){
        return (
            <div>
                <Navbar></Navbar>
                <Swiper></Swiper>
                <Tabbar></Tabbar>
            </div>
        )
    }
}
export default App

这样直接在子组件里再写子组件是显示不出来的,其实这种方式也是可以实现爷孙嵌套的,但是先不讲

 class App extends Component{
    render(){
        return (
            <div>
                <Navbar>
                    <Child/>
                </Navbar>
                <Swiper></Swiper>
                <Tabbar></Tabbar>
            </div>
        )
    }
}

如果想体现Child是Navbar的子组件,需要单独写一个Child,然后在Navbar里调用:


import React, { Component } from "react"
//export {Component},es6的模块化导出,也就是之前说过的默认导出,命名导出
const Child = function () {
    return <div>Child</div>
}
//声明类组件
class Navbar extends Component {
    render() {
        return <div>navbar
            <Child></Child>
        </div>
    }
}
//声明函数组件
function Swiper() {
    return <div>Swiper</div>
}
//箭头函数组件
const Tabbar = () => <div>Tabbar</div>

 class App extends Component{
    render(){
        return (
            <div>
                <Navbar>
                    <Child/>
                </Navbar>
                <Swiper></Swiper>
                <Tabbar></Tabbar>
            </div>
        )
    }
}
export default App

这样就好了,还可以体现Navbar和Child的父子关系

组件的样式

{}里的内容当js处理

样式的两种处理:行内样式,使用class,给dom添加className

之所以可以把外部的css等模块直接导入,免不了webpack的支持,webpack把导入的样式模块转化为内部的style样式

而脚手架把webpack封装了

jsx里,for是js的保留字,在react的现版本更推荐htmlFor

当用户点击<label>时,浏览器会查找和for属性匹配的id,把焦点设置到input控件上

import React, { Component } from "react";

class App extends Component {
    render() {
        return (
            <div>
                <label htmlFor='username'>用户名:</label>
                <input type='text' id='username' />
            </div>
        );
    }
}

export default App;

 react里更推荐行内样式

React 推荐我们使用行内样式,因为 React 觉得每一个组件都是一个独立的整体
这个地方不能加小括号,是回调函数,加了小括号就会立马执行
   <button onClick={this.handleClick()}>add2</button>

并且这个时候onClick={},{}里面是函数的返回值,如果里面的函数加了小括号,就会执行并且把返回值赋给onClick,如果里面的函数没有返回值,就是undefined

开启this大战

import React, { Component } from "react" 
class App extends Component{

   a=100
   handleClick2() {
    console.log('onclick2',this.a)
}
  
    render(){
        return (
            
            <button onClick={this.handleClick2}>add2</button>
      
            </div>
        )
    }
}
export default App

希望可以通过点击事件回调函数的this获取App里的a

失败了孩子们                                                                                    我们来看看this是谁:                                                                                             为什么是undefined呢孩子们,谁调用this指向谁,点击以后执行,是react的事件系统调用的,指谁也指不到App啊,a是App里的属性,所以也就获取不了a了

总之就是this指向出问题了,怎么修正this指向呢?以前我们在js里学了好几个更改this的方法,比如bind()、apply()、call()

    <button onClick={this.handleClick2.bind(this)}>add2</button>
//不推荐这种写法

成功了孩子们

问题又来了:为什么是bind()呢?因为call和apply会自动调用函数,而回调函数不需要立马调用,且apply用于数组

如果想获取App的属性,可以直接用箭头函数:

import React, { Component } from "react" 
class App extends Component{

   a=100
   handleClick2() {
    console.log('onclick2',this.a)
}
    handleClick3 = () => {
    console.log('onclick3',this.a)
    }
    render(){
        return (
            <div>
                <input type='text' id='username' />
            <button onClick={this.handleClick3}>add3</button>
//比较推荐这种写法
            </div>
        )
    }
}
export default App

因为箭头函数会引用上个作用域的this,在这里就是App,所以可以打印App的属性

在里面也使用箭头函数和this调用

       <button onClick={() => {
                    this.handleClick4()
                    //可以传参,比较推荐
            }}>add4</button>
       handleClick4 = () => {
    console.log('onclick4',this.a)
}

里面的this和外面的this是一样的

                                                                                                                                                             

事件处理

React并不会真正的绑定事件到每个具体的元素上,而是采用事件代理的模式       

React 在应用的根节点(通常是 #root 或 #app)上监听所有支持的事件(如 click、change 等)事件发生时,React 会根据事件的 target(触发事件的元素)找到对应的组件,并调用组件中定义的事件处理函数,通常在冒泡阶段处理事件,也就是点击按钮时,事件冒泡到根节点,React 调用 handleClick执行。            

优点是性能优化,减少内存占用、封装了浏览器的事件系统、在组件卸载时自动移除事件监听器,避免内存泄漏   

关于事件对象e                                                                               

和普通浏览器一样,事件handler会被自动传入一个 event 对象,这个对象和普通的浏览器 event 对 象所包含的方法和属性都基本一致。不同的是 React中的 event 对象并不是浏览器提供的,而是它自己内部所构建的,也就是一个合成事件e,它是 React 对浏览器原生事件对象的封装。它同样具有 event.stopPropagation 、 event.preventDefault 这种常用的方法

ref                                                                                    

ref是引用的意思

用一种古旧的方法(react目前已不支持refs访问dom元素或组件了)获取标签:

import React, { Component } from "react" 
class App extends Component{

   a=100

    render(){
        return (
            <div>
                <input ref='mytext' />
                <button onClick={()=>{console.log('click1',this.refs.mytext)
                }}>add1</button>
            </div>
        )
    }
}
export default App

这就代表我们获取到这个元素了,获取这个元素以后也可以获取他的属性

新的写法是这么写的:

import React, { Component } from "react" 
class App extends Component{

    a=100
    myref=React.createRef()//返回一个ref对象
    render(){
        return (
            <div>
                <input ref='mytext' />
                <input ref={this.myref} />
                {/* //把ref绑定在input上 */}
                <button onClick={() => {
                    console.log('click', this.myref)
                }}>add1</button>
            </div>
        )
    }
}
export default App

获取到的是一个对象,原生dom节点被放在ref的current属性里

注意在类组件里要一直注意this指向的问题

状态

在我还没有学react的时候,我以为这样就可以切换按钮内容了

import React, { Component } from "react" 

class App extends Component{
render() {
        let text = '收藏'
        return (
            <div>        
                <button onClick={()=>text = '取消收藏'}>{text}</button>
            </div>
        )
    }
}
export default App

实则不然,在react内部并不知道你改变了它,不会渲染,需要用状态来管理

React里我们要尽量减少对dom的操作,因为react内部已经在做dom操作了,你只需要告诉他你要什么

状态可以满足我们不改变dom,通过数据来操作页面的要求

import React, { Component } from "react" 

class App extends Component{
 state = {
     show:true
       }
    render() {
       
        return (
            <div>
                <button onClick={() => { 
                    this.setState({
                        show:!this.state.show
                    })
                }}>{ this.state.show?'收藏':'取消收藏'}</button> 
            </div>
        )
    }
}
export default App

类组件更像是在用面向对象的思想编程

除了这种写法还有这样设置状态的写法

constructor() {
super()
this.state = {
name: 'React',
isLiked: false
}
}

    super() 用于调用父类(React.Component)的构造函数,保证this正确指向组件实例

    列表渲染

    写写类组件的列表渲染

    import React, { Component } from "react" 
    
    class App extends Component{
        state = {
            list: [
                {
                id:1,text:'111'
                },
                { id: 2, text: '222' },
                {id:3,text:'333'}
        ]
    }
        render() {
         
            return (
                <div>
                    <ul>
                        {this.state.list.map((item) => <li key={item.id}>{ item.text}</li>)}
                   </ul>
                </div>
            )
        }
    }
    export default App

    kerwin老师对key的解析:

    Diff 算法 是 React 用于比较虚拟 DOM(Virtual DOM)更新前后差异的核心算法。它的目的是高效地计算出需要更新的部分,从而最小化对真实 DOM 的操作,提升性能。

    对于相同的元素类型,React 会保留该 DOM 节点,只更新变化的属性。

    对于不同的元素类型,React 会销毁旧节点并创建新节点。

    Key :为列表中的每个元素提供唯一的 key,帮助 React 识别元素的移动、添加或删除,为了列表的复用和重排,设置key值,提高性能

    理想的key是数组里的对象,item.id是对象里的一个属性(最好不要拿数组下标,这样删除一个后面的都会乱,不涉及列表的增加、删除、重排是可以设置为索引值的)

    tolist制作

    添加数据

    对于状态的控制和函数组件的useState是相似的,得把更改的结果传入:

    this.state.list.push(this.myref.current.value)不能直接修改状态

    为了避免直接修改状态,我们可以复制一份修改,然后把新的值赋值回去:

         let newList = this.state.list//这样对吗?

    显然是不对的,这叫赋值,赋值的本质二者指向的还是同一块内存地址

    参考博客

    这时候其实还是相当于直接修改了状态,所以我们要进行拷贝(深拷贝和浅拷贝)

    类组件实现的todolist

    import React, { Component } from "react" 
    class App extends Component{
    
        a=100
        myref = React.createRef()//返回一个ref对象
            state = {
            list: [
                {
                id:1,text:'111'
                },
                { id: 2, text: '222' },
                {id:3,text:'333'}
        ]
    }
        render(){
            return (
                <div>
                    <input ref={this.myref} />
                    {/* //把ref绑定在input上 */}
                    <button onClick={this.handleClick}>add</button>
                    <ul>
                        {
                            this.state.list.map((item) => <li key={item.id}>{ item.text}</li>)
    }
                    </ul>
                </div>
            )
        }
        handleClick = () => {
            console.log('click', this.myref.current.value)
            //this.state.list.push(this.myref.current.value)不能直接修改状态
            let newList = [...this.state.list]
            newList.push({
                id:this.state.list.length+1,
                text:this.myref.current.value
            })
            this.setState({
                list:newList
            })
        }
    }
    export default App

    删除数据

    用bind绑定删除的元素index

    import React, { Component } from "react" 
    class App extends Component{
    
        a=100
        myref = React.createRef()//返回一个ref对象
            state = {
            list: [
                {
                id:1,text:'111'
                },
                { id: 2, text: '222' },
                {id:3,text:'333'}
        ]
    }
        render(){
            return (
                <div>
                    <input ref={this.myref} />
                    {/* //把ref绑定在input上 */}
                    <button onClick={this.handleClick}>add</button>
                    <ul>
                        {
                            this.state.list.map((item,index) => <li key={item.id}>{ item.text}<button onClick={this.handleDel.bind(this,index)}>delete</button></li>)
    }
                    </ul>
                </div>
            )
        }
        handleClick = () => {
            console.log('click', this.myref.current.value)
            //this.state.list.push(this.myref.current.value)不能直接修改状态
            let newList = [...this.state.list]
            newList.push({
                id:this.state.list.length+1,
                text:this.myref.current.value
            })
            this.setState({
                list:newList
            })
        }
        handleDel = (index) => {
            console.log('del',index)
            
        }
    }
    export default App

    其实我决定根据id删除才是更正确的方式

    import React, { Component } from "react" 
    class App extends Component{
    
        a=100
        myref = React.createRef()//返回一个ref对象
            state = {
            list: [
                {
                id:1,text:'111'
                },
                { id: 2, text: '222' },
                {id:3,text:'333'}
        ]
    }
        render(){
            return (
                <div>
                    <input ref={this.myref} />
                    {/* //把ref绑定在input上 */}
                    <button onClick={this.handleClick}>add</button>
                    <ul>
                        {
                            this.state.list.map((item,index) => <li key={item.id}>{ item.text}<button onClick={()=>this.handleDel(index)}>delete</button></li>)
    }/*{传递参数让你知道你删除的是第几个}*/
                    </ul>
                </div>
            )
        }
        handleClick = () => {
            console.log('click', this.myref.current.value)
            //this.state.list.push(this.myref.current.value)不能直接修改状态
            let newList = [...this.state.list]
            newList.push({
                id:this.state.list.length+1,
                text:this.myref.current.value
            })
            this.setState({
                list:newList
            })
        }
        handleDel = (index) => {
            console.log('del',index)
            let newList =this.state.list.slice()//复制
            newList.splice(index, 1)//删除
            this.setState(//修改状态
                {list:newList}
            )
        }
    }
    export default App

    条件渲染

    根据条件渲染

    增加一些小功能:清除input,在数组长度为0时显示todolist空空如也

    点击按钮控制受控组件的value为0

        handleClick = () => {
            console.log('click', this.myref.current.value)
            //this.state.list.push(this.myref.current.value)不能直接修改状态
            let newList = [...this.state.list]
            newList.push({
                id:this.state.list.length+1,
                text:this.myref.current.value
            })
            this.setState({
                list:newList
            })
            this.myref.current.value=''
        }

    数组长度为0时,显示暂无待办事项

    //三目运算符
       { this.state.list.length?null:<div>暂无待办事项</div>}
    //逻辑短路
     this.state.list.length===0&&<div>暂无待办事项</div>}

    还有一种方法是让他不满足条件时隐藏,满足时显示,要引入css

     <div className={this.state.list.length===0?'':'hidden'}>暂无待办事项</div>
    
    .hidden{
         display:none;
     }

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

    如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

    相关文章

    以教育之道御AI之术:培养未来人才的关键策略

    在当今这个人工智能(AI)技术日新月异的时代,AI已经渗透到我们生活的方方面面,教育领域也不例外。然而,面对AI的浪潮,我们不仅要学会利用它来提升教学效率,更要坚守教育的本质,即“以教育之道御AI之术”,培养出能够适应未来社会需求的创新型人才。 AI技术为教育带来的…

    基于qiime2的16S数据分析全流程:从导入数据到下游分析一条龙

    目录 创建metadata 把数据导入qiime2 去除引物序列 双端合并 &#xff08;dada2不需要&#xff09; 质控 &#xff08;dada2不需要&#xff09; 使用deblur获得特征序列 使用dada2生成代表序列与特征表 物种鉴定 可视化物种鉴定结果 构建进化树&#xff08;ITS一般不构建进化树…

    DeepSeek V3 并行训练、推理优化点(一)

    训练优化1&#xff0c; FP8计算 DeepSeek-V3在训练过程中统一使用E4M3格式&#xff0c;并通过细粒度的per-tile&#xff08;1x128&#xff09;和per-group&#xff08;128x128&#xff09;量化来降低误差。 FP8的好处还体现在节省显存上&#xff08;尤其是激活值&#xff09;…

    comctl32!ListView_OnSetItem函数分析LISTSUBITEM结构中的image表示图标位置

    第一部分&#xff1a; BOOL ListView_SetSubItem(LV* plv, const LV_ITEM* plvi) { LISTSUBITEM lsi; BOOL fChanged FALSE; int i; int idpa; HDPA hdpa; if (plvi->mask & ~(LVIF_DI_SETITEM | LVIF_TEXT | LVIF_IMAGE | LVIF_STATE)) { …

    Docker基础篇——Ubuntu下Docker安装

    大家好我是木木&#xff0c;在当今快速发展的云计算与云原生时代&#xff0c;容器化技术蓬勃兴起&#xff0c;Docker 作为实现容器化的主流工具之一&#xff0c;为开发者和运维人员带来了极大的便捷 。下面我们一起进行Docker安装。 Docker的官方Ubuntu安装文档&#xff0c;如…

    Python图形编程之EasyGUI: indexbox的用法

    目录<<上一章&#xff1a;ynbox用法详解 下一章&#xff1a;boolbox用法详解 >> # 1 Python图形编程之EasyGUI: indexbox的用法 1.1 基本用法 indexbox提供用户一个选择不同选项的功能&#xff0c;不同的选项由按钮来表示&#xff0c;提供类似功能的还有choicebox…

    大语言模型从理论到实践(第二版)-学习笔记(绪论)

    大语言模型的基本概念 1.理解语言是人工智能算法获取知识的前提 2.语言模型的目标就是对自然语言的概率分布建模 3.词汇表 V 上的语言模型&#xff0c;由函数 P(w1w2 wm) 表示&#xff0c;可以形式化地构建为词序列 w1w2 wm 的概率分布&#xff0c;表示词序列 w1w2 wm…

    突破极限!蓝耘通义万相2.1引爆AI多模态新纪元——性能与应用全方位革新

    云边有个稻草人-CSDN博客 目录 一、 引言 二、 蓝耘通义万相2.1版本概述 三、 蓝耘通义万相2.1的核心技术改进 【多模态数据处理】 【语音识别与文本转化】 【自然语言处理&#xff08;NLP&#xff09;改进】 【跨平台兼容性】 四、 蓝耘注册 部署流程—新手也能轻松…

    JVM常用概念之本地内存跟踪

    问题 Java应用启动或者运行过程中报“内存不足&#xff01;”&#xff0c;我们该怎么办? 基础知识 对于一个在本地机器运行的JVM应用而言&#xff0c;需要足够的内存来存储机器代码、堆元数据、类元数据、内存分析等数据结构&#xff0c;来保证JVM应用的成功启动以及未来平…

    p5.js:sound(音乐)可视化,动画显示音频高低变化

    本文通过4个案例介绍了使用 p5.js 进行音乐可视化的实践&#xff0c;包括将音频振幅转化为图形、生成波形图。 承上一篇&#xff1a;vite&#xff1a;初学 p5.js demo 画圆圈 cd p5-demo copy .\node_modules\p5\lib\p5.min.js . copy .\node_modules\p5\lib\addons\p5.soun…

    PDF处理控件Aspose.PDF,如何实现企业级PDF处理

    PDF处理为何成为开发者的“隐形雷区”&#xff1f; “手动调整200页PDF目录耗时3天&#xff0c;扫描件文字识别错误导致数据混乱&#xff0c;跨平台渲染格式崩坏引发客户投诉……” 作为开发者&#xff0c;你是否也在为PDF处理的复杂细节消耗大量精力&#xff1f;Aspose.PDF凭…

    ruo-yi项目启动备忘

    ruo-yi项目启动遇到问题备忘 参考文档: 若依 手把手启动 https://blog.csdn.net/qq_43804008/article/details/132950644?utm_mediumdistribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-132950644-blog-137337537.235^v43^pc_blog_bottom_…

    ⭐LeetCode周赛 Q1. 找出最大的几近缺失整数——模拟⭐

    ⭐LeetCode周赛 Q1. 找出最大的几近缺失整数——模拟⭐ 示例 1&#xff1a; 输入&#xff1a;nums [3,9,2,1,7], k 3 输出&#xff1a;7 解释&#xff1a; 1 出现在两个大小为 3 的子数组中&#xff1a;[9, 2, 1]、[2, 1, 7] 2 出现在三个大小为 3 的子数组中&#xff1a;[3,…

    Java 集合框架大师课:性能调优火葬场(四)

    &#x1f680; Java 集合框架大师课&#xff1a;性能调优火葬场&#xff08;四&#xff09; &#x1f525; 战力值突破 95% 警告&#xff01;调优就像吃重庆火锅——要选对食材&#xff08;数据结构&#xff09;还要控制火候&#xff08;算法&#xff09;&#x1f336;️ 第一章…

    【愚公系列】《Python网络爬虫从入门到精通》045-Charles的SSL证书的安装

    标题详情作者简介愚公搬代码头衔华为云特约编辑&#xff0c;华为云云享专家&#xff0c;华为开发者专家&#xff0c;华为产品云测专家&#xff0c;CSDN博客专家&#xff0c;CSDN商业化专家&#xff0c;阿里云专家博主&#xff0c;阿里云签约作者&#xff0c;腾讯云优秀博主&…

    蓝桥杯嵌入式组第七届省赛题目解析+STM32G431RBT6实现源码

    文章目录 1.题目解析1.1 分而治之&#xff0c;藕断丝连1.2 模块化思维导图1.3 模块解析1.3.1 KEY模块1.3.2 ADC模块1.3.3 IIC模块1.3.4 UART模块1.3.5 LCD模块1.3.6 LED模块1.3.7 TIM模块 2.源码3.第七届题目 前言&#xff1a;STM32G431RBT6实现嵌入式组第七届题目解析源码&…

    KUKA机器人:智能制造的先锋力量

    在科技日新月异的今天&#xff0c;自动化和智能化已成为推动制造业转型升级的重要引擎。作为全球领先的智能、资源节约型自动化解决方案供应商&#xff0c;KUKA机器人在这一浪潮中扮演着举足轻重的角色。本文将带您深入了解KUKA机器人的发展现状&#xff0c;探索其在智能制造领…

    Ateme在云端构建可扩展视频流播平台

    Akamai Connected Cloud帮助Ateme客户向全球观众分发最高质量视频内容。 “付费电视运营商和内容提供商现在可以在Akamai Connected Cloud上通过高质量视频吸引观众&#xff0c;并轻松扩展。”── Ateme首席战略官Rmi Beaudouin ​ Ateme是全球领先的视频压缩和传输解决方案提…

    OceanBase社区年度之星专访:张稚京与OB社区的双向奔赴

    2024年年底&#xff0c;OceanBase社区颁发了“年度之星”奖项&#xff0c;旨在表彰过去一年中为 OceanBase 社区发展作出卓越贡献的个人。今天&#xff0c;我们有幸邀请到这一荣誉的获得者——来自融科智联的张稚京老师&#xff0c;并对他进行了专访。 在过去的一年中&#xf…

    如何选择国产串口屏?

    目录 1、迪文 2、淘晶驰 3、广州大彩 4、金玺智控 5、欣瑞达 6、富莱新 7、冠显 8、有彩 串口屏&#xff0c;顾名思义&#xff0c;就是通过串口通信接口&#xff08;如RS232、RS485、TTL UART等&#xff09;与主控设备进行通信的显示屏。其核心功能是显示信息和接收输入…