React:类组件(中)

news2025/7/8 15:34:17

dangerouslySetInnerHTML

React写进{}内的东西,不允许被当作代码块解析,是为了防止xss攻击和代码注入

XSS(跨站脚本攻击,Cross-Site Scripting) 是一种常见的安全漏洞,攻击者通过注入恶意脚本到网页中,从而在用户浏览器中执行恶意代码。XSS 攻击通常发生在 Web 应用程序中,尤其是当用户输入的内容未经过滤或转义就直接显示在页面上时。

代码注入:恶意用户可以通过注入 HTML 或 JavaScript 代码,篡改页面内容或窃取用户数据

不过如果你想忽略跨站脚本攻击也是可以的

dangerouslySetInnerHTML 是React 中用于直接设置 HTML 内容的一个特殊属性。它的名字中的 "dangerously" 暗示了它的潜在风险:如果使用不当,可能会导致 XSS(跨站脚本攻击) 等安全问题

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}>
                            <span dangerouslySetInnerHTML={
                                { __html: item.text }
                            }></span>
<button onClick={() => this.handleDel(index)}>delete</button></li>)
}
                </ul>
                <div className="hidden">暂无待办事项</div>
            </div>
        )
    }

只有你很信任后端给的数据才可以这么写哦

或者是后端ajax返回的数据可以直接被渲染也可以这么用

影院案例

使用猫的眼睛的电影对外的API访问数据

 constructor() {
        super()

        this.state = {
            cinemaList: [],
            bakcinemaList:[]
        }
        //用axios请求数据
        axios.get('https://apis.netstart.cn/maoyan/index/moreCinemas?day=2021-11-12&offset=0&limit=20&districtId=-1&lineId=-1&hallType=-1&brandId=-1&serviceId=-1&areaId=-1&stationId=-1&item&updateShowDay=true&reqId=1636710166221&cityId=1&lat=23.135636443326355&lng=1').then(res => {
            console.log(res)
            this.setState({
                cinemaList: res.data,
                bakcinemaList: res.data
                
            })
        }).catch(err => {
            console.log(err)
        })

    }

再用map将数组元素转化为标签进行渲染

 {
                        this.state.cinemaList.map(item => <dl key={item.cinemaId}>
                            <dt>{ item.title}</dt>
                            <dd>{ item.location}</dd>

                        </dl>)
                    }

加上样式:


*{
    margin: 0;
    padding:0;
}
ul{
    list-style: none;
    display:flex;
    position: fixed;
    bottom:0px;
    left:0px;
    height: 50px;
    line-height:50px;
    width:100%;
    background-color:white ;
}
ul li{
    flex:1;
    text-align: center;
}
.active{
    color:red;
}
dl{
    height:50px;
    border-bottom:1px solid grey;
}

dl dt{
    font-size: 20px;
}
dl dd{
    font-size: 12px;
    color: grey;
}
input{
width: 100%;
height: 30px;
line-height: 30px;
font-size: medium;
}

记得导入样式

当触发事件的元素和ref为一个元素时,可以利用事件对象e代替ref

所以在这个模糊搜索功能处,可以用target.value获取input输入框的值,然后使用filter筛选标题和地址满足要求的影院

很简单的小项目捏

import React from 'react'
import axios from 'axios'
class Cinema extends React.Component{
    constructor() {
        super()

        this.state = {
            cinemaList: [],
            bakcinemaList:[]
        }
        //用axios请求数据
        axios.get('https://apis.netstart.cn/maoyan/index/moreCinemas?day=2021-11-12&offset=0&limit=20&districtId=-1&lineId=-1&hallType=-1&brandId=-1&serviceId=-1&areaId=-1&stationId=-1&item&updateShowDay=true&reqId=1636710166221&cityId=1&lat=23.135636443326355&lng=1').then(res => {
            console.log(res)
            this.setState({
                cinemaList: res.data,
                bakcinemaList: res.data
                
            })
        }).catch(err => {
            console.log(err)
        })

    }
    //生命周期函数更适合发送ajax请求
    render() {
        
        return (
            <div>
                <input onChange={this.handleInput}/>
                      {
                        this.state.cinemaList.map(item => <dl key={item.cinemaId}>
                            <dt>{ item.title}</dt>
                            <dd>{ item.location}</dd>

                        </dl>)
                    }
             
                  </div> 
        )
 
    }
    handleInput = (event) => {
            //感觉这里可以加一个防抖
            console.log('input', event.target.value)
            let newList = this.state.bakcinemaList.filter(item => item.title.includes(event.target.value)||item.location.includes(event.target.value))
            this.setState({
              cinemaList:newList
          })
        }
}
export default Cinema

setState在类组件里也同样是异步的

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

        this.setState({
            count:this.state.count+1
        })
        console.log(this.state.count)

    }
}

setState处在同步的环境中,异步更新状态,异步更新真实dom,一个事件循环彻底结束后,在下一轮宏任务中更新状态

在react18以前,setState在异步的情况下是同步的,不过现在React 18 及之后:引入了自动批处理,即使在异步代码中,setState 也可能表现为异步。

useState 的更新既不是宏任务,也不是微任务,而是由 React 的调度机制管理。

setState是改变状态的,你怎么知道他什么时候改变完呢?

setState的第二个参数可以传回调函数,获取的状态是当前作用域内的state,也就是说:

 handleClick2 = () => {
        setTimeout(() => {
            this.setState({
            count:this.state.count+1
        },()=>  console.log('setState的第二个参数',this.state.count))
      console.log('外部的state',this.state.count)
        },0)
    }

这个第二个参数里的回调函数,是在状态和dom都更新完以后才执行的

BetterScroll

让页面更平滑的滚动

我个人感觉这更像是对setState第二个参数的妙用,因为这个回调函数会在状态和dom都完成更新后再执行

例如BetterScroll本身可以更平滑的滚动,但是要想把数据全部包在wraper里,就要在dom树和状态都更新完以后,再创建wrapper实例:

import React, { Component } from "react" 
import BetterScroll from 'better-scroll'
class App extends Component{

  state={
list:[]
  }
    render(){
        return (
            <div>
                <button onClick={()=>this.getData()}>click</button>
                <div className='wrapper' style={{height:'200px',background:'yellow',overflow:'hidden'}}>
                    <ul className='content' >
                        {
                            this.state.list.map(item => <li key={item}>{item}</li>)
                        }
                    </ul>
               </div>
            </div>
        )
    }
    getData() {
        let list = [1, 2, 3, 4, 5, 6, 7, 8,9,10,11,12,13]
        this.setState({
            list:list
        }, () => { new BetterScroll('.wrapper') })
     
    }
}
export default App

把影院组件套到BetterScroll上来,一定要满足以下结构:

   return (
            <div>
                <input onChange={this.handleInput}/>
            
                 <div className='wrapper' style={{height:'500px',background:'yellow',overflow:'hidden'}}>
                    <div className='content'>
                     {
                        this.state.cinemaList.map(item => <dl key={item.cinemaId}>
                            <dt>{ item.title}</dt>
                            <dd>{ item.location}</dd>

                        </dl>)
                    }
                     </div>
                </div>
                  </div> 
        )

kerwin老师说可以不放在setState的第二个参数上也可以执行,我试了试react18不行哦

  //用axios请求数据
        axios.get('https://apis.netstart.cn/maoyan/index/moreCinemas?day=2021-11-12&offset=0&limit=20&districtId=-1&lineId=-1&hallType=-1&brandId=-1&serviceId=-1&areaId=-1&stationId=-1&item&updateShowDay=true&reqId=1636710166221&cityId=1&lat=23.135636443326355&lng=1').then(res => {
            console.log(res)
            this.setState({
                cinemaList: res.data,
                bakcinemaList: res.data
                
            },()=>{new BetterScroll('.wrapper') })//貌似react18必须放在这个位置
            
        }).catch(err => {
            console.log(err)
        })

状态是react里很重要的一种数据挂载的方式捏

属性

属性之于标签就像参数之于函数,属性是父组件传过来的:

import React, { Component } from "react" 
import Navbar from "./base/Navbar"
class App extends Component{

    render(){
        return (
            <div>
                <div>
                <h2>首页</h2>
                <Navbar tittle='首页'/>
                </div>
                <div>
                <h2>列表</h2>
                <Navbar tittle='列表'/>
                </div>
                <div>
                <h2>购物车</h2>
                <Navbar tittle='购物车'/>
                </div>
            </div>
        )
    }
}
export default App

通过this.props获取属性

渲染到网页上去:

import React, { Component } from "react" 
class Navbar extends Component{
    state = {
    //只能内部自己用,外部无法改变
}
 //属性是父组件传来的,通过this.props获取
    render() {
        console.log(this.props)
        let {tittle}=this.props
        return (
            <div>
               Navbar-{tittle}
            </div>
        )
    }
}
export default Navbar

这样我们就实现了对属性的键值对使用,在组件上通过key=value 写属性,通过this.props获取属性,这样组件的可复用性提高了。

还可以根据属性进行条件渲染

false和true要放在{}里才会被当作boolean处理,不然就是字符串,只要字符串不为空怎么判断都是true

props.js

import React, { Component } from "react" 
import Navbar from "./base/Navbar"
class App extends Component{

 
    render(){
        return (
            <div>
                <div>
                <h2>首页</h2>
                <Navbar tittle='首页' leftshow={false}/>
                </div>
                <div>
                <h2>列表</h2>
                <Navbar tittle='列表' leftshow={true}/>
                </div>
                <div>
                <h2>购物车</h2>
                <Navbar tittle='购物车' leftshow={true}/>
                </div>
            </div>
        )
    }
}
export default App

index.js

import React, { Component } from "react" 

class Navbar extends Component{
    state = {
    //只能内部自己用,外部无法改变
}
 //属性是父组件传来的,通过this.props获取
    render() {
        console.log(this.props)
        let {tittle,leftshow}=this.props
        return (
            <div>
               {leftshow &&<button>返回</button>}
                Navbar-{tittle}
                 <button>home</button>
            </div>
        )
    }
}
export default Navbar

首页模块无法返回,所以不显示左按钮

验证属性

在接收属性的时候要做验证

类属性:定义在类本身上的属性,而不是类的实例上的属性。它们通常用于存储与类相关的共享数据或方法。在es7里为了区分类属性和对象属性,在前面加一个关键字static,所以类属性也叫静态属性

对象属性:定义在类的实例上的属性,每个实例都有自己独立的对象属性。要想访问对象属性,就必须先创建实例

class Test{
    a = 1//对象属性
    static a=100//类属性
}
let obj = new Test()
console.log('类属性',Test.a,'对象属性:',obj.a)

做好对属性封装的验证,才能知道你用的属性对不对:

import React, { Component } from "react" 
import AugustTypes from 'prop-types'

console.log(AugustTypes)

class Navbar extends Component {
    state = {
        //只能内部自己用,外部无法改变
    }
    
    //属性是父组件传来的,通过this.props获取
    render() {
        console.log(this.props)
        let { title, leftshow } = this.props
        return (
            <div>
                {leftshow && <button>返回</button>}
                Navbar-{title}
                <button>home</button>
            </div>
        )
    }
   
}
 //类属性
  Navbar.propTypes = {
        title: AugustTypes.string,
        leftshow:AugustTypes.bool
    }

export default Navbar

添加默认属性

可以这样写在外面

也可以加上static关键字写在类里面:

import React, { Component } from "react" 
import AugustTypes from 'prop-types'

console.log(AugustTypes)

class Navbar extends Component {
    state = {
        //只能内部自己用,外部无法改变
    }
     //类属性
    static propTypes = {
        title: AugustTypes.string,
        leftshow:AugustTypes.bool
    }

    //默认属性
    static defaultProps = {
    leftshow:true
}
    
    //属性是父组件传来的,通过this.props获取
    render() {
        console.log(this.props)
        let { title, leftshow } = this.props
        return (
            <div>
                {leftshow && <button>返回</button>}
                Navbar-{title}
                <button>home</button>
            </div>
        )
    }
   
}
export default Navbar

属性注意事项

可以利用对象的解构赋值来添加属性,或者说属性也可以写成一个对象:

import React, { Component } from "react" 
import Navbar from "./base/Navbar"
class App extends Component{

 
    render() {
           let obj = {
             title: 'test',
             leftshow:false
            }
        return (
            
            <div>
               
                <Navbar title={obj.title} leftshow={obj.leftshow}/>
                <Navbar {...obj} />
            </div>
        )
    }
}
export default App

效果是一样的

 

在函数式组件里props是函数的形参,在使用的时候解构就可以,之前学过这里就不写了

状态和属性的区别

相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)

不同点:

1. 属性能从父组件获取,状态不能

2. 属性可以由父组件修改,状态不能

3. 属性能在内部设置默认值,状态也可以,设置方式不一样

4. 属性不在组件内部修改,状态要在组件内部修改

5. 属性能设置子组件初始值,状态不可以

6. 属性可以修改子组件的值,状态不可以

state 的主要作用是用于组件保存、控制、修改自己的可变状态。 state 在组件内部初始化,可以被 组件自身修改,而外部不能访问也不能修改。你可以认为 state 是一个局部的、只能被组件自身控制 的数据源。 state 中状态可以通过 this.setState 方法进行更新, setState 会导致组件的重新渲染。

props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参 数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props ,否则组件的 props 永远保持不变(算是一种单向数据流)。父子通信本身也是子向父发出请求,父再修改属性传给子,属性是只读的:子组件不能直接修改父组件传递的属性。

没有 state 的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件 (stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。

状态可以被当作属性值传递给子组件

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

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

相关文章

第六次CCF-CSP认证(含C++源码)

第六次CCF-CSP认证 数位之和&#xff08;easy&#xff09;思路及AC代码遇到的问题 开心消消乐&#xff08;easy&#xff09;思路及AC代码 画图&#xff08;mid&#xff09;思路及AC代码 数位之和&#xff08;easy&#xff09; 题目链接 思路及AC代码 既然题目要求我们输出各位…

SpringBoot 如何调用 WebService 接口

前言 调用WebService接口的方式有很多&#xff0c;今天记录一下&#xff0c;使用 Spring Web Services 调用 SOAP WebService接口 一.导入依赖 <!-- Spring Boot Web依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId…

算法 之 树形dp 树的中心、重心

文章目录 重心实践题目小红的陡峭值 在树的算法中&#xff0c;求解树的中心和重心是一类十分重要的算法 求解树的重心 树的重心的定义&#xff1a;重心是树中的一个节点&#xff0c;如果将这个点删除后&#xff0c;剩余各个连通块中点数的最大值最小&#xff0c;那么这个节点…

Docker 配置镜像源

》》Daemon {"registry-mirrors": ["https://docker.1ms.run","https://docker.xuanyuan.me"] }》》》然后在重新 docker systemctl restart docker

Linux 离线部署Ollama和DeepSeek-r1模型

都在复制粘贴联网状态下linux部署deepseek&#xff0c;离线状态下需要下载Ollama和DeepSeek模型&#xff0c;然后将下载包上传到linux中。 1、下载Ollama https://github.com/ollama/ollama/releases 注意&#xff1a;如果CentOS7建议安装V0.5.11版本&#xff0c;V0.5.13需要…

SQLAlchemy系列教程:如何执行原生SQL

Python中的数据库交互提供了高级API。但是&#xff0c;有时您可能需要执行原始SQL以提高效率或利用数据库特定的特性。本指南介绍在SQLAlchemy框架内执行原始SQL。 在SQLAlchemy中执行原生SQL SQLAlchemy虽然以其对象-关系映射&#xff08;ORM&#xff09;功能而闻名&#xff…

RuleOS:区块链开发的“新引擎”,点燃Web3创新之火

RuleOS&#xff1a;区块链开发的“新引擎”&#xff0c;点燃Web3创新之火 在区块链技术的浪潮中&#xff0c;RuleOS宛如一台强劲的“新引擎”&#xff0c;为个人和企业开发去中心化应用&#xff08;DApp&#xff09;注入了前所未有的动力。它以独特的设计理念和强大的功能特性&…

【编译器】VSCODE烧录ESP32-C3——xiaozhi智能聊天机器人固件

【编译器】VSCODE烧录ESP32-C3——xiaozhi智能聊天机器人固件 文章目录 [TOC](文章目录) 前言一、方法一&#xff1a;使用固件烧录工具1. 安装CH340驱动2. 打开FLASH_DOWNLOAD文件3. 选择芯片类型和烧录方式4. 选择烧录文件5. 参数配置 二、方法二&#xff1a;VSCODE导入工程1.…

显式 GC 的使用:留与去,如何选择?

目录 一、什么是显式 GC&#xff1f; &#xff08;一&#xff09; 垃圾回收的基本原理 &#xff08;二&#xff09;显式 GC 方法和行为 1. System.gc() 方法 2. 显式 GC 的行为 &#xff08;三&#xff09;显式 GC 的使用场景与风险 1. JVM 如何处理显式 GC 2. 显式 GC…

SpringMVC概述以及入门案例

目录 SpringMVC概述 为什么需要Spring MVC&#xff1f; SpringMVC入门 工作流程分析 SpringMVC概述 SpringMVC技术与Servlet技术功能等同&#xff0c;均属于Web层开发技术。SpringMVC是一种基于java实现MVC模型的轻量级Web框架。 为什么需要Spring MVC&#xff1f; 在传统J…

⭐LeetCode周赛 3468. 可行数组的数目——暴力与数学⭐

⭐LeetCode周赛 3468. 可行数组的数目——暴力与数学⭐ 示例 1&#xff1a; 输入&#xff1a;original [1,2,3,4], bounds [[1,2],[2,3],[3,4],[4,5]] 输出&#xff1a;2 解释&#xff1a; 可能的数组为&#xff1a; [1, 2, 3, 4] [2, 3, 4, 5] 示例 2&#xff1a; 输入&…

javaEE初阶————多线程进阶(2)

今天来继续带大家学习多线程进阶部分啦&#xff0c;今天是最后一期啦&#xff0c;下期带大家做一些多线程的题&#xff0c;我们就可以开始下一个环节啦&#xff1b; 1&#xff0c;JUC&#xff08;java.util.concurrent&#xff09;的常见类 1&#xff09;Callable 接口 我们之…

maven无法解析插件 org.apache.maven.plugins:maven-jar-plugin:3.4.1

解决流程 1.修改maven仓库库地址 2.删除本地的maven仓库 maven插件一直加载有问题: 无法解析插件 org.apache.maven.plugins:maven-jar-plugin:3.4.1 开始以为maven版本有问题&#xff0c;重装了maven&#xff0c;重装了idea工具。结果问题还是没解决。研究之后发现&#xf…

Android Studio右上角Gradle 的Task展示不全

Android Studio 版本如下&#xff1a;Android Studio lguana|2023.21, 发现Gradle 的Tasks阉割严重&#xff0c;如下图&#xff0c;只显示一个other 解决方法如下&#xff1a;**Setting>Experimental>勾选Configure all gradle tasks during Gradle Sync(this can make…

UDP协议 TCP协议(格式 超时重传 滑动窗口 拥塞控制...)

UDP协议 格式 UDP协议头部格式由8个字节组成&#xff0c;由4个2字节大小的字段组成。 源端口&#xff08;Source Port&#xff0c;16 位&#xff09;&#xff1a; 发送端的端口号&#xff0c;标识数据从哪个端口发出。如果不需要&#xff0c;则可以填 0。 目标端口&#xff0…

爱普生温补晶振 TG5032CFN高精度稳定时钟的典范

在科技日新月异的当下&#xff0c;众多领域对时钟信号的稳定性与精准度提出了极为严苛的要求。爱普生温补晶振TG5032CFN是一款高稳定性温度补偿晶体振荡器&#xff08;TCXO&#xff09;。该器件通过内置温度补偿电路&#xff0c;有效抑制环境温度变化对频率稳定性的影响&#x…

【网络安全工程】任务11:路由器配置与静态路由配置

目录 一、概念 二、路由器配置 三、配置静态路由CSDN 原创主页&#xff1a;不羁https://blog.csdn.net/2303_76492156?typeblog 一、概念 1、路由器的作用&#xff1a;通过路由表进行数据的转发。 2、交换机的作用&#xff1a;通过学习和识别 MAC 地址&#xff0c;依据 M…

Webservice创建

Webservice创建 服务端创建 3层架构 service注解&#xff08;commom模块&#xff09; serviceimpl&#xff08;server&#xff09; 服务端拦截器的编写 客户端拦截器 客户端调用服务端&#xff08;CXF代理&#xff09; 客户端调用服务端&#xff08;动态模式调用&a…

使用VS Code remote ssh进行远程开发的笔记

本文是在VS Code中使用 remote ssh 进行开发的笔记。 安装插件 打开VS Code&#xff0c;在扩展区找到remote相关插件&#xff0c;安装之。下图中红色框出来的是已经安装了的插件&#xff08;圆圈处即为Remote Explorer&#xff09;。 实践 连接服务器 新建连接&#xff1a…

C语言每日一练——day_3(快速上手C语言)

引言 针对初学者&#xff0c;每日练习几个题&#xff0c;快速上手C语言。第三天。&#xff08;会连续更新&#xff09; 采用在线OJ的形式 什么是在线OJ&#xff1f; 在线判题系统&#xff08;英语&#xff1a;Online Judge&#xff0c;缩写OJ&#xff09;是一种在编程竞赛中用…