从0学习React(1)

news/2024/12/21 22:28:57/

上次在写关于index.tsx的解析的文章的时候,写着写着我突然发现文章太长了,以至于我把代码的很多细节都给忽略掉,只把index.tsx文件的大致结构给写了出来。所以接下来的几篇文章,我将会把index.tsx分成很多个部分,我争取对于每个部分,都尽量的讲的通透易懂,而且生动形象。

type PropsType = {loadMore: 'more' | 'noMore' | 'loading' | undefined;   //loadMore 的值可以控制一些组件的状态[key: string]: any;
};
/*
'more':通常在分页加载数据时,表示当前页面的数据已经加载完成,可以继续加载下一页的数据
'noMore':通常在分页加载数据时,表示所有数据已经加载完毕,没有更多数据可以加载了
'loading':表示正在加载数据。通常在发起数据请求时使用,表示当前正在加载数据,可能会显示一个加载动画或进度条
undefined:表示 loadMore 属性未定义或未初始化。这种情况下,loadMore 属性没有特定的状态,可能用于初始化或重置状态
*/

上面的代码我们称之为“类型定义”。其实这是typescript的语法,我上网百度了一下,其实这个代码可以省略,但是如果你有这个代码,就会更加严谨规范。

state: PropsType = {actionSheetIsOpen: false,searchType: '0,5,6,9',   //故障中心首页存储的故障单种类execStatus: null,faultStatusMap: new Map(),faultStatusList: [],loadMore: 'more',      //控制加载更多的状态page: {                //分页信息pageSize: 10,current: 1,},// tabList: [{ title: '公共故障' }, { title: '我的上报' }],listData: [],         //现在先定义为空数组,待会儿从后端拿到故障单后,每张故障单都会放到这里userInfo: getStorageSync(TOKEN_KEY),deviceCode: '',deviceId: '',reporterId: '',realExectorId: '',loading: false,       //控制加载状态selectedButton: null, // 用于跟踪选中的按钮};

这个代码是React中的组件状态的初始化,为组件提供默认值,确保组件在第一次渲染时有一个合理的初始状态。

因为每个组件都有自己的状态,你不可能一个组件啥状态也没有吧,那组件需要有状态的话,状态的值是多少呢?组件第一次渲染的时候,必须要有状态值,不然它渲染不出来,所以这个代码就是初始化状态的。

componentDidMount() {this.getBaseDefineOption();  //获取初始数据/*eventCenter.on 方法用于监听路由的 onShow 事件。当页面显示时,回调函数会被调用,回调函数中会通过 this.$instance?.router?.params 获取当前路由的参数,并根据参数执行相应的逻辑。*/eventCenter.on(this.$instance.router!.onShow, () => {const params: any = this.$instance?.router?.params;  
console.log(JSON.stringify(params)+"params")  //params没有,证明监听不到路由参数if (params) {if (params.reporterId) {Taro.setNavigationBarTitle({title: '我的故障',});} else if (params.realExectorId) {Taro.setNavigationBarTitle({title: '我的维修',});}this.setState({deviceId: params.deviceId,deviceCode: params.deviceCode,reporterId: params.reporterId,realExectorId: params.realExectorId,},() => {this.getList();});} else {this.getList();}});}

这个是生命周期函数。

既然说到了生命周期函数,那我们来说说首次加载组件时的顺序:先执行初始化state,接着执行render(),最后执行componentDidMount()方法。我一开始不是很懂什么是首次加载组件,然后我问了一下AI,大致意思就是,比如我有一个故障中心,首次加载组件指的就是用户第一次访问故障中心页面时,组件从创建到呈现的整个过程。

所以其实故障中心可以被理解成一个大组件,或者叫容器组件。大组件通常会使用componentDidMount()方法进行数据获取,获取的数据会存储在大组件的state中,并通过将状态和回调函数作为属性传递给子组件。

对于大组件中的子组件,比如说按钮这种就是子组件。如果你点击一个按钮,执行的顺序应该是这样的:首先会执行事件处理程序,接着执行setState更新组件的状态,最后执行render重新渲染。

可以看到,你点击一个按钮和你进入故障中心其实背后的工作是不一样的,你点击按钮时不会触发初始化state和componentDidMount的,只会触发状态更新和重新渲染。

 onReachBottom() {if (this.state.loadMore == 'noMore') {return;}this.setState({loadMore: 'loading',page: {...this.state.page,current: this.state.page.current + 1,},},() => {const { execStatus,} = this.state;if (execStatus !== undefined && execStatus !== null) {this.getList({ execStatus }, true);} else {this.getList({}, false); // 不传递 execStatus 参数}});}

这个代码是典型的处理滚动加载的代码,当用户滚动到底部时触发。如果 loadMore 状态为 noMore,则直接返回不执行任何操作。否则,它会将 loadMore 状态设置为 loading,并增加 page.current 的值,然后在状态更新完成后,根据 execStatus 的值调用 getList 方法来继续加载故障单列表(如果execStatus 的值是1,就会继续加载未完成的故障单,如果execStatus 的值是2,就会继续加载已完成的故障单,如果execStatus 的值是null,就会继续加载是[0,5,6,9]的故障单)。

getList = (/*type,loadMore*/ /*type = {}, loadMore = false*/ type: { execStatus?: number | null } = {}, loadMore: boolean = false) => {this.handleLoading(true);const {searchType,deviceCode,deviceId,reporterId,realExectorId,execStatus,} = this.state;// console.log(searchType+"测试");0569// console.log(deviceCode+"测试");null// console.log(deviceId+"测试");null// console.log(reporterId+"测试");nullconsole.log(execStatus+"测试")let params: any = {...this.state.page,...type,};//console.log(JSON.stringify(params) + " 测试数据1");      {"pageSize":10,"current":1,"execStatus":2}         {"pageSize":10,"current":1}if (type && type.execStatus) {params.execStatus = type.execStatus;} else {params.statusSet = searchType;}//console.log(JSON.stringify(params) + " 测试数据2");        {"pageSize":10,"current":1,"execStatus":2}         {"pageSize":10,"current":1,"statusSet":"0,5,6,9"}if (deviceId) {params.deviceId = deviceId;}if (deviceCode) {params.deviceCode = deviceCode;}if (reporterId) {params.reporterId = reporterId;}if (realExectorId) {params.realExectorId = realExectorId;}//console.log(JSON.stringify(params) + " 测试数据3");        {"pageSize":10,"current":1,"execStatus":2}           {"pageSize":10,"current":1,"statusSet":"0,5,6,9"}getFaultCenterList(params).then((result) => {if (result?.code === SUCCESS) {if (loadMore) {this.setState({listData: [...this.state.listData, ...result.data.list],             loadMore: result.data.list.length > 0 ? 'more' : 'noMore',});} else {this.setState({listData: result.data.list,loadMore: result.data.total <= 10 ? 'noMore' : 'more',actionSheetIsOpen: false,page: { ...this.state.page, current: 1 },});}}this.handleLoading(false);}).catch(() => {this.setState({listData: [],loadMore: 'noMore',});this.handleLoading(false);});};

这个代码是获取故障单列表的代码,也是最重要的代码。

“已完成”和“未完成”这两个按钮的事件处理函数中,更新完组件状态后,就调用了这个方法获取故障单。接下来,我以“已完成”按钮为例,详细的介绍一下这个代码。

const {searchType,deviceCode,deviceId,reporterId,realExectorId,execStatus,} = this.state;

这里是解构赋值。比如说,是“已完成”按钮调用了这个getList()方法的,那么这里的解构赋值拿的就是“已完成”按钮的状态的值,比如这里就会拿this.state.execStatus=2(已完成按钮自己的状态)赋值给getList()方法的execStatus属性。

let params: any = {...this.state.page,...type,};

这个是JavaScript的语法,代码意思是:创建了一个名为 params 的对象,它通过对象展开运算符 (...) 将 this.state.page 和 type 对象的所有属性合并到 params 中。

if (type && type.execStatus) {
params.execStatus = type.execStatus;
} else {
params.statusSet = searchType;
}

这段代码检查 type 对象是否存在且 type.execStatus 是否有值。如果 type.execStatus 存在,则将其赋值给 params.execStatus;否则,将 searchType 的值赋给 params.statusSet

getFaultCenterList(params).then((result) => {if (result?.code === SUCCESS) {if (loadMore) {this.setState({listData: [...this.state.listData, ...result.data.list],             loadMore: result.data.list.length > 0 ? 'more' : 'noMore',});} else {this.setState({listData: result.data.list,loadMore: result.data.total <= 10 ? 'noMore' : 'more',actionSheetIsOpen: false,page: { ...this.state.page, current: 1 },});}}this.handleLoading(false);}).catch(() => {this.setState({listData: [],loadMore: 'noMore',});this.handleLoading(false);});};

前面不是说了将很多属性赋值到params参数吗?这个params参数是请求参数,通过请求参数从后端接口中得到数据之后,会把后端返回的数据装到“result”里。如果 loadMore 为 true,也就是需要加载更多数据,则将新获取的数据追加到现有的 listData 中;如果 loadMore 为 false,也就是不需要加载更多数据,那直接将 listData 重置为新获取的数据。

其实你看一下这段逻辑就知道了,从后端拿到list[]的数据之后,要把list[]的数据放到listData中,listData其实就是状态。其他的状态就看着来更新,返回true或者false,更新的状态也不一样。

cancel2 = async () => {this.setState({ execStatus: 2, page: {...this.state.page,current: 1,}},() => {this.getList({ execStatus: 2 }, false);});};

这个代码就是在点击“已完成”按钮时更新状态,并重新获取故障单的列表数据。

cancel1 = async () => {this.setState({ execStatus: 1, page: {...this.state.page, current: 1,} }, () => {this.getList({ execStatus: 1 }, false);});};

这个代码就是在点击“未完成”按钮时更新状态,并重新获取故障单的列表数据。

render() {const { faultStatusMap, faultStatusList, userInfo ,selectedButton}: any = this.state;const TaskStatuText = function(props) {const {status,realExectorId,realExectorName,pendingAcceptorId,pendingAcceptor,} = props.info;};const FaultCenterItem = () => {return (<View>{this.state.listData.map((item) => (<ViewclassName='container-item'key={item.id}onClick={() => this.toTaskList(item)}><View className='title'>{item.deviceName} ( {item.devicePosition} )</View><View className='des'><View>上报人/<Text className='name'>{item.reporterName}</Text></View><View><TaskStatuText info={item} /></View></View><View className='footer'><View className='time'>{item.reportTime}</View><View className='btn'><Text className='check'>查看详情</Text><View className='at-icon at-icon-chevron-right'></View></View></View></View>))}</View>);};return (<View className='two-buttons-container'><AtButtonclassName={`button ${selectedButton === 'cancel1' ? 'selected' : ''}`}onClick={this.cancel1}>未完成</AtButton><AtButtonclassName={`button ${selectedButton === 'cancel2' ? 'selected' : ''}`}onClick={this.cancel2}>已完成</AtButton></View><View className='container'><FaultCenterItem /></View></View>);}
}
export default Index;

未完待续......


http://www.ppmy.cn/news/1534048.html

相关文章

知识图谱入门——6:Cypher 查询语言高级组合用法(查询链式操作、复杂路径匹配、条件逻辑、动态模式创建,以及通过事务控制和性能优化处理大规模数据。

在熟悉 Cypher 的基本操作后&#xff0c;复杂查询场景中的高级用法可以帮助你充分利用 Neo4j 图数据库的强大功能。这些组合用法涉及查询链式操作、复杂路径匹配、条件逻辑、动态模式创建&#xff0c;以及通过事务控制和性能优化处理大规模数据。 文章目录 1. 使用 WITH 管道式…

Qt C++设计模式->责任链模式

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许多个对象有机会处理请求&#xff0c;而不需要明确指定哪个对象处理。通过将这些对象连成一条链&#xff0c;请求沿着链传递&#xff0c;直到有对象处理它为止。该模式…

长期提供APX515/B原装二手APX525/B音频分析仪

Audio Precision APx515 是一款针对生产测试而优化的高性能音频分析仪。它因其速度、性能、自动化和易用性而成为一流的仪器。它具有卓越的性能&#xff0c;具有 –106 dB 的典型 THDN、1M 点 FFT 和 192k 数字 I/O&#xff0c;以及所有 APx 系列音频分析仪的一键式自动化和易用…

【Linux】Docker下载与使用-nginx

目录 一、Docker介绍 二、Docker结构 三、下载Daocker 1. 在linux上下载docker&#xff0c;执行以下命令即可&#xff1a; 2. 开启docker 3. 执行以下操作并进行使用 四、在Docker上安装nginx 一、Docker介绍 Docker&#xff1a;是给予Go语言实现的开源项…

【Ubuntu】使用阿里云apt源来更新apt源

1.前言 我在京东云买了一个云服务器&#xff0c;但是我第一次使用apt的时候&#xff0c;发现遇到了下面这些情况 后面听老师讲&#xff0c;还需要执行下面这个 但是我再次使用apt下载软件的时候&#xff0c;还是出现了下面这个情况 后面问了老师才知道是apt源的问题&#x…

安全点的应用场景及其原理详解

引言 在Java虚拟机&#xff08;JVM&#xff09;运行的过程中&#xff0c;有些时刻&#xff0c;系统需要暂停所有正在运行的线程&#xff0c;以执行某些全局操作或确保数据的一致性。这些暂停线程的时刻被称为**“安全点”**&#xff08;Safepoint&#xff09;。尽管安全点最广…

使用微服务Spring Cloud集成Kafka实现异步通信

在微服务架构中&#xff0c;使用Spring Cloud集成Apache Kafka来实现异步通信是一种常见且高效的做法。Kafka作为一个分布式流处理平台&#xff0c;能够处理高吞吐量的数据&#xff0c;非常适合用于微服务之间的消息传递。 微服务之间的通信方式包括同步通信和异步通信。 1&a…

CentOS常用命令收集

系统相关 重置root密码 1. 通过GRUB菜单重置 重启系统进入GRUB菜单&#xff0c;按e键编辑启动参数。找到以linux16开头的行&#xff0c;更改ro为 rw init/sysroot/bin/sh按Ctrl X启动系统进入后执行以下命令&#xff1a;chroot /sysroot passwd root touch /.autorelabel完…