Mock平台-08开发:项目管理(四)编辑功能和Component抽离

【Mock平台】为系列测试开发教程,从0到1编码带你一步步使用Spring Boot 和 Antd React框架完成搭建一个测试工具平台,希望作为一个实战项目对各位的测试开发学习之路有帮助,大奇一个专注测试技术干货原创与分享的家伙。

本篇重点:继续基于项目增加所有用到的Form和Modal两个组件做一些深化,实现项目管理的编辑功能,并将代码进行合并优化,提取第一个自定义的component组件。

1.项目编辑功能

要实现项目编辑对话框,需要拿到对应行的项目详细信息,可以通过在点击行按钮时候将整行信息传入,即之前table配置列信息时候操作列 render: (text, record) => [Link]()中的record数据,但如果你返回的列表不不是所有字段,那就需要拿到行对应ID,通过查询接口拿到详细信息保存到一个定义好的变量中。

我们这里项目信息比较简单,所以采用前者,定义一个详细信息变量、编辑点击事件,并注意需要将之前定义在外部projectColumns挪到Project(...)主体内,让其正确调用内部新定义的方法。

const Project = () => {// 迁移列到内部,并添加editAction方法透传recordconst projectColumns = [{dataIndex:"id",title:"编号",},...省略...{dataIndex:"option",title:"操作",render: (text, record) => (<Space><a onClick={()=>editAction(record)}>编辑</a><a>删除</a></Space>),},]  // 定义项目编辑操作,并动态赋值到新的详细项目变量const [projectInfo, setProjectInfo] = useState({});const editAction = (record) => {setProjectInfo(record);}
}

在实现编辑对话框表单之前需要了解如何初始化数据,从 Form 组件官方API可以查看到其initialValues 可以绑定初始信息,值与name直接匹配,也可以在Form.Item 中initialValue独立绑定,好处是可以做些计算、转换再初始化。

参考上篇添加逻辑,拷贝一份Modal+Form修改其文案,并添加一个ID项(禁止编辑状态),再做个整体数据绑定操作,其中先不做保存修改操作,一份去了重的代码参考如下:

  // 控制显示编辑项目对话框表单const [projectEditVisible, setProjectEditVisible] = useState(false);... 省略部分...<Modalid="p_edit"title="项目修改"visible={projectEditVisible}destroyOnClose="true"onCancel={()=>setProjectEditVisible(false)}onOk={() => {// 暂时不实现接口操作,先看交互是否满足}}><Form initialValues={projectInfo}><Form.Item name='id' label='编号'><Input disabled></Input></Form.Item><Form.Itemname='name'label='名称'rules={[{required: true,message: '项目名称为必填项!',},]}><Input placeholder="请输入项目名称"></Input></Form.Item><Form.Item name='owner' label='负责人'><Input placeholder="项目相负责人"></Input></Form.Item><Form.Item name="desc" label="更多信息"><TextArea/></Form.Item></Form></Modal>

几个关键的代码增加后,运行看下效果,并进行测试,编辑的对话框表单的弹出和显示,数据初始化都正常,但是反填的数据只是第一次选中行的数据,即时已经设置了 destroyOnClose关闭对话框销毁子元素也无效。
在这里插入图片描述

经查找官方组件API下边有这样的说明:

你不能用控件的 value 或 defaultValue 等属性来设置表单域的值,默认值可以用 Form 里的 initialValues 来设置。注意 initialValues 不能被 setState 动态更新,你需要用 setFieldsValue 来更新。

也就是要想动态的替换是需要使用 setFieldsValue来实现,在此交互场景下initialValues/initialValue 更适合新增时候一些默认数据绑定。改动给出diff代码块如下。

const [formEditProject] = Form.useForm();
- //const [projectInfo, setProjectInfo] = useState({});const editAction = (record) => {
- // setProjectInfo(record);
+ formEditProject.setFieldsValue(record);setProjectEditVisible(true);
}<Form
+ form={formEditProject}
- // initialValues={projectInfo}
>

具体改动点涉及:

  • 定义useForm Hook 并绑定编辑Form;
  • 点击编辑按钮无需再赋予projectInfo,直接调用表单setFieldsValue动态赋值。

由于在之实现后端项目保存的时候其增加/修改都是一个接口,唯一的增量是编辑带原始ID,所以保存接口代码参考增加的onOK,请求参数里增加个ID字段,其他对应改成编辑modal绑定的变量。

onOk={() => {formEditProject.validateFields().then(async (values) => {const data = {id: values.id,name: values.name,owner: values.owner,desc: values.desc,type: 'public',operator: '大奇'}const resp = await saveProduct(data);if (resp.success) {formEditProject.resetFields(); setProjectEditVisible(false);reloadProjectList();}}).catch((info) => {console.log('修改项目信息失败', info);});
}}

五处改动点分别为formEditProjectid: values.idformEditProject.resetFields();setProjectEditVisible(false);console.log('修改项目信息失败', info);

带上这部分代码,重新编译做个测试,看下效果。
在这里插入图片描述

至此项目管理的增加和修改的数据交互操作,通过最基本Modal+Form组件已经实现了。类似这类字段较少的数据保存交互都可以通过这种方式实现了。

2.编写Component

随着应用的发展,会需要在多个页面分享 UI 元素 (或在一个页面使用多次),或是在一个tsx逻辑代码太多,这种情况下就可以把这部分抽成 component 。

我们来编写一个 UpsertProject component,再将增加和修改合并,这样就将大幅优化代码。

按照之前Template里的例子,新建 src/pages/Project/components/UpsertProject.tsx 文件:

import React, { useState } from 'react';/* 抽离出来的组件,用于优化页面代码 */
const UpsertProject = (props) => {return (<></>)
}export default UpsertProject;

2.1 编码index.jsx

为了保留历史参考代码,增改组件的提取将全部定义新变量,源代码中将注释掉,如果是本地测试开发的话完全可以直接删掉。这里再想一个问题,在之前实现的新增和修改Modal+Form其实将近90%代码重复,所以我们可以将其合并,不同的部分通过条件判断进行逻辑操作和动态赋值。因此我们在 src/pages/Project/index.jsx 有如下新定义:

  // Components 需要留在上级的变量(重新定义原有的将注释掉)const [upsertVisible, setUpsertVisible] = useState(false); //控制抽离的组件显隐const [upsertAction, setUpsertAction] = useState('ADD'); // 标记组件的动作默认增加const [upsertDetail, setUpsertDetail] = useState({}); // 编辑动作下选择行详细信息

对应的也需要修改组件引用、涉及到增加和修改方法逻辑:

  • 原有p_add和p_edit可以全部删掉,使用新的组件
  • 新的组件里会用一些变量和方法直接透传
  • 修改addAction添加按钮方法逻辑,标记动作为ADD并设置状态显示
  • 修改editAction表操作列,标记动作为EDIT,赋值编辑行详细信息,同样设置状态显示
import UpsertProject from "@/pages/Project/components/UpsertProject";const addAction = () => {// setProjectVisible(true);setUpsertAction("ADD");setUpsertVisible(true);}const editAction = (record) => {// setProjectInfo(record);// formEditProject.setFieldsValue(record);// setProjectEditVisible(true);setUpsertDetail(record);setUpsertAction('EDIT');setUpsertVisible(true);}return (<><Button...省略...>项目添加</Button>{/*原来的增加和修改Modal都可以删掉了, 引入抽离的组件*/}<UpsertProjectupsertAction={upsertAction}upsertVisible={upsertVisible}setUpsertVisible={setUpsertVisible}upsertDetail={upsertDetail}reloadProjectList={reloadProjectList}/><Table...省略.../></>
)

如果对比原index.jsx文件,代码量的减少直观让可阅读和逻辑性更好。

2.2 组件UpsertProject

接下来就要真正实现 UpsertProject 组件 内部逻辑了,基本上将p_edit的代码拷贝过来,然后额外进行页面渲染初始化逻辑判断,以及动态判断动作赋值和组件的显示隐藏,详细的解释请参考如下完整代码。其中有两个新知识点说明移步到下文useEffect和hidden学习。

import React, { useEffect, useState } from "react";
import { Form, Input, Modal } from "antd";
const { TextArea } = Input;import { saveProduct } from "@/pages/Project/service";/* 抽离出来的组件,用于优化页面代码 */
const UpsertProject = (props) => {const [form] = Form.useForm();// 副作用钩子,给定一个参数,当props内容有变化是执行此HookuseEffect(()=>{if(props.upsertAction==='EDIT'){form.setFieldsValue(props.upsertDetail);} else {form.resetFields();}},[props]) //return (<Modaltitle={props.upsertAction==='ADD'?'增加项目':'修改项目'} // 动态判断标题visible={props.upsertVisible}destroyOnCloseonCancel={()=>props.setUpsertVisible(false)}onOk={() => {form.validateFields().then(async (values) => {const data = {id: props.upsertAction==='ADD'? undefined: values.id, // 根据增加还是修改给定id值name: values.name,owner: values.owner,desc: values.desc,type: 'public',operator: '大奇'}const resp = await saveProduct(data);if (resp.success) {form.resetFields(); // 表单清除历史props.setUpsertVisible(false);props.reloadProjectList();}}).catch((info) => {console.log('保存项目信息失败', info);});}}><Form form={form}>{/*通过hidden属性决定是否隐藏此项目,在新增操作时候隐藏*/}<Form.Item hidden={props.upsertAction==='ADD'} name='id' label='编号'><Input disabled></Input></Form.Item><Form.Itemname='name'label='名称'rules={[{required: true,message: '项目名称为必填项!',},]}><Input placeholder="请输入项目名称"></Input></Form.Item><Form.Item name='owner' label='负责人'><Input placeholder="项目相负责人"></Input></Form.Item><Form.Item name="desc" label="更多信息"><TextArea/></Form.Item></Form></Modal>)
}export default UpsertProject;

2.3 集成测试

完成所有代码编写后,做个集成集成测试,强调一下笔者在边开发边总结文档的过程是一点点测试过来,非一次编码后才进行测试的,这里受于文章的排版才这样做的。

测试1:对话框显隐和赋值

  • Case1: 验证对话框弹出和关闭正常
  • Case2: 项目添加表单为空
  • Case3: 项目编辑值正确初始化
    在这里插入图片描述

测试2:添加和修改保存操作

  • Case1: 验证项目新增保存成功
  • Case2: 验证项目修改保存成功
  • Case3: 保存成功后关闭对话框不刷新项目Table
    在这里插入图片描述

3. useEffect和hidden

对于上自定义组件代码涉及到几个新出现的知识点,分别简单讲解下。

3.1钩子useEffect

为了实现项目增改组件数据的初始化,引入useEffect钩子, 可看作是React中 componentDidMountcomponentDidUpdatecomponentWillUnmount 几个声明周期的组合,这里主要的目的当透传的值有变化的时候,触发这个周期Hook,实现根据upsertAction判断是新增还是编辑操作,如果编辑使其表单动态初始化值,否则保持表单为空。

https://zh-hans.reactjs.org/docs/hooks-reference.html#useeffect

useEffect传递两个参数,第一个参数是逻辑处理函数,第二个参数是一个数组,其中

  • 如果参数二存放变量,当数组存放变量发生改变时,第一个参数,逻辑处理函数将会被执行;
  • 如果参数二不传,浏览器会无线循环执行逻辑处理函数;
  • 如果参数二传空数组[],相当于挂在完成后执行一次。

3.2组件隐藏Hidden

在React没有像Vue那种v-if的语法糖,在处理组件根据条件是否渲染的时候,比较正规的处理方式是写个函数定义组件,例如如下用法:显示那种按钮和文案根据给定值动态返回。

const showButton= (state) => {if (state==='OPEN'){return <Button type='link'>CLOSE</Button>} else {return <Button>OPEN</Button>}
}<div>{showButton("OPEN")}</div>

但对于本篇中的仅是根据某种条件隐藏编号表单项即可,经验证有一种简单的用法,即大部分官方组件有Hidden的属性,所以我们值需要为这个隐藏字段赋予逻辑值true或false就能控制是否显示。比如代码中根据操作动作来确定此项目是否显示。

 <Form.Item hidden={props.upsertAction==='ADD'} name='id' label='编号'><Input disabled></Input>
</Form.Item>

至此通过详细的讲解和演示实践,完成了项目管理的增加和编辑需求开发,学习开发过程成中,是否遇到什么问题呢?如果需要帮助和交流的可以加我,我尽量在时间允许的情况下回复你,一同探讨学习、动手实战,一起踏实成长。

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

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

相关文章

MetaMask Mobile +Chrome DevTools 调试Web3应用教程

注&#xff1a;本教程来源网络&#xff0c;根据项目做的整理 写好了WEB3应用&#xff0c;在本地调试用得好好的&#xff0c;但是用钱包软件访问就报莫名的错&#xff0c;但是又不知道是什么原因&#xff0c;排查的过程非常浪费时间 。 因此在本地同一局域网进行调试就非常有必要…

mybatis-plus--配置-(sql)日志输出-自动填充-分页-多数据源-逻辑删除

写在前面&#xff1a; 本文主要介绍mybatis-plus的配置&#xff0c;以后在有的时候在补充。欢迎交流。 文章目录 日志输出自动填充分页全局字段配置多数据源 日志输出 调试的时候需要看执行的sql&#xff0c;这时候就很需要日志来记录查看了。 mybatis-plus的日志配置在yml…

​8th参考文献:[8]许少辉.乡村振兴战略下传统村落文化旅游设计[M]北京:中国建筑出版传媒,2022.

​&#xff18;th参考文献&#xff1a;&#xff3b;&#xff18;&#xff3d;许少辉&#xff0e;乡村振兴战略下传统村落文化旅游设计&#xff3b;&#xff2d;&#xff3d;北京&#xff1a;中国建筑出版传媒&#xff0c;&#xff12;&#xff10;&#xff12;&#xff12;&…

RK3588平台开发系列讲解(AI 篇)RKNN C API 详细说明

文章目录 一、API 硬件平台支持说明二、API 函数介绍2.1、rknn_init2.2、rknn_destroy2.3、rknn_query2.4、rknn_inputs_set2.5、rknn_run2.6、rknn_outputs_get2.7、rknn_outputs_release沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要讲解 RKNN C API 详细…

springboot 项目日志配置文件详解

spring boot 项目指定 日志配置文件 在Spring Boot项目中&#xff0c;可以通过在application.properties或application.yml文件中指定日志配置文件来配置日志。 1. 使用application.properties文件&#xff1a; 在application.properties中&#xff0c;您可以使用以下属性来…

【ARM】Day4 点亮LED灯

1. 思维导图 2. 自己编写代码实现三盏灯点亮 .text .global _start _start: /**********LED1&#xff0c;LED2,LED3点灯:PE10,PF10,PE8**************/ RCC_INIT:使能GPIOE组/GPIOF组控制器,通过RXCC_MP_AHB4ENSETR设置第[5:4]位写1,地址:0x50000A28[5:4]1ldr r0,0x50000A28 …

01_Redis单线程与多线程

01——Redis单线程与多线程 一、Redis是单线程还是多线程 在谈Redis的单线程或多线程时&#xff0c;需要根据版本来区分。 在redis 3.x之前&#xff0c;redis是单线程的从redis 4.x开始&#xff0c;redis引入多线程。处理客户端请求时&#xff0c;使用单线程&#xff1b;在异…

B-树和B+树的区别

B-树和B树的区别 一、B-tree数据存储 在下图中 P 代表的是指针&#xff0c;指向的是下一个磁盘块。在第一个节点中的 16、24 就是代表我们的 key 值是什么。date 就是这个 key 值对应的这一行记录是什么。 假设寻找 key 为 33 的这条记录&#xff0c;33 在 16 和 34 中间&am…

QT TLS initialization failed问题(已解决) QT基础入门【网络编程】openssl

问题: qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed 这个问题的出现主要是使用了https请求:HTTPS ≈ HTTP + SSL,即有了加密层的HTTP 所以Qt 组件库需要OpenSSL dll 文件支持HTTPS 解决: 1.加入以下两行代码获取QT是否支持opensll以…

如何在出差期间远程访问企业ERP系统?内网穿透解决您的难题!

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 概述 ERP系统对于企业来说重要性不言而喻&#xff0c;不管是财务、生产、销售还是采购&#xff0c;都需要用到ERP系统来协助。…

SharkTeam:Worldcoin运营数据及业务安全分析

Worldcoin的白皮书中声明&#xff0c;Worldcoin旨在构建一个连接全球人类的新型数字经济系统&#xff0c;由OpenAI创始人Sam Altman于2020年发起。通过区块链技术在Web3世界中实现更加公平、开放和包容的经济体系&#xff0c;并将所有权赋予每个人。并且希望让全世界每一个人都…

Web3和去中心化:互联网的下一个演化阶段

文章目录 Web3和去中心化的定义Web3&#xff1a;去中心化&#xff1a; 为什么Web3和去中心化如此重要&#xff1f;数据隐私和安全&#xff1a;去中心化的创新&#xff1a;去除中间商&#xff1a; Web3和去中心化的应用领域去中心化金融&#xff08;DeFi&#xff09;&#xff1a…

Linux驱动开发之点亮三盏小灯

头文件 #ifndef __HEAD_H__ #define __HEAD_H__//LED1和LED3的硬件地址 #define PHY_LED1_MODER 0x50006000 #define PHY_LED1_ODR 0x50006014 #define PHY_LED1_RCC 0x50000A28 //LED2的硬件地址 #define PHY_LED2_MODER 0x50007000 #define PHY_LED2_ODR 0x50007014 #define…

机器学习深度学习——NLP实战(情感分析模型——数据集)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——BERT&#xff08;来自transformer的双向编码器表示&#xff09; &#x1f4da;订阅专栏&#xff1a;机器…

Unity如何控制声音大小(包括静音功能)

一&#xff1a;UGUI制作 1. 首先在【层级】下面创建UI里面的Slider组件。设置好它对应的宽度和高度。 2.调整Slider滑动条的填充颜色。一般声音颜色我黄色&#xff0c;所以我们也调成黄色。 我们尝试滑动Slider里面的value。 a.滑动前。 b.滑动一半。 c.滑动完。 从以上滑动va…

DeFINE:用于神经序列建模的深度分解输入令牌嵌入

一、说明 DeFINE&#xff0c;是华盛顿大学和艾伦人工智能开发的自然语言处理工具&#xff0c;可以处理的范围是&#xff1a;NLP、语言模型、LM、神经机器翻译、NMT、变压器、变压器-XL等&#xff1b;本文对token-bedding进行生成。 借助DeFINE&#xff0c;Transformer-XL可以在…

汽车级36V、4A同步降压转换器MAX20404AFOD/VY、MAX20404AFOC/VY、MAX20404AFOA/VY开关稳压器

MAX20404是小型同步降压转换器&#xff0c;集成了高端和低端开关。这些IC均设计为可在3V到36V的宽输入电压范围内提供高达4A的电流。电压质量可以通过观察PGOOD信号来监测。该器件可以在99%的占空比下运行&#xff0c;非常适合汽车和工业应用。 MAX20404提供可编程输出电压或5…

Debian查询硬件状态

很早以前写过一个查询树霉派硬件状态的文章&#xff0c;用是Python写的一个小程序。里面用到了vcgencmd这个测温度的内部命令&#xff0c;但这个命令在debian里面没有&#xff0c;debian里只有lm_sensors的外部命令&#xff0c;需要安装&#xff1a;apt-get install lm_sensors…

python:tkinter + cef 模仿 mdict 界面

cefpython3 其上游是C开发的CEF&#xff08;基于webkit、V8&#xff09;&#xff0c; CEF 即 (Chromium Embedder Framework)&#xff0c; 是基于Google Chromium项目的开源 Web browser控件(WebView)。 可查看github文档&#xff1a;cefpython api pip install cefpython3 c…

TCP编程流程(补充)

目录 1、listen&#xff1a; 2、listen、tcp三次握手 3、 发送缓冲区和接收缓冲区&#xff1a; 4、tcp编程启用多线程 1、listen&#xff1a; 执行listen会创建一个监听队列 listen(sockfd,5) 2、listen、tcp三次握手 三次握手 3、 发送缓冲区和接收缓冲区&#xff1a;…