React笔记(四)类组件(2)

一、类组件的props属性

组件中的数据,除了组件内部的状态使用state之外,状态也可以来自组件的外部,外部的状态使用类组件实例上另外一个属性来表示props

1、基本的使用

在components下创建UserInfo组件

import React, { Component } from 'react'
import '../assets/css/userinfo.scss'
export default class UserInfo extends Component {render() {return (<div className='info-box'><h3>{this.props.title}</h3> <div>姓名:{this.props.name}</div><div>年龄:{this.props.age}</div><div>性别:{this.props.gender===1?'男':'女'}</div><div>爱好:{this.props.hobby.join("、")}</div> </div>)}
}

在App.jsx中引用组件,并且传递数据到组件的内部

import React, { Component } from 'react'
import UserInfo from './components/UserInfo'
export default class App extends Component {constructor(){super()this.state={users:[{title:'教师信息',name:'翟吉喆',age:38,gender:1,hobby:['爱打游戏','爱读书']},{title:'学生信息',name:'张资源',age:24,gender:1,hobby:['爱写js','爱UI设计']},
​{title:'班主任信息',name:'王玉倩',age:28,gender:0,hobby:['爱唱歌','爱学习']}]}}render() {const {users}=this.statereturn (<>{users.map((item,index)=><UserInfo key={index} {...item}/>)}</>)}
}

2、props的默认值

React的props的默认值设置有两种方法

  • 类名.defaultProps={key:value}

export default class UserInfo extends React.Component{}
UserInfo.defaultProps={title:'暂无标题',name:'暂无名称',age:0,gender:1,hobby:['暂无兴趣'],birthday:new Date(),avatar:'http://old.woniuxy.com/page/img/head_picture/0.jpg'
}
  • static defaultProps={key:value}(推荐)

export default class UserInfo extends React.Component{static defaultProps={title:'暂无标题',name:'暂无名称',age:0,gender:1,hobby:['暂无兴趣'],birthday:new Date(),avatar:'http://old.woniuxy.com/page/img/head_picture/0.jpg'}
}

3、props验证器[了解]

配置React验证器的步骤

  • 下载prop-types依赖包

yarn add prop-types
  • 引入prop-types

import PropTypes from 'prop-types'
  • 配置验证器

    配置验证器也有两种方法

    • 类名.propTypes={key:value}

    export default class UserInfo extends React.Component{}
    UserInfo.propTypes={age:PropTypes.number.isRequired
    }
    • static propTypes={key:value}

    export default class UserInfo extends React.Component{static propTypes={age:PropTypes.number.isRequired}
    }

    4、props的只读性

    总结:

    • 通过props传递进来的基本类型,组件内部不能直接更改,如果更改就会报如下错误

    • 通过props传递进来的引用数据,不能直接更改,如果更改会报如下错误

    • 通过props传递进来的引用数据类型,可以更改引用数据类型的属性

二、React插槽

在React中实现插槽需要我们自己来实现 主要用到props.children

三、组件的生命周期

生命周期指的就是从组件的加载初始化-数据的改变-组件的卸载阶段。描述的就是组件从创建到死亡的阶段,react的生命周期中提供了很多个生命周期钩子函数来方便我们操作。

react的生命周期主要分为以下的几个步骤:

  1. 挂载阶段:组件数据的初始化,及组件数据的渲染

  2. 运行阶段:这个节点是最长的阶段,主要用户对组件的数据进行修改,状态改变以及重绘

  3. 卸载阶段:这个阶段也是销毁阶段,组件运行完成后,或者从页面中移除,那么组件就应该被销毁。这个阶段我们可以执行一些资源的回收,性能优化的代码可以在这里设计。

组件的生命周期流程图

React lifecycle methods diagram

1、组件挂载阶段

组件的挂载阶段也是组件创建-数据初始化-数据渲染的过程。接下来通过代码来演示执行的流程。

1.1 constructor构造器执行的阶段

构造执行那就意味着组件正在被创建,并且数据也可以在这里初始化。

通常,在 React 中,构造函数仅用于以下两种情况:

  • 通过给 this.state 赋值对象来初始化内部 state

  • 为事件处理函数绑定实例

如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。

import React, { Component } from 'react'export default class LifeCycle extends Component {constructor(props){super(props)this.state={count:0}this.increment=this.increment.bind(this)console.log('====执行constructor组件正在创建和初始化');}increment(){this.setState({count:this.state.count+1})}render() {console.log("====调用render方法开始执行数据渲染");return (<div><h1>React生命周期全过程</h1>{this.state.count}<button onClick={this.increment}>+</button></div>)}
}

输出的结果为:

====执行constructor组件正在创建和初始化
====调用render方法开始执行数据渲染

先执行constructor构造器将数据初始化,其中props和state的数据就会被加载。接着执行render函数来渲染。

1.2 componentDidMount函数执行

界面渲染完毕(DOM挂载完毕)的一个通知,类似于vue组件中的created,我们可以在这个生命周期做

很多事情。

  • 获取DOM节点

  • 发送请求获取后台数据

  • 设置定时器、延时器等等

  • 绑定全局事件,例如document的点击事件等等

 async componentDidMount(){console.log("===componentDidMount==");const {data:{movies}}=await          axios.get('https://www.fastmock.site/mock/4441a79ad5f884f83b784cf4c588bdb6/movies/getHotMovies')}

2、组件更新阶段

每当组件的props或者state变化之后,都会导致组件的更新,我们可以使用钩子函数在组件更新之前或者之后做一些逻辑操作。

2.1、创建shouldComponentUpdate钩子函数来拦截数据修改

shouldComponentUpdate(){return false;
}

定义在重新render之前被调用,可以返回一个布尔值来决定一个组件是否更新, 如果返回false,那么前面的流程都不会被触发。这个方法默认的返回值都是true。

这里我们再来完成一个功能就是将外部传递进来的数据赋给内部变量data,当点击按钮的时候每次增加1

import React, { Component } from 'react'
import axios from 'axios'
export default class LifeCycle extends Component {constructor(props){super(props)this.state={title:props.title}}changeTitle=()=>{this.setState({title:"计数器演示"})}render() {console.log("====调用render方法开始执行数据渲染");return (<div><h1>{this.state.title}</h1><button onClick={this.changeTitle}>更改标题</button></div>)}shouldComponentUpdate(nextProps,nextState){console.log(this.state.title+"---------->"+nextState.title);return true}
}

但是从控制台的显示结果来看,每次点击之后都是上次的数据,如果要想得到更改后的数据我们可以使用如下参数来解决这个问题

参数:nextProps代表更改后的props值;nextState代表更改过后的state值。我们可以获取到这个数据进行判断

shouldComponentUpdate(nextProps,nextState){console.log(this.state.data+"---->"+nextState.data);return true;
}
控制台显
示效果如下所示

2.3 componentDidUpdate钩子函数来执行通知。

componentDidUpdate(){console.log("数据修改成功");
}

3、组件卸载阶段

componentWillUnmount,在组件被卸载和销毁之前调用的方法,可以在这里做一些清理的工作。我们要完成组件的卸载,那需要创建两个组件,在父组件中引入子组件,当条件为true的时候就加载组件,条件为false的时候就卸载组件。

export default class ParentCom extends Component {state = {isShow:true}changePanel = ()=>{this.setState({isShow:false})}render() {return (<div><h1>ParentComponent</h1>{this.state.isShow && <ChildCom/>}{/* {this.state.isShow && } */}<button type="button" onClick={this.changePanel}>点击切换</button></div>)}
}

花括号中嵌入逻辑与 (&&) 运算符。它可以很方便地进行元素的条件渲染,&&是我们的短路运算符,一旦this.state.boo的值为false,那后面<ChildCom>的组件就不会渲染。

当点击按钮我们动态修改isShow的值,然后判断条件false组件就卸载。

export default class ChildCom extends Component {render() {return (<div><h2>ChildComponent</h2></div>)}componentWillUnmount(){console.log("ChildCom组件正在卸载");}
}

一旦组件卸载那就执行componentWillUnmount钩子函数完成调用,那我们可以完成清理工作。

执行结果为:

ChildCom组件正在卸载

4、资源清理

在componentWillUnmount钩子函数中我们可以执行一些资源清理工作。比如事件解绑,定时器清除等等工作。

先在ChildCom子组件里面定义事件和定时器等等代码。

componentDidMount(){this.timer = setInterval(function(){console.log("定时器执行");},1000);
}

在componentDidMount组件里面设置一个定时器,我们在父组件里面将组件卸载。但是定时器依然在执行所以,所以在组件卸载的时候我们需要清楚定时器。

componentWillUnmount(){console.log("ChildCom组件正在卸载");clearInterval(this.timer);
}

执行完组件的卸载,那定时器就被清除。

四、兄弟组件通信

  • 状态提升

  • 事件总线

  • 发布订阅模式

1、状态提升

React中的状态提升概括来讲,就是将多个组件需要共享的状态提升到他们最近的父组件上,再在父组件上改变这个状态,然后通过props分发给子组件

1)新建Child.jsx组件

import React, { Component } from 'react'
import './son.css'
export default class Son extends Component {render() {return (<div className='sonbox'><h2>儿子</h2><button onClick={()=>{this.props.callback('通过父亲给妹妹1万元')}}>发送</button></div>)}
}

2)新建Parent.jsx组件

import React, { Component } from 'react'
import './parent.css'
import Son from './Son'
import Daughter from './Daughter'
export default class Parent extends Component {state={fromChildMsg:''}render() {return (<div className='box'><Son className="c1" callback={(msg)=>{//接收儿子给的信息console.log('接受儿子的信息',msg);//然后将这个信息更新到状态中this.setState(()=>{return {fromChildMsg:msg}},()=>{console.log(this.state.fromChildMsg)})}}></Son><Daughter className="c2" cmsg={this.state.fromChildMsg}></Daughter></div>)}
}

3)新建Daughter.jsx

import React, { Component } from 'react'
import './daughter.css'
export default class Daughter extends Component {render() {return (<div className='daughterbox'><h2>女儿</h2><div>{this.props.cmsg}</div></div>)}
}
2、事件总线方式

兄弟之间传递参数我们有多种方案,本节中我们就给大家带来。基于事件总线的方式来设计

EventBus 又称为事件总线。在Vue中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的灾难,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。

但在React中没有EventBus的概念,可以通过 node events模块进行模拟,在React中可以依赖一个使用较多的库 events 来完成对应的操作。

1)安装events

yarn add events

2)创建事件中心

新建一个文件MyEventListener.js文件用于作为事件中心。

import { EventEmitter } from 'events';
export default new EventEmitter();

我们只需要引入EventEmitter对象,将这个对象实例化过后返回出去,调用的时候执行对应的API就可以完成事件的绑定和通知

events常用的API:

  • 创建EventEmitter对象:eventBus对象;

  • 发出事件:eventBus.emit("事件名称", 参数列表);

  • 监听事件:eventBus.addListener("事件名称", 监听函数);

  • 移除事件:eventBus.removeListener("事件名称", 监听函数);

3)监听事件

import React, { Component } from 'react'
import MyEventListener from './MyEventListener'export default class Borther1 extends Component {state={className:'web05'}//在组件完毕后就监听dataChange事件componentDidMount(){MyEventListener.addListener("dataChange",this.changeData);}//当组件卸载的时候就移除事件监听componentWillUnmount(){MyEventListener.removeListener('dataChange',this.changeData);}changeData=(params)=>{this.setState({className:params});}render() {return (<div><h2>兄弟1</h2><p>数据为:{this.state.className}</p></div>)}
}

在生命周期函数里面绑定事件监听和移除事件监听,当事件中心里面加入了dataChange事件,当前组件就能监听到,接着执行我们绑定的changeData。

4)发送事件

在Brother2组件里面我们添加一个按钮,往事件中心发出一个dataChange事件,并将值传递给调用者

import React, { Component } from 'react'
import MyEventListener from './MyEventListener'export default class Borther2 extends Component {changeData=()=>{MyEventListener.emit("dataChange","web08");}render() {return (<div><h2>兄弟2</h2><button onClick={this.changeData}>修改数据</button></div>)}
}

其中emit这个API就可以完成事件发送。这样就可以完成兄弟组件之间的参数传递,当然事件总线这种设计模式可以应用在任何组件之间。实现跨组件通信。

3、发布与订阅模式

1)定义订阅者

//创建一个observer.js文件
const observer={list:[],subscribe(callback){this.list.push(callback)},dispatch(data){this.list.forEach(item => {item(data)});}
}
export default observer

2)定义子组件用来发送数据

import React, { Component } from 'react'
import './son.css'
import observer from '../observer'
export default class Son extends Component {render() {return (<div className='sonbox'><h2>儿子</h2><button onClick={()=>{observer.dispatch('兄弟姐妹们,我给每个人200元') }}>发送</button></div>)}
}

3)定义子组件用来接受数据

import React, { Component } from 'react'
import './daughter.css'
import observer from '../observer'
export default class Daughter extends Component {state={fromMsg:''}componentDidMount(){observer.subscribe(data=>{this.setState(()=>{return{fromMsg:data}})})}render() {return (<div className='daughterbox'><h2>女儿</h2><div>{this.state.fromMsg}</div></div>)}
}

五、表单处理

表单的处理:从表单中获取内容

vue中如果获取表单的内容:v-model:是一个双向绑定的指令,react不是一个双向绑定的

1、受控表单

1.1、什么是受控组件

在 HTML 中,表单元素(如<input><textarea><select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。

我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

1.2、受控组件的使用步骤
  • 在state中添加一个状态name

state={name:''
}
  • 我们在input标签里面定义了value属性,这个属性就是文本框的值,将state对象里面的name绑定到文本框里面

  <input value={this.state.name}/>
  • onChange是必须要的,这个函数相当于绑定了一个事件,当数据发生变化的时候,可以执行你绑定的函数handlerName

 <input value={this.state.name} onChange={this.handleName}/>
  • 定义bindName函数,将文本框的值动态绑定赋值给state对象

handleName=(e)=>{this.setState({name:e.target.value})
}

参数e代表事件对象,可以通过e来获取到target目标对象,通过value值来获取文本框的值。

2、非受控表单

有时使用受控组件会很麻烦,因为你需要为数据变化的每种方式都编写事件处理函数,并通过一个 React 组件传递所有的输入 state。当你将之前的代码库转换为 React 或将 React 应用程序与非 React 库集成时,这可能会令人厌烦。在这些情况下,你可能希望使用非受控组件, 这是实现输入表单的另一种方式。

在大多数情况下,我们推荐使用 受控组件 来处理表单数据。在一个受控组件中,表单数据是由 React 组件来管理的。另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理。

要编写一个非受控组件,有两种方式

2.1、第1种方式

使用步骤

  • 在表单元素中添加ref属性

<form onSubmit={this.register}><div><label>用户名:</label><input type="text" placeholder='请输入用户名' ref={input=>this.nameEle=input}/></div><div><input type="submit" value="提交"></input></div>
</form>
  • 在通过this.nameEle.value来获取到当前节点的值

register=(e)=>{console.log(this.nameEle.value);e.preventDefault();
}
2.2 、第2种方式

使用步骤

  • 调用React.createRef()方法创建一个ref对象

constructor(){super();this.username=React.createRef();
}
  • 将创建好的ref对象添加到文本框中

 <form onSubmit={this.register}><div><label>用户名:</label><input type="text" placeholder='请输入用户名' ref={this.username}/></div><div><input type="submit" value="提交"></input></div>
</form>
  • 通过ref对象获取到文本框的值

 register=(e)=>{console.log(this.username.current.value);e.preventDefault();}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详解 ElasticSearch Kibana 配置部署

默认安装部署所在机器允许外网 SSH工具 Putty 链接&#xff1a;https://pan.baidu.com/s/1b6gumtsjL_L64rEsOdhd4A 提取码&#xff1a;lxs9 Winscp 链接&#xff1a;https://pan.baidu.com/s/1tD8_2knvv0EJ5OYvXP6VTg 提取码&#xff1a;lxs9 WinSCP安装直接下一步到完成…

在Windows10上编译grpc工程,得到protoc.exe和grpc_cpp_plugin.exe

grpc是google于2015年发布的一款跨进程、跨语言、开源的RPC(远程过程调用)技术。使用C/S模式&#xff0c;在客户端、服务端共享一个protobuf二进制数据。在点对点通信、微服务、跨语言通信等领域应用很广&#xff0c;下面介绍grpc在windows10上编译&#xff0c;这里以编译grpc …

aac音频格式怎么转mp3?这种转换方法很简单

AAC格式和MP3格式都是数字音频格式&#xff0c;但它们使用不同的音频压缩算法。虽然AAC格式在音质和文件大小方面表现出色&#xff0c;但是不是所有的设备都支持该格式。相比之下&#xff0c;MP3格式的兼容性更好&#xff0c;可以在各种设备和操作系统上播放&#xff0c;因此转…

7.(Python数模)消防站的选址问题

Python解决消防站的选址问题 原文参考该博文 问题描述 源代码 import pulp # 导入 pulp 库# 主程序 def main():# 问题建模&#xff1a;"""决策变量&#xff1a;x(j) 0, 不选择第 j 个消防站x(j) 1, 选择第 j 个消防站, j1,8目标函数&#xff1a;min fx …

Linux 基础篇

很长时间&#xff0c;因为一些事情&#xff0c;没有更新我的文章这让我很惭愧&#xff0c;于是我将打算在今天更新下自己的文章&#xff0c;我发现一些事情&#xff0c;计算机并不是很难学到可以工作的水平&#xff0c;关键在于是否可以坚持下来&#xff0c;有很多时候我并不是…

人工智能论文通用创新点(一)——ACMIX 卷积与注意力融合、GCnet(全局特征融合)、Coordinate_attention、SPD(可替换下采样)

1.ACMIX 卷积与注意力融合 论文地址:https://arxiv.org/pdf/2111.14556.pdf 为了实现卷积与注意力的融合,我们让特征图经过两个路径,一个路径经过卷积,另外一个路径经过Transformer,但是,现在有一个问题,卷积路径比较快,Transformer比较慢。因此,我们让Q,K,V通过1*1的…

安装kali虚拟机镜像的坑

1.0 安装虚拟机镜像成功之后&#xff0c;只有光标&#xff0c;没有界面 在VMware上安装kali linux环境时&#xff0c;根据提示操作完成后&#xff0c;开启虚拟机&#xff0c;屏幕黑屏&#xff0c;左上角有一个光标在闪&#xff0c;一直开不了机。 出现问题的原因&#xff0c;…

说说TIME_WAIT和CLOSE_WAIT区别

分析&回答 TCP协议规定&#xff0c;对于已经建立的连接&#xff0c;网络双方要进行四次握手才能成功断开连接&#xff0c;如果缺少了其中某个步骤&#xff0c;将会使连接处于假死状态&#xff0c;连接本身占用的资源不会被释放。网络服务器程序要同时管理大量连接&#xf…

云备份——实用类工具实现

一&#xff0c;文件实用类设计实现 不管是客户端还是服务端&#xff0c;文件的传输备份都涉及到文件的读写&#xff0c;包括数据管理信息的持久化也是如此&#xff0c;因此首先设计封装文件操作类&#xff0c;这个类封装完毕之后&#xff0c;则在任意模块中对文件进行操作时都将…

【python爬虫案例】用python爬豆瓣音乐TOP250排行榜!

文章目录 一、爬虫对象-豆瓣音乐TOP250二、python爬虫代码讲解三、同步视频四、获取完整源码 一、爬虫对象-豆瓣音乐TOP250 您好&#xff0c;我是 马哥python说 &#xff0c;一名10年程序猿。 今天我们分享一期python爬虫案例讲解。爬取对象是&#xff0c;豆瓣音乐TOP250排行…

基于aarch64分析kernel源码 四:printk 内核打印

一、参考 Message logging with printk — The Linux Kernel documentation 如何获得正确的printk格式占位符 — The Linux Kernel documentation 使用printk记录消息 — The Linux Kernel documentation printk 内核打印 – 人人都懂物联网 (getiot.tech) 内核printk原理…

五金轴尺寸机器视觉测量软硬件方案--康耐德智能

检测内容&#xff1a; 五金轴尺寸机器视觉测量 检测要求&#xff1a; 精度0.015mm&#xff0c;速度180~240个/分钟 视觉可行性分析&#xff1a; 对样品进行了光学实验&#xff0c;并进行图像处理&#xff0c;原则上可以使用机器视觉系统进行测试测量。 结果&#xff1a; 对…

Python小知识 - 1. Python装饰器(decorator)

Python装饰器&#xff08;decorator&#xff09; Python装饰器是一个很有用的功能&#xff0c;它可以让我们在不修改原有代码的情况下&#xff0c;为已有的函数或类添加额外的功能。 常见的使用场景有&#xff1a; a. 函数缓存&#xff1a;对于一些计算量较大的函数&#xff0c…

Samba服务器

目录 一、什么是Samba&#xff1f; 二、Samba进程 三、Samba主要功能 四、Samba工作流程 五、Samba安全级别 六、Sam主配置文件/etc/samba/smb.conf 七、Samba服务配置案例 一、什么是Samba&#xff1f; Samba可以让linux计算机和windows计算机之间实现文件和打印机资源共享的一…

Homebrew下载安装及使用教程

Homebrew是什么&#xff1f; 简单来说&#xff0c;就是用命令行的形式去管理mac系统的包或软件。 安装命令 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"国内请使用镜像源进行下载 执行上述命令后会要求输入…

【设计模式】装饰者模式

5.3 装饰者模式 5.3.1 概述 我们先来看一个快餐店的例子。 快餐店有炒面、炒饭这些快餐&#xff0c;可以额外附加鸡蛋、火腿、培根这些配菜&#xff0c;当然加配菜需要额外加钱&#xff0c;每个配菜的价钱通常不太一样&#xff0c;那么计算总价就会显得比较麻烦。 使用继承的…

vue3 ref reactive响应式数据 赋值的问题

文章目录 vue3 ref reactive响应式数据 赋值的问题场景1:将响应式数据赋值请求后的数据错误示范&#xff1a;直接赋值正确写法 场景2&#xff1a;响应式数据解构之后失去响应式原因分析解决办法 toRefs/toRef方法创建ref引用对象 vue3 ref reactive响应式数据 赋值的问题 doing…

[PyTorch][chapter 53][Auto Encoder 实战]

前言&#xff1a; 结合手写数字识别的例子&#xff0c;实现以下AutoEncoder ae.py: 实现autoEncoder 网络 main.py: 加载手写数字数据集&#xff0c;以及训练&#xff0c;验证&#xff0c;测试网络。 左图&#xff1a;原图像 右图&#xff1a;重构图像 ----main----- 每轮训…

bazel远程缓存(Remote Cache)

原理 您可以将服务器设置为构建输出&#xff08;即这些操作输出&#xff09;的远程缓存。这些输出由输出文件名列表及其内容的哈希值组成。借助远程缓存&#xff0c;您可以重复使用其他用户的 build 中的构建输出&#xff0c;而不是在本地构建每个新输出。 增量构建极大的提升…

开启EMQX的SSL模式及SSL证书生成流程

生成证书 首先&#xff1a;需要安装Openssl 以下是openssl命令 生成CA证书 1.openssl genrsa -out rootCA.key 2048 2.openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -subj "/CCN/STShandong/Ljinan/Oyunding/OUplatform/CNrootCA" -out ro…