前言
这篇文章的内容基于自己日常开发经验,主要是一些实战小技巧和踩坑心得,希望能对大家有所帮助。持续更新~
注释
养成一个写注释的好习惯利人利己,写注释时要站在同事的角度,简明扼要:
- 单行注释
// 程序描述
function toStr(v) { // 块描述
// 代码段描述
return v.toString(); // 语句描述
}
- 多行注释
/**
* 在多行注释中,
* 包含在 /** 和 */ 符号之间的任何字符,
* 都会被视为注释文本
*/
- 注释前缀
// TODO: 接口等待联调
// FIXME: 列表更新有bug,待修复
引入模块顺序
- 第三方的放最上面
- 其次是当前项目的其它模块
- 最后是 CSS 样式
import * as React from 'react;
import {Button, Input} from 'antd';
import Header from './Header';
import {Status} from './const';
import * as styles from './index.less';
代码风格
以下是主流的编码风格,具体还得遵循团队规范:
- 使用单引号,或者 es6 的反引号
- 除了代码块以外的每个表达式,结尾必须加分号
- 变量和函数采用小驼峰命名
- 常量用大写字母命名,单词之间用下划线分隔,例如:STATUS_MAP
- 组件内的事件函数使用 handle 开头,例如:handleConfirm
- 通过 porps 传递函数时使用 onXxx 的形式作为回调函数的属性名称
const App = () => {
const handleCancel = () => {
...
}
return (
<div>
Hello !
<Child onClose={handleCancel}/>
</div>
)
}
- 不要过分省略大括号
// not good
if(condition) doSomething();
// good
if (condition) {
doSomething();
}
语义化
给状态和函数命名时要做到语义化,让人看完英语单词立即能够知道这个状态代表哪个值、这个函数是处理什么事件,要尽量避免未知含义的代码:
// not good
const [value, setValue] = useState();
// good
const [checkedValue,setCheckedValue] = useState();
// not good
const handleClick = () => {}
// good
const handleConfirm = () => {}
// bad(同事一脸懵逼)
if (type !== 0) {
// TODO
}
// good
const STATUS = {
FAILED: 0,
SUCCESS: 1,
}
if (type === STATUS.SUCCESS) {
// TODO
}
// best(TS枚举)
enum STATUS {
FAILED = 0,
SUCCESS = 1,
}
渲染默认值
添加非空判断,利用默认值进行预防,可以提高代码的稳健性。例如后端返回的一些值,可能会出现不存在的情况,这时候给一个默认值就能避免很多缺陷:
const res = request();
if (res && res.success) {
message.success('删除成功');
} else {
// 如果后端没有暴露出失败的具体原因,就提示 ‘删除失败’
message.error(res.message || '删除失败');
}
还有一种情况,后端本来应该返回一个数组,但是数据库里取不到数据,这时可能返回 null
。如果代码里有将 list.length
作为条件判断,就会报错。最简单的解决方法就是添加非空判断和默认值:
const [listData, setListData] = useState([]);
const { data: { list } } = request();
// 如果 list 为 null,就会取 [],下面的 listData.length 就不会报错
setListData(list || [])
if (listData.length > 0) {
......
}
数据格式转换
在开发时一定要多留意后端返回的数据类型是不是符合我们的预期,有时候很多问题都是由此导致的。
例如,我们拿到的id
是string
类型,但是在调其它接口传参数时需要传number
类型,这很容易被忽略。以下两种将字符串转换成数字的方法是等价的:
const a = '2022';
console.log(+a); // 2022(number) 最简单
console.log(Number(a)); // 2022(number)
还有一种情况需要注意,后端返回的 ‘布尔值’,其实是个字符串类型:‘false’
、‘true’
。如果我们直接用来判断,则永远为true
。曾经因为这个问题导致的一个bug差点给我整崩溃了~
转成布尔值推荐使用 双重逻辑非!!
console.log(!!0); // false
console.log(!!1); // true
console.log(!!""); // false
console.log(!!null); // false
console.log(!!undefined); // false
console.log(!![]); // true
console.log(!!{}); // true
判断条件真假
以下为假,其它为真:
- false
- null
- undefined
- 0
- '' (空字符串)
- NaN
解构赋值
写代码尽量简洁,这样更易于阅读和后期维护。使用解构赋值将频繁使用的属性或值先进行缓存,后面使用的话会更加方便:
// bad
props.data.id;
props.data.username;
state.detail.status;
// good
const { id, username } = props.data;
const { status } = state.detail;
input 输入框去空格
// bad
const handleInputChange = (e) => {
setInputValue(e.target.value);
}
// good
const handleInputChange = (e) => {
setInputValue(e.target.value.trim());
}
try catch
发送 ajax 请求时,使用try catch
捕获错误,也可以根据返回的状态进行一些操作。例如,进入列表页时首先需要一个loading
状态,然后去请求数据,无论请求成功还是失败,都需要把loading
去掉:
const getList = async () => {
try {
setLoading(true);
const res = await request();
} catch (err) {
// TODO
} finally {
setLoading(false);
}
}
阻止事件默认行为
在 React 中不能通过返回 false 来阻止默认行为,必须明确调用 event.preventDefault()
。
阻止冒泡
event.stopPropagation()
减少 useEffect 依赖
useEffect
依赖越多,复杂度就越高,容易导致 bug:
// bad
function Component({ id, name }) {
useEffect(() => {
setId(id);
setName(name);
}, [id, name, ...更多]);
}
// good
function Component({ id, name }) {
useEffect(() => {
setId(id);
}, [id]);
useEffect(() => {
setName(name);
}, [name]);
}
key
key
只是在兄弟节点之间必须唯一,并不需要全局唯一。避免使用index
和date
作为 key 值。如果实在取不到唯一值,可以使用nanoid
这个库来生成 uuid (通用唯一识别码):
npm i nanoid
import { nanoid } from 'nanoid'
// 直接调用,即可生成一个 uuid
key={ nanoid() }
组件实例是基于它们的key
来决定是否更新以及复用,如果key
是一个下标,那么修改顺序时index
也会随之改变,即当前key
发生了变化,这可能会导致非受控组件的 state(比如输入框) 相互篡改,发生无法预期的变动。
key
应该具有唯一性、稳定性和可预测性。不稳定的 key(比如new Date()、Math.random()
) 会导致许多组件实例和DOM节点被不必要地重新创建,这可能导致性能下降和子组件中的状态丢失。
最后
如果文中有错误或者不足之处,欢迎大家在评论区指正。
你的点赞是对我莫大的鼓励!感谢阅读~