React 绑定 onClick 事件不生效问题分析,原来是绑定方法二不归!初学需注意

1,641 阅读5分钟

背景

上周碰到一个小问题,有同事在系统配置查询的控制器里添加了一项配置,照样子复制了三行代码,然后直接提交了。我在 SVN 更新比对的时候,发现虽然只有三行代码,但是也是一个不同的逻辑啊,没有改全就提交了。

这让我想起以前在阮大神的网络日志时看到的一段话:

我从互联网上得到的最好的经验之一,就是永远不要复制和粘贴不是自己编写的代码。如果你一定要复制,那就照着它逐字输入,逼着自己思考,这些代码实际上是什么意思。

是的,复制代码,如果觉得很简单,不想启动环境测试的话,最好的方法是目测,然后 SVN 比对分析,看看改了什么,有没有改完整。从以往的经验来看,无论复制什么代码,只要心里感觉太简单,有所松懈,就可能有坑!

言归正传,开发的闭环,总结经验,为后续排坑做准备,近期 React 前端开发的问题。

React 绑定事件不生效问题

问题描述:一个简单的 Div ,上需要加点击事件,随便模仿写了下,发现怎么都不会触发,我是这么写的:

<div  onClick={()=> this.doAction1}>导出</div>
<div  onClick={()=> this.doAction2}>查询</div>

问题原因:绑定方式错误了,onClick 是一个属性,要么直接指向一个固定的值,要么是一段 lambda 表达式的调用代码,上面这个恰好弄了一个二不归,所以事件方法不会执行。

解决方法一:直接指定事件方法,没有参数的话

onClick={this.doAction1} 

这个事件属性执行一个方法定义,会固定传递一个 (e) 的事件参数给目标方法。

解决方法二:如果需要给调用方法传递特殊参数,就需要用匿名函数的方法指定事件属性:

onClick={(e)=>{this.doAction(e, temp.type)}} 

这里的 temp.type 是事件之外的参数,因为这个 Div 是动态生成的,目标函数需要接受具体的数据。

自定义表单样式覆盖 React 样式

问题描述:antd 的表单验证不通过的默认样式不明显,大概是这样: 在这里插入图片描述 问题分析:可能是用的前端库中的样式又问题,定位到这个错误文字的地方,找到样式名称 ant-form-item-explain-error,页面调整了下样式生效了,所以解决办法就是重写默认样式。

解决办法:重写样式,且要保证覆盖 antd 的样式,需要这样写:

:global .ant-form-item-explain  .ant-form-item-explain-error {
	width: 200px;
	color:#ff4d4f;
	margin-top:5px;
	position: relative;
}

生效后的结果: 在这里插入图片描述 另外一点,如果 Form.Item 的高度过低,出现校验信息后,表单会出现一种跳动的感觉,因为显示错误提示信息后,原始变高了,有扩张。解决办法就是调高一点 Form.Item ,流出提示信息的位置。

多个 Form 表单绑定到同一个对象的问题

问题描述:页面上有多个 Form 表单,但是 ref 属性指向了同一个 React.createRef() 对象,那么在这个对象上的操作会出现什么问题呢?

对 formRef 对象的操作,如 this.formRef.current.resetFields() /setFields 只会在页面上最后一个绑定这个对象的组件上看到操作结果。

所以,结论是,如果页面上有多部分区域需要表单信息,不能都指向同一个,需求拆分成多个不同的表单对象,彼此独立的引用。

最后的保存操作可以由最后一个 Form 触发,然后通过直接操作表单对象,获取其他表单的配置信息。

Switch 组件编辑元素显示问题

问题描述:开关组件放在表单中,初始化值没有生效。

解决办法:加上特有的 valuePropName="checked" 属性。

<Form.Item label="是否启用" name="elag" valuePropName="checked" >
  <Switch checkedChildren="是" unCheckedChildren="否"/>
</Form.Item>

如果直接用 checked 属性设置了状态,就不能操作了,下面这种尝试是不可行的:

<Switch size="small"  
  checkedChildren="是" 
  unCheckedChildren="否" 
  checked={record.flag===1} />

像这样 record.flag=1 ,显示后就是选中状态,点击切不到未选中状态,因为这个属性值已经固定了。

最后记录及个 Linux 命令

运维打包时,两次结果不一样,少了一个压缩命令:

  1. tar -zcvf xxx.tar.gz 目录名称 ,z 参数是指定压缩的。
  2. tar -cvf 不压缩。 c,create 创建压缩文件。
  3. tar -xf 解压文件名称
  4. vim 全局替换 :%s/s1/s2/g ,将字符串 s1 替换成 s2
  5. 文件夹递归拷贝:cp -r A B ,将文件夹 A 递归拷贝到文件夹 B 中
  6. grep 正则匹配文件:ls |grep "^helloworld" 匹配当前目录下以 helloworld 开头的文件名称
  7. Shell 脚本编码 cd $var ,当变量不存在时不会报错,而是切到 HOME 目录,堪称坑点。
  8. grep 路径下递归查找 grep -r “目标字符串" 目录
  9. 大文件查找 du --max-depth=1 -h 指定目录。 10.SpringBoot 启动时包路径参数 -Dloader.path 和 Java 的自身的参数 -Djava.ext.dirs 是冲突的,只能保留一个,否则无法加载目标文件夹下的包。 Shell 重定向不能有空格。
  10. SpringCloud 支持 https 证书文件生成命令:
keytool -genkeypair -alias myname -keypass MyPass -keyalg RSA -keysize 1024 -validity 3650 -keystore mycert.jks -storepass MyPass

keytool -genkeypair -alias myname -storetype PKCS12 -keypass MyPass -keyalg RSA -keysize 1024 -validity 3650 -keystore mycert.pkcs -storepass MyPass

配置:
  ssl:
    enabled: true
    key-store: file:mycert.pkcs
    key-store-type: PKCS12
	key-alias: myname
	key-store-password: mypass

还碰到一个奇怪的问题,对一个文件夹打包时,未删除 应用日志文件之前,包大小 4.2G,打包压缩后文件 1.5G 左右;删掉应用日志文件后,包只有 1.9G ,但是打包压缩文件还是 1.5 G 左右。

如果文件夹过小,300 MB ,打包压缩,只压缩了 30MB ,压缩比例很少。直观关键是文件夹太大的时候,压缩效果明显。

互联网如此便捷,我的大脑以为它不需要记命令了,每次都要搜一下上面的命令,也是挺烦恼的,海量的搜,还是自己记录下来,直接找。