作为一个刚入门的萌新,入职在这个公司大半年之后,每当看到以前的代码,总会默默骂一句狗屎,忍无可忍开始优化之路
一、 if else if 过长
简单的状态判断
可以通过对象或者ts中的枚举
function fn(state: number) {
if (state === 1) {
console.log('xxxx1')
} else if (state === 2) {
console.log('xxxx2')
} else if (state === 2) {
console.log('xxxx3')
}
}
//使用对象的方式
function fn1(state: number) {
const stateObj = {
1: 'xxxx1',
2: 'xxxx2',
3: 'xxxx3'
}
console.log(stateObj[state])// key值为数字,不能使用.进行赋值,使用[]
}
复杂一点的信息提交校验时
经常会见到这样的代码
async function onSubmit(values: Partial<SubData>) {
const { tel, isPhone, verCode, password, conimPawd, verCodeKey, ...vals } = values
if (!tel) {
message.warning('手机号为空')
} else if (!isPhone.test(tel)) {
message.warning('手机号格式不正确')
} else if (!verCode) {
message.warning('验证码为空')
} else if (password === '' || conimPawd === '') {
message.warning('密码为空')
} else if (password !== conimPawd) {
message.warning('密码必须相同')
} else if (!verCodeKey) {
message.warning('请获取验证码')
} else {
const res: Resolve = await forgetPass(values)
if (res?.code === 200) {
message.success('修改成功,请重新登录')
navigate('/login')
}
}
}
通过循环和return关键字
将连续校验的结构拆解为自上而下的结构,代码逻辑更加清晰
async function onSubmit(values: Partial<SubData>) {
const { tel, isPhone, verCode, password, conimPawd, verCodeKey, ...vals } = values
const rules = [
{ required: !tel, message: '手机号为空' },
{ required: !isPhone.test(tel), message: '手机号格式不正确' },
{ required: !verCode, message: '验证码为空' },
{ required: !password || !conimPawd, message: '密码为空' },
{ required: password !== conimPawd, message: '密码必须相同' },
{ required: !verCodeKey, message: '请获取验证码' }
]
for (let i = 0; i < rules.length; i++) {
if (rules[i].required) {
message.error(rules[i].message)
return
}
}
const res: Resolve = await resetPass(values)
if (res?.code === 200) {
message.success('修改成功,请重新登录')
navigate('/login')
}
}
二、自定义hook,摆脱重复CV
这是一个后台页面的大概逻辑
我们可以通过自定义hook来简化这个过程,避免每个页面重复Ctrl+CV
const [oSrch, setSrch] = useState<SrchData>({ page: 1, pageSize: 10 })
const [tableData, setTableData] = useState<Res<TableData>>()
useEffect(() => { getData(), [oSrch])
async function getData() {
try {
const res: Res<T> = await networkReq(oSrch)
if (res?.code === 0) setData(res?.data)
} catch (err) {
console.error(err)
}
}
//查询
function onSearch(values: Partial<TableData>) {
const { name, ...vals } = values
// 对参数的处理
setSrch({ ...vals, page: 1, pageSize: oSrch.pageSize })
}
//分页变化
function pageChange(page, pageSize) {
setSrch({ ...oSrch, page, pageSize })
}
自定义hook代码
可以在这里集中捕获错误,判断获取状态等
/*
networkReq:封装好的网络请求
addParame:需要添加的额外请求参数
返回值
parame:网络请求参数
setParame:改变参数配合useEffect重新请求 (例如:搜索查询)
data:成功后的数据
isSendReq, setSendReq:是否重新请求的开关
loading:请求过程的状态
*/
import { useEffect, useState } from 'react'
const useGetData = <T,>(networkReq: any, addParame?: SrchData) => {
const [data, setData] = useState<ResData<T>>()
const [parame, setParame] = useState<SrchData>({ page: 1, pageSize: 10 })
const [isSendReq, setSendReq] = useState<boolean>(false)
const [loading, setLoading] = useState<boolean>(false)
useEffect(() => {
getData()
}, [parame, isSendReq])
async function getData() {
try {
setLoading(true)
const res: Res<T> = await networkReq({ ...parame, ...addParame })
if (res?.code === 0) {
setData(res?.data)
setLoading(false)
} else {
//常见错误:例如约定的成功返回值code不为0
console.warn(res)
setLoading(false)
}
} catch (err) {
console.error(err)
setLoading(false)
}
}
return [parame, setParame, data, isSendReq, setSendReq, loading] as [SrchData, any, ResData<T>, boolean, any, boolean]
}
export default useGetData
使用
原先每个页面十几行代码,现在一行结束,告别复制粘贴
const [oSrch, setSrch, tableData, isSendReq, setSendReq, loading] = useGetData<TableData>(getAdminList)
//查询
function onSearch(values: Partial<TableData>) {
const { name, ...vals } = values
// 对参数的处理
setSrch({ ...vals, page: 1, pageSize: oSrch.pageSize })
}
三、循环方式的选择
当时碰到一个开发需求,后台返回的全国省市区需要二次处理,当时还是初入职场的菜鸡,傻乎乎的用三层for循环
for循环
const options = [];
for (let i = 0; i < regionData?.length; i++) {
options.push({
value: regionData[i]?.id,
label: regionData[i]?.name,
children: [],
})
for (let c = 0; c < regionData[i]?.city?.length; c++) {
options[i].children.push({
value: regionData[i]?.city[c].id,
label: regionData[i]?.city[c].name,
children: [],
})
for (let a = 0; a < regionData[i]?.city[c]?.area.length; a++) {
options[i].children[c]?.children?.push({
value: regionData[i]?.city[c]?.area[a].id,
label: regionData[i]?.city[c]?.area[a].name
})
}
}
}
使用map
可以看到可读性更好,总体也更加简洁(这里先不考虑效率问题)
const options = regionData?.map(province => ({
value: province.id,
label: province.name,
children: province.city.map(city => ({
value: city.id,
label: city.name,
children: city.area.map(area => ({
value: area.id,
label: area.name
}))
}))
}))