React:类组件(中)

devtools/2025/3/15 2:07:23/

dangerouslySetInnerHTML

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

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

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

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

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

class App extends Component{a=100myref = 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.propsreturn (<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.propsreturn (<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.propsreturn (<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.propsreturn (<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.ppmy.cn/devtools/167173.html

相关文章

计算机二级web易错点(2)-选择题

HTML&#xff08;HyperText Markup Language&#xff09;即超文本标记语言&#xff0c;是专门为 Internet 文档设计的标记语言。 HTML 具有跨平台性&#xff0c;只要在安装了浏览器的设备上&#xff0c;无论设备使用的是什么操作系统&#xff0c;都可以运行 HTML 文档。 在 H…

DeepSeek-R1深度解读

deepseek提出了一种通过强化学习&#xff08;RL&#xff09;激励大语言模型&#xff08;LLMs&#xff09;推理能力的方法&#xff0c;个人认为最让人兴奋的点是&#xff1a;通过RL发现了一个叫“Aha Moment”的现象&#xff0c;这个时刻发生在模型的中间版本中。在这个阶段&…

QoS质量配置

他们祝你挺拔&#xff0c;再挺拔一点&#xff1b;我只祝你&#xff0c;永远年少&#xff0c;永远一骑当先. 1. QoS的概念 QoS(服务质量)是指一个网络能够利用各种各样的基础技术向选定的网络通信提供更好 的服务的能力。这些基础技术包括&#xff1a;帧中继&#xff08;FrameR…

文件跨国传输如何加速?UDP改造机制解析

引言&#xff1a;被忽视的"数字物流"危机 全球数字化协作背景下&#xff0c;企业跨国文件传输效率正成为新的竞争力指标。据Gartner统计&#xff0c;跨国企业每年因文件传输延迟导致的协作成本损失高达营收的1.2%。以某新能源车企为例&#xff0c;其中美团队同步10G…

HarmonyOS开发 - 电商App实例二( 网络请求http)

在HarmonyOS中进行网络请求开发时&#xff0c;可以使用"ohos.net.http"库&#xff0c;该库支持常见的HTTP方法&#xff0c;能够满足大多数应用或元服务的需求。 接下来&#xff0c;我们将通过http库&#xff0c;对其进行二次封装&#xff0c;并向后台发送请求&#x…

Docker 基础命令 - 以 Nginx 实战总结

前言 操作镜像&#xff1a;Nginx操作环境&#xff1a;CentOS 7 64Docker版本&#xff1a;1.13.1 1. 在宿主机安装 Docker 软件 可以博主写的另外一篇博客&#xff0c;地址&#xff1a;CentOS 7 64 安装 Docker 2.Docker 基本命令 2.1 拉取 Nginx 镜像 # 搜索镜像 docker s…

leetcode日记(96)有序链表转换二叉搜索树

这么多天以来学到最多的一道题。 这题真的是把链表和树的知识综合起来了&#xff0c;需要融会贯通。 有两种做法&#xff0c;很遗憾自己写的时候一种都没想出来&#xff0c;只想到将链表先转换为数组这种简单方法…… 第一个知识点是快慢指针&#xff0c;这种做法在找出长链…

Android的tablayout+ViewPager2,缓存的数量有容量上限吗?

Android的tablayoutViewPager2&#xff0c;ViewPager2里面有6个fragment&#xff0c;不断切换不同的tab&#xff0c;那么ViewPager2会缓存6个fragment吗&#xff0c;还是缓存的数量有容量上限&#xff1f; DeepSeek R1 思考 61 秒 思考过程 好的&#xff0c;我现在要回答用户…