面向新手的React实战经验
前言
这篇文章的内容基于自己日常开发经验,主要是一些实战小技巧和踩坑心得,希望能对大家有所帮助,不足之处还请大家多多指教。持续更新~
注释
养成一个写注释的好习惯利人利己,写注释时要站在同事的角度,简明扼要。
单行注释
// 程序描述 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节点被不必要地重新创建,这可能导致性能下降和子组件中的状态丢失。
不点赞就跑?感谢阅读~
作者:款冬_
链接:https://juejin.cn/post/7056315818845405221