阅读 24

面向新手的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) {
   ......
}复制代码

数据格式转换

在开发时一定要多留意后端返回的数据类型是不是符合我们的预期,有时候很多问题都是由此导致的。

例如,我们拿到的idstring类型,但是在调其它接口传参数时需要传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只是在兄弟节点之间必须唯一,并不需要全局唯一。避免使用indexdate作为 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


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 gxwowoo@163.com 举报,一经查实,本站将立刻删除。
相关推荐