react的setState中为什么不能用++?
背景:
在使用react的过程中产生了一些困惑,handleClick函数的功能是记录点击次数,handleClick函数被绑定到按钮中,每点击一次将通过this.state.counter将累计的点击次数显示在页面上

困惑:
为什么不能直接写prevState++而是要写成prevState.counter + 1
在React中,setState 方法用于更新组件的状态。当使用函数形式的 setState 时,React 提供了一个函数,该函数接收当前的状态 (prevState) 和当前的属性 (props) 作为参数,并返回一个新状态的对象。这是因为状态的更新应该是不可变的,这意味着不应直接修改现有的状态对象。
# 为什么不能直接写 prevState++
 
-  
不可变性:在React中,状态的更新应该遵循不可变原则。直接修改
prevState(如prevState.count++)会违反这一原则,因为prevState是只读的。 -  
返回值问题:
prevState.count++会立即递增prevState.count的值,并返回递增后的值。然而,在setState中,你需要返回一个新对象来更新状态,而不是修改prevState。 -  
状态更新逻辑:
setState的目的是更新组件的状态,而不是修改现有状态。使用prevState.count++试图在原有状态上进行修改,这与setState的设计目的不符。 
正确的做法
正确的做法是返回一个包含更新后状态的新对象。这样可以确保状态的更新是不可变的,并且能够正确地更新组件的状态。以下是正确的示例:
this.setState((prevState) => ({count: prevState.count + 1
}));
 
React框架源码级解释
为了更好地理解这一点,我们可以看一下React框架中关于 setState 的简化源码示例。请注意,实际的React源码非常复杂,这里提供的代码是为了说明目的而简化过的。
React组件类的简化实现
class ReactComponent {constructor(props) {this.props = props;this.state = {};this._pendingState = null;}setState(partialState, callback) {if (typeof partialState === 'function') {// 当setState接受一个函数时const currentState = this.state;this._pendingState = Object.assign({}, this._pendingState || {}, partialState(currentState));} else {// 当setState接受一个对象时this._pendingState = Object.assign({}, this._pendingState || {}, partialState);}// 触发更新this.scheduleUpdate();}scheduleUpdate() {// 这里模拟React调度更新的逻辑// 在实际的React中,这会触发一系列复杂的更新队列处理// 这里我们只是简单地调用forceUpdatethis.forceUpdate();}forceUpdate(callback) {// 这里模拟React更新组件的逻辑// 在实际的React中,这将触发整个渲染流程this.updateState();if (callback) {callback();}}updateState() {if (this._pendingState) {// 合并pending state到当前状态this.state = Object.assign({}, this.state, this._pendingState);this._pendingState = null;// 重新渲染组件this.render();}}render() {console.log('Rendering component with state:', this.state);// 这里是组件渲染的逻辑// 实际应用中,这会生成虚拟DOM并更新真实DOM}
}
 
使用简化版React组件
现在我们可以创建一个简单的计数器组件,并使用上面的简化版 setState 方法:
const Counter = (props) => {class CounterComponent extends ReactComponent {constructor(props) {super(props);this.state = { count: 0 };this.handleClick = this.handleClick.bind(this);}handleClick() {this.setState((prevState) => ({count: prevState.count + 1}));}render() {console.log('Rendering counter with state:', this.state);return (<div><p>计数: {this.state.count}</p><button onClick={this.handleClick}>增加计数</button></div>);}}return <CounterComponent />;
};// 创建并渲染组件
const counter = new Counter();
counter.render();
 
为什么不能使用 prevState++
 
在上述简化版的实现中,如果你尝试使用 prevState.count++,将会出现问题:
handleClick() {this.setState((prevState) => {const newCount = prevState.count++; // 这里的prevState.count++是不正确的return {count: newCount};});
}
 
问题在于:
prevState是只读的,不应该直接修改。prevState.count++返回的是递增后的值,但这并没有被正确地返回给setState。
总结
在React中,你应该始终使用返回新状态对象的方式来更新状态。这确保了状态更新的不可变性,并且与React的设计理念一致。使用 prevState.count + 1 而不是 prevState.count++ 是正确的做法,因为它遵循了状态更新的最佳实践。
讲讲JS的Object.assign函数?
Object.assign() 是 JavaScript 中的一个方法,用于将所有可枚举的自有属性(own enumerable properties)的值从一个或多个源对象(source objects)复制到目标对象(target object)。如果目标对象中的键与源对象中的键相同,则源对象中的值会覆盖目标对象中的值。
基本语法
Object.assign(target, ...sources)
 
target: 目标对象,所有源对象的属性都会被复制到这个对象上。...sources: 一个或多个源对象,这些对象的属性会被复制到目标对象上。
示例
下面是一个简单的例子来说明 Object.assign() 的用法:
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };const result = Object.assign(target, source1, source2);console.log(result); // 输出: { a: 1, b: 2, c: 3 }
 
在这个例子中,target 对象首先有一个属性 a,然后我们将 source1 和 source2 中的属性合并到 target 上。最终的结果是一个包含了三个属性的对象 { a: 1, b: 2, c: 3 }。
注意事项
-  
浅拷贝:
Object.assign()只会复制对象的第一层属性,即它执行的是浅拷贝(shallow copy),不会复制对象内部的嵌套对象。const obj1 = { a: 1, b: { x: 10 } }; const obj2 = { b: { y: 20 }, c: 3 };const mergedObj = Object.assign({}, obj1, obj2); console.log(mergedObj); // 输出: { a: 1, b: { y: 20 }, c: 3 }// 修改 obj2 中的嵌套对象会影响 mergedObj obj2.b.y = 200; console.log(mergedObj.b.y); // 输出: 200 -  
不可枚举属性:
Object.assign()不会复制不可枚举的属性(non-enumerable properties)。 -  
覆盖顺序:如果有相同的属性名,那么后面的源对象的属性值会覆盖前面的源对象的属性值。
 -  
目标对象的改变:
Object.assign()默认会修改第一个参数(目标对象),除非你传入一个全新的空对象作为目标对象。 
应用场景
在React或其他JavaScript框架中,Object.assign() 经常用来合并对象,特别是在需要基于现有状态创建新状态的情况下。例如,在React中更新组件状态时,通常会这样做:
this.setState(prevState => ({count: Object.assign({}, prevState, { count: prevState.count + 1 })
}));
 
在这个例子中,prevState 是当前的状态对象,通过 Object.assign 将其与一个新的对象 { count: prevState.count + 1 } 合并,从而创建出一个新的状态对象,其中 count 属性的值被递增了1。
这种方法确保了状态更新是不可变的,这对于保持React应用程序的可预测性和易于调试非常重要。
是的,您提到的 newarr = [...arr1, ...arr2] 是使用数组的扩展运算符(spread operator ...)来合并两个数组。这种做法类似于使用 Object.assign() 来合并对象,但在数组中使用的是扩展运算符而不是 Object.assign()。
数组的扩展运算符
扩展运算符 ... 用于将数组或迭代对象展开为独立的元素列表。它可以用于数组、字符串或任何可迭代对象。当用于数组时,扩展运算符可以将一个数组的元素提取出来,就像它们是单独的元素一样。
示例
假设我们有两个数组 arr1 和 arr2,我们可以使用扩展运算符将它们合并为一个新的数组:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];const newarr = [...arr1, ...arr2];
console.log(newarr); // 输出: [1, 2, 3, 4, 5, 6]
 
在这个例子中,[...arr1, ...arr2] 将 arr1 和 arr2 的元素提取出来,并将它们合并到一个新的数组 newarr 中。
对比 Object.assign()
 
对比来看,Object.assign() 用于合并对象。它的工作原理与扩展运算符类似,但针对的是对象而不是数组。
示例
假设我们有两个对象 obj1 和 obj2,我们可以使用 Object.assign() 将它们合并为一个新的对象:
const obj1 = { a: 1 };
const obj2 = { b: 2 };const result = Object.assign({}, obj1, obj2);
console.log(result); // 输出: { a: 1, b: 2 }
 
在这个例子中,Object.assign({}, obj1, obj2) 将 obj1 和 obj2 的属性合并到一个新的对象中。这里使用了一个空对象 {} 作为目标对象,以避免修改原始对象。
总结
- 扩展运算符:用于数组和其他可迭代对象,可以将多个数组合并成一个新数组。
 Object.assign():用于对象,可以将多个对象的属性合并到一个新对象中。
这两种方法都是JavaScript中非常实用的功能,用于创建新数组或对象,同时保持数据的不可变性。在React中,我们通常使用 Object.assign() 来创建新的状态对象,而在其他场景下,扩展运算符则用于数组的操作。
您提到的 Object.assign() 是否复制引用的问题是一个很好的点。确实,Object.assign() 在处理对象时只进行浅拷贝,这意味着如果源对象中包含嵌套的对象,那么这些嵌套对象的引用会被复制到目标对象中,而不是创建新的对象。
浅拷贝 vs. 深拷贝
- 浅拷贝:只复制对象的第一层属性,对于嵌套的对象,只是复制其引用。
 - 深拷贝:复制对象的所有层级,包括嵌套的对象,创建全新的对象。
 
示例
让我们通过一个具体的例子来说明这一点:
const obj1 = { a: 1, b: { x: 10 } };
const obj2 = { b: { y: 20 }, c: 3 };const result = Object.assign({}, obj1, obj2);
console.log(result); // 输出: { a: 1, b: { y: 20 }, c: 3 }// 修改 obj2 中的嵌套对象会影响 result
obj2.b.y = 200;
console.log(result.b.y); // 输出: 200
 
在这个例子中,result 对象包含了来自 obj1 和 obj2 的属性。当 obj2.b.y 的值被修改时,result.b.y 的值也随之改变,因为 result.b 和 obj2.b 是同一个对象的引用。
如何避免这个问题
如果您需要完全独立的对象副本,可以使用深拷贝技术。在JavaScript中,有多种方法可以实现深拷贝,例如使用JSON序列化和反序列化,或者使用第三方库如 lodash 的 _.cloneDeep 方法。
使用JSON序列化和反序列化
const deepClone = (obj) => JSON.parse(JSON.stringify(obj));const obj1 = { a: 1, b: { x: 10 } };
const obj2 = { b: { y: 20 }, c: 3 };const result = Object.assign(deepClone(obj1), obj2);
console.log(result); // 输出: { a: 1, b: { y: 20 }, c: 3 }// 修改 obj2 中的嵌套对象不会影响 result
obj2.b.y = 200;
console.log(result.b.y); // 输出: 20
 
使用 lodash 的 _.cloneDeep
 
import _ from 'lodash';const obj1 = { a: 1, b: { x: 10 } };
const obj2 = { b: { y: 20 }, c: 3 };const result = Object.assign(_.cloneDeep(obj1), obj2);
console.log(result); // 输出: { a: 1, b: { y: 20 }, c: 3 }// 修改 obj2 中的嵌套对象不会影响 result
obj2.b.y = 200;
console.log(result.b.y); // 输出: 20
 
总结
Object.assign()在处理对象时只进行浅拷贝,即对于嵌套的对象,只是复制引用。- 如果需要完全独立的对象副本,可以使用深拷贝技术。
 - 使用JSON序列化和反序列化或 
lodash的_.cloneDeep方法可以实现深拷贝。 
希望这些解释和示例有助于澄清 Object.assign() 的行为以及如何处理对象的拷贝问题。如果您还有其他疑问或需要进一步的帮助,请随时提问。
是的,您的理解是正确的。当我们使用 Object.assign() 来合并 obj1 和 obj2 时,obj2 中的属性会覆盖 obj1 中相同名称的属性。对于嵌套对象,obj2 中的嵌套对象会覆盖 obj1 中相同名称的嵌套对象。
在您给出的例子中,obj1 和 obj2 分别如下:
const obj1 = { a: 1, b: { x: 10 }, c: 5 };
const obj2 = { b: { y: 20 }, c: 3 };
 
当我们使用 Object.assign() 来合并这两个对象时,obj2 中的属性会覆盖 obj1 中的相应属性。因此,b 和 c 属性会被 obj2 中的值覆盖。结果将是:
const result = Object.assign(obj1, obj2);
console.log(result); // 输出: { a: 1, b: { y: 20 }, c: 3 }
 
这里发生了以下几件事:
obj1中的a属性没有被覆盖,因此保留原样。obj1中的b属性被obj2中的b属性覆盖。这意味着obj1中的{ x: 10 }被替换为obj2中的{ y: 20 }。obj1中的c属性被obj2中的c属性覆盖,5被替换为3。
最终的 result 对象将是 { a: 1, b: { y: 20 }, c: 3 }。
请注意,由于 Object.assign() 默认修改第一个参数(在这里是 obj1),所以在这种情况下,obj1 也被修改成了 { a: 1, b: { y: 20 }, c: 3 }。如果您希望创建一个新的对象而不是修改 obj1,可以使用一个空对象作为目标对象,如下所示:
const result = Object.assign({}, obj1, obj2);
console.log(result); // 输出: { a: 1, b: { y: 20 }, c: 3 }
 
这样,obj1 保持不变,而 result 是一个新的对象。
当使用 Object.assign() 合并对象时,对于嵌套的对象,Object.assign() 只会复制引用,而不是创建新的对象。这意味着如果原对象和合并后的对象都包含对同一个嵌套对象的引用,那么对其中一个对象的修改会影响到另一个对象。
让我们通过一个具体的例子来说明这一点:
const obj1 = { a: 1, b: { x: 10 }, c: 5 };
const obj2 = { b: { y: 20 }, c: 3 };const result = Object.assign(obj1, obj2);
console.log(result); // 输出: { a: 1, b: { y: 20 }, c: 3 }// 修改 obj2 中的嵌套对象会影响 result
obj2.b.z = 30;
console.log(result.b); // 输出: { y: 20, z: 30 }
 
在这个例子中,result 和 obj2 都包含了对同一个嵌套对象的引用。当我们修改 obj2.b 添加一个新属性 z 时,result.b 也反映了这个变化,因为它们都指向同一个对象。
示例代码
下面是完整的示例代码:
const obj1 = { a: 1, b: { x: 10 }, c: 5 };
const obj2 = { b: { y: 20 }, c: 3 };const result = Object.assign(obj1, obj2);
console.log(result); // 输出: { a: 1, b: { y: 20 }, c: 3 }// 修改 obj2 中的嵌套对象会影响 result
obj2.b.z = 30;
console.log(result.b); // 输出: { y: 20, z: 30 }
 
总结
Object.assign()在处理嵌套对象时只复制引用,而不是创建新的对象。- 因此,如果两个对象包含对同一个嵌套对象的引用,那么对其中一个对象的修改会影响到另一个对象。
 - 如果需要完全独立的对象副本,可以使用深拷贝技术,例如使用JSON序列化和反序列化或使用 
lodash的_.cloneDeep方法。 
相关文章:
react的setState中为什么不能用++?
背景: 在使用react的过程中产生了一些困惑,handleClick函数的功能是记录点击次数,handleClick函数被绑定到按钮中,每点击一次将通过this.state.counter将累计的点击次数显示在页面上 困惑: 为什么不能直接写prevStat…...
2.2算法的时间复杂度与空间复杂度——经典OJ
本博客的OJ标题均已插入超链接,点击可直接跳转~ 一、消失的数字 1、题目描述 数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗? 2、题目分析 (1)numsS…...
【CentOS 】DHCP 更改为静态 IP 地址并且遇到无法联网
文章目录 引言解决方式标题1. **编辑网络配置文件**:标题2. **确保配置文件包含以下内容**:特别注意 标题3. **重启网络服务**:标题4. **检查配置是否生效**:标题5. **测试网络连接**:标题6. **检查路由表**࿱…...
Linux 操作系统 --- 信号
序言 在本篇内容中,将为大家介绍在操作系统中的一个重要的机制 — 信号。大家可能感到疑惑,好像我在使用 Linux 的过程中并没有接触过信号,这是啥呀?其实我们经常遇到过,当我们运行的进程当进程尝试访问非法内存地址时…...
黑马前端——days09_css
案例 1 页面框架文件 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compati…...
【Python爬虫】技术深度探索与实践
目录 引言 第一部分:Python爬虫基础 1.1 网络基础 1.2 Python爬虫基本流程 第二部分:进阶技术 2.1 动态网页抓取 2.2 异步编程与并发 2.3 反爬虫机制与应对 第三部分:实践案例 第四部分:法律与道德考量 第五部分&#x…...
智启万象|挖掘广告变现潜力,保障支付安全便捷
谷歌致力于为开发者提供 先进的广告变现与支付解决方案 一起回顾 2024 Google 开发者大会 了解如何利用谷歌最新工具和功能 提高变现收入,优化用户体验,保障交易安全 让变现更上一层楼 广告检查器是谷歌 AdMob 平台最新推出的高级测试工具,开…...
函数递归,匿名、内置行数,模块和包,开发规范
一、递归与二分法 一)递归 1、递归调用的定义 递归调用:在调用一个函数的过程中,直接或间接地调用了函数本身 2、递归分为两类:直接与间接 #直接 def func():print(from func)func()func() # 间接 def foo():print(from foo)bar…...
Springboot3 整合swagger
一、pom.xml <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-api</artifactId><version>2.1.0</version></dependency> 二、application.yml # SpringDoc配置 # springdoc:swa…...
查看同一网段内所有设备的ip
使用命令提示符(CMD)进行扫描 查看本机IP地址 首先通过 ipconfig /all 命令查看本机的IP地址,确定你的网段,例如 192.168.1.。 Ping网段内每个IP地址 接着使用循环命令: for /L %i IN (1,1,254) DO ping -w 1 -n …...
Spark MLlib 特征工程(上)
文章目录 Spark MLlib 特征工程(上)特征工程预处理 Encoding:StringIndexer特征构建:VectorAssembler特征选择:ChiSqSelector归一化:MinMaxScaler模型训练总结Spark MLlib 特征工程(上) 前面我们一起构建了一个简单的线性回归模型,来预测美国爱荷华州的房价。从模型效果来…...
《SPSS零基础入门教程》学习笔记——03.变量的统计描述
文章目录 3.1 连续变量(1)集中趋势(2)离散趋势(3)分布特征 3.2 分类变量(1)单个分类变量(2)多个分类变量 3.1 连续变量 (1)集中趋势 …...
2024年杭州市网络与信息安全管理员(网络安全管理员)职业技能竞赛的通知
2024年杭州市网络与信息安全管理员(网络安全管理员)职业技能竞赛的通知 一、组织机构 本次竞赛由杭州市总工会牵头,杭州市人力资源和社会保障局联合主办,杭州市萧山区总工会承办,浙江省北大信息技术高等研究院协办。…...
SpringBoot参数校验详解
前言 在web开发时,对于请求参数,一般上都需要进行参数合法性校验的,原先的写法时一个个字段一个个去判断,这种方式太不通用了,Hibernate Validator 是 Bean Validation 规范的参考实现,用于在 Java 应用中…...
安全基础学习-SHA-1(Secure Hash Algorithm 1)算法
SHA-1(Secure Hash Algorithm 1)是一种密码学哈希函数,用于将任意长度的输入数据(消息)转换成一个固定长度的输出(哈希值或摘要),长度为160位(20字节)。SHA-1的主要用途包括数据完整性验证、数字签名、密码存储等。 1、SHA-1 的特性 定长输出:无论输入数据长度是多…...
leetcode350. 两个数组的交集 II,哈希表
leetcode350. 两个数组的交集 II 给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可…...
基于YOLOv8的缺陷检测任务模型训练
文章目录 一、引言二、环境说明三、缺陷检测任务模型训练详解3.1 PCB数据集3.1.1 数据集简介3.1.2 数据集下载3.1.3 构建yolo格式的数据集 3.2 基于ultralytics训练YOLOv83.2.1 安装依赖包3.2.2 ultralytics的训练规范说明3.2.3 创建训练配置文件3.2.4 下载预训练模型3.2.5 训练…...
【upload]-ini-[SUCTF 2019]CheckIn-笔记
上传图片木马文件后看到,检查的文件内容,包含<? 一句话木马提示 检查的文件格式 用如下图片木马,加上GIF89a绕过图片和<?检查 GIF89a <script languagephp>eval($_POST[cmd])</script> .user.ini实际上就是一个可以由用…...
uniapp条件编译使用教学(#ifdef、#ifndef)
#ifdef //仅在xxx平台使用#ifndef //除了在xxx平台使用#endif // 结束 标识平台APP-PLUSAPPMP微信小程序/支付宝小程序/百度小程序/头条小程序/QQ小程序MP-WEIXIN微信小程序MP-ALIPAY支付宝小程序MP-BAIDU百度小程序MP-TOUTIAO头条小程序MP-QQQQ小程序H5H5APP-PLUS-NVUEApp nv…...
NXP i.MX8系列平台开发讲解 - 4.1.2 GNSS 篇(二) - 卫星导航定位原理
专栏文章目录传送门:返回专栏目录 Hi, 我是你们的老朋友,主要专注于嵌入式软件开发,有兴趣不要忘记点击关注【码思途远】 文章目录 关注星号公众号,不容错过精彩 作者:HywelStar Hi, 我是你们的老朋友HywelStar, 根…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
