狗蛋开发日记

前言:

  因为公司数据不能暴露,本文中的数据都是临时创建出来的,可能有问题,不要全看。并且这里都是用react的代码

持续更新中...


日常代码中的问题和技巧

问题:

问题1:请求接口报400(请求数据有问题)

场景:发送请求后报400,然而传过去的数据没有错
原因:传入进去的是JSON字符串,发现请求中的数据“{”,“}”,“[”,“]”没有转码
在这里插入图片描述
解决方法:把这串JSON字符串转码后再发送请求

export default (data) => data.replace(/\[/g, '%5B').replace(/\]/g, '%5D').replace(/\{/g, '%7B').replace(/\}/g, '%7D');

问题2:在input框内连续输入数据会感觉很卡,一直快速输入数据显示需要时间

场景:写项目时发现像input框这种可以连续输入的组件,连续输入,每次点击键盘时间很短的时候,input框内有延迟显示。但是没有绑定任何属性的input框没有这种情况。
原因:我是用react中的useState绑定了input的value,并且把对应的set方法绑定到onChange上。由于set方法是异步的,并且会重新渲染组件,如果键盘输入太快,就会触发很多次set方法,导致异步的set方法会出现问题,进而导致页面渲染input框内的数据卡死。
解决方法1:如果其他地方的操作不会影响这里的值。
不要绑定value,就把onChange里面使用的set方法加一个节流,不过时间设置小一点,要不然会出现用户修改完,都点击了提交这种操作,onchange里面的set函数还没有触发
解决方法2:如果其他地方的操作会影响这里的值。
就在“解决方法1”的基础上,可以用默认值(defaultValue)控制这个input的值。
我理解defaultValue是会在input框第一次渲染的时候展示的值,如果value有值,就会展示value的值。
可以先销毁这个input,再把input重新渲染

import React, { useState, useEffect } from 'react';
import { throttle } from 'lodash';

export default () => {
	const [data, setData] = useState();
	const [show, setShow] = useState(true);
	
	useEffect(() => {
		if(!show) {
			setShow(true);
			setData('改变了');
		}
	},[show]);
	
	return (
		{show && 
			<input
				defaultValue={data}
				onChange={throttle(setData, 50)}
			/>
		}
		<button
			onClick={() => {
				setShow(false);
			}}
		>点击</button>
	);
}

这里用show这个参数把input销毁了,然后重新创建了,这里只是随手写的代码,项目里面要根据具体情况写
解决方法3:把绑定的数据改成同步的数据。
可以在组件“export default”上面let的数据,不过这种要用useEffect模拟销毁生命周期的时候重置,否则切换路由回到这个页面,会导致页面数据还是修改后的数据。
还可以使用useRef.current存一个同步的数据。
这个会导致一个问题,就是页面不会重新加载,导致input框没有重新渲染里面的数据

问题3:表格需要渲染大量数据,导致页面进入时有几秒卡顿

场景:因为需求导致进入时渲染两个表格数据,加在一起最少有800条,虽然用了懒加载,但是进入时还是有3秒以上的卡顿
原因:大量数据渲染表格自然会卡(具体为什么表格渲染会卡,还要去看看,如果您知道,希望您可以评论一下,万分感谢)
解决方法:最后是改了需求,并且控制台这里把表格做了分页。一开始是因为没有想到其他办法展示这里的数据给用户操作,最后借鉴其他项目渲染的方式把这里的需求改了

问题4:正则判断有问题

场景:写了一个正则,使用正则方法出现奇怪的情况

var reg = /test/g;
console.log(reg.test('test'), reg.lastIndex);  // true 4
console.log(reg.test('test'), reg.lastIndex);  // false 0
console.log(reg.test('test'), reg.lastIndex);  // true 4
console.log(reg.test('test'), reg.lastIndex);  // false 0

原因:正则最后写了一个"/g"导致每次使用完方法,会用“lastIndex”记录一次当前位置,如果找到就是当前位置,没有找到就会把“lastIndex”变成0
解决方法1:不要写"g",使用“g”要谨慎

var reg = /test/;
console.log(reg.test('test'), reg.lastIndex);  // true 0
console.log(reg.test('test'), reg.lastIndex);  // true 0
console.log(reg.test('test'), reg.lastIndex);  // true 0
console.log(reg.test('test'), reg.lastIndex);  // true 0

解决方法2:在每次使用之后,直接改变“lastIndex”的值

var reg = /test/g;
console.log(reg.test('test'), reg.lastIndex);  // true 4
reg.lastIndex = 0;

console.log(reg.test('test'), reg.lastIndex);  // true 4
reg.lastIndex = 0;

console.log(reg.test('test'), reg.lastIndex);  // true 4
reg.lastIndex = 0;

console.log(reg.test('test'), reg.lastIndex);  // true 4
reg.lastIndex = 0;

问题5:项目运行的时候报"getaddrinfo ENOTFOUND …"

场景:换一台电脑运行项目的时候报这个错
原因:120.0.0.1没有和后面那个地址绑定上
解决方法:修改hosts文件
例:
  127.0.0.1   对应的地址

问题6: echarts tooltip 里面写 react代码

这个过程太多,全部放到这篇文章中: https://blog.csdn.net/weixin_44726476/article/details/127301152

问题7: react中,引入图片之后,页面直接报错(没有找到这个模块)

场景:
直接看伪代码:

// 这样运行之后页面会报错,找不到这张图片
const url = './xxx.png';

<img src={require(url)} />

// 这样运行之后页面正常运行
<img src={require('./xxx.png')} />

原因:我猜测是webpack打包的时候,并没有执行js代码,觉得require里面是一个参数名,就没有把这张图片打包进去
直接看webpack打包后的文件:
先看直接引用字符串后的打包文件和代码:
在这里插入图片描述
打包时,有找到这个图片,并打包过去
然后看看引用参数时,打包生成的文件和代码:
在这里插入图片描述
dist文件夹里面并没有根据我配置的webpack,生成对应的images文件夹
解决办法:以后引入图片的时候,如果图片是存在前端文件里面的,引入的时候一定要引入对应路径。
就算图片路径是根据代码来判断用那张图片,也要先全部引入。可以用对象包裹起来,然后判断用哪张图片,不要为了少些几个require,导致这个bug找半天找不到原因。

问题8: 圆角导致图片位置错误

场景: 图片(img)外面有一个div,预期让div包裹图片,加一个圆角和边框
具体展示: 图片盖住上面两个圆角,下面两个圆角不会盖住,但是下面两个圆角和图片相隔一个圆角的距离
原因: 不明!
解决方法: 直接在img上加边框和圆角


技巧:

技巧1:后端传过来的是带HTML字符串,不让这些HTML标签用字符串直接展示

场景:后端传过来一个带html标签的字符串,但是展示不需要把这个html当字符串展示出来 (因为后端代码是好久之前某个离职的实习生写的,不好修改,就不改后端代码了)
解决方法1:react中dangerouslySetInnerHTML这个参数是可以把字符串转成html的标签(不建议使用)

<div dangerouslySetInnerHTML={{'__html': 后端传过来的数据}} />

解决方法2:根据后端传过来的字符串,把字符串拆分,并重新组合了一下,放到对应的位置。(内容格式固定的情况下)

技巧2:需要修改组件库的样式

场景:使用组件库时,发现组件库的样式不能满足需求,自己写的话需要时间,而且没有别人封装的全,这时就需要更改样式。
解决方法:

  1. 在开发页面中打开控制台,找到需要更改样式的元素,找到对应的class在这里插入图片描述
  2. 在对应的文件里面写css样式,最好在 ‘:global’ 外面套一层,要不然样式会作用到整个项目
.box {
  :global{
    .GeTMDd {
      color: red;
    }
  }
}

技巧3:修改hosts文件

场景:前端一个很频繁操作,不过都是项目运行前配置一次就可以了

  1. 在cmd中运行一串指令
    $ sudo vi /etc/hosts
    
  2. 输入密码后就进入文件了
  3. 退出的话直接输入
    $ :wq
    

技巧4:react中获取dom样式

场景:需要获取当前这个dom的一些样式的值

  1. 用useRef绑定这个dom
import React, { useRef } from 'react';
export default () => {
  const ref = useRef(null);
  return (
  	<div
  		ref={ref}
  	>dom
  	</div>
  )
}
  1. 使用window上的这个方法,就可以拿到这个dom的参数了
window.getComputedStyle(ref.current)

注意:这里的ref.current必须要绑定上这个dom才可以拿到

技巧5:react 18前useState 的set方法批处理

场景:在18之前,react的set方法写一次重新渲染一次,可以用unstable_batchedUpdates包裹住,就只渲染一次

import React, { useState } from 'react';
import { unstable_batchedUpdates } from 'react-dom';

export default () => {
	const [dataA, setDataA] = useState(0);
	const [dataB, setDataB] = useState(0);
	const [dataC, setDataC] = useState(0);
	
	setTimeout(() => {
		unstable_batchedUpdates(() => {
			setDataA(dataA + 1);
			setDataB(dataB + 1);
			setDataC(dataC + 1);
		})
	}, 10000)
	console.log(123); // 10秒后,这个123只执行一次

	return <div />
};

技巧6: 在iframe中,将iframe外的滚动条滚动到iframe的指定位置

场景: 滚动条是在iframe外的dom,没有主动修改这个dom的滚动条,也不能在iframe里面拿到外面的dom,也没有将浏览器窗口宽高、页面整个高度传进iframe
解决方法1: iframe中,可以通过dom上的scrollIntoView方法,将这个dom展示出来
解决方法2: textarea标签上的focus事件,也是可以让iframe外的滚动条滚动到这个textarea标签位置

手机兼容问题:

问题1:最好不要用replaceAll

场景:有些安卓机会报replaceAll不是一个函数
原因:有些安卓机不支持这个api
解决方法:使用replace


特殊的组件

选择本地文件,并获取其内容

需求:点击一个按钮之后,弹出弹窗,可以选择本地文件,获取这个文件内容,并转成base-64传到后端那里去,以及获取其文件名
代码:

import React, { useRef, useState } from 'react';
import { Button } from 'xxx组件库';

export default () => {
  const fileRef = useRef();
  const [fileInfo, setFileInfo] = useState({
    name: '', // 文件名
    content: '', // 文件内容
  });

  return (
    <div>
      <Button
        text
        onClick={() => {
          fileRef.current.click();
        }}
      >{fileInfo.name || '点击选择文件'}
      </Button>
      <input
        ref={fileRef}
        type="file"
        hidden
        onChange={(e) => {
          if (e.target.files.length !== 0) {
            const reader = new FileReader();
            const info = {};

			// 按代码来看,获取文件名应该放到reader.onload里面,但是我在reader.onload里面拿不到名字,可能是我拿到方式有问题
            info.name = e.target.files[0].name;
            reader.readAsText(e.target.files[0], 'utf-8')
            reader.onload = (res) => {
              // 获取文件内容,并转成base-64的字符串
              info.content = window.btoa(res.target.result);
              setFileInfo(info);
            }
          }
        }}
      />
    </div>
  )
};

fileInput按钮的小问题:

  1. fileInput样式不好看
  2. 第一次点击fileInput选择一个文件后。再次选择文件时,点击取消按钮,fileInput会展示未选择文件的样子,但是我不知道怎么触发取消事件

解决方式:把原本的fileInput隐藏,用useRef拿到fileInput的点击事件。然后像怎么展示就怎么展示。
ps:如果要选择多个文件需要改一下,我这里是因为只需要获取一个文件


处理ts项目飘红和飘黄

问题:

问题1:ts文件中,从window这种数据里拿一个后期添加的数据导致飘红

场景:代码飘红,报Property ‘*’ does not exist on type ‘window & typeof globalThis’.,而且window这种数据类型不是在这个项目里面设置的。(以window为例)
在这里插入图片描述
原因:window类型里面没有‘ABCD’的声明。
解决方法:在ts的配置文件 “自己命名.d.ts” 文件里面增加一条这个就可以了。

interface Window {
  ABCD?: any;
}

ps:一开始想用ts的继承,然后发现我修改不了window的接口(可能可以修改,但是我是因为第一次用ts,好多东西不知道)。

问题2:ts文件里面写require引入飘红

场景:代码飘红,报 Require statement not part of import statement.
这里整行飘黄是因为第二行不是空白的代码
在这里插入图片描述
原因:ts文件里面不能用require引入 (原因需要再看看,我师兄说是因为ts文件需要预编译什么的)
解决方法:使用“import … from …”引入

问题3:tsconfig.json配置文件最上方飘红

场景:代码飘红,报:

File '文件名' is not under 'rootDir' 'rootDir里面填的路径'. 'rootDir' is expected to contain all source files.
  The file is in the program because:
    Part of 'files' list in tsconfig.json

原因:这个​​​​​​​报错是因为在tsconfig.json文件“files”或“include”里面的文件不在“compilerOptions”配置中的“rootDir”配置里面。试过修改“rootDirs”里面的内容,但是没有用。
解决方法:虽然不理解这些配置,但是最后在网上找到一个方法,就是把"rootDir"改成默认的"./“,这样就可以把整个项目都放进去,原来这里"rootDir"里写的是”./src",就是不知道这样会不会对项目有什么影响,需要过几天测一下,我现在还没有测试一下,不确定有没有问题。

问题4:下载package.json中的包卡住,一直转圈圈

场景:项目是用ts的,用公司的npm下载插件,因为有些是公司自己的包,npm下载不了,就没有试npm了。几天前下载没有问题,今天突然就开始卡住,而且停止之后重新“npm i”又有用了。
而且文件里面会报有些依赖引用不到。
在这里插入图片描述由于node_modules可以找到对应的文件,由于之前是有用的,所以排除两种修改方法
排除方法1:使用这个命令下载ts对应的包 “npm i --save-dev @types/依赖名”
排除方法2: 在ts的配置文件 “自己命名.d.ts” 文件里面增加一条 “ declare module ‘依赖名’ “

网上有个说是因为这个包没有下配置,第一个是下载一个ts的,如果报错,就是这个包没有ts的版本。这时候可以用第二个方法,但是这个方法我还是没有理解是干啥。不过大家都建议用第一个。
原因:未知,需要再看看
解决方法:除了上面两种排除的方法,网上没有找到其他解决方法,然后无意中发现,下载一部分package.json的包,然后再下载全部的就没有问题了,猜测是包太多了,导致下载卡住

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值