新手该如何用好react的useEffect

300 阅读2分钟

最近看到很多文章,写了useEffect依赖会造成“心智负担”和“非直觉的”渲染,出现了很多莫名其妙的形容词,今天我来讲讲用好useEffect的一些细节

1.不要在useEffet中使用setState

这是一种极其错误的行为,要记住useEffect是一种副作用,为什么叫副作用呢?因为他是状态改变后带来的额外作用,所以在副作用中修改状态本来就是一种荒谬的行为,很容易造成死循环然后心智负担就来了。(当然你是高手你可以这么写)

更好的写法是使用useMemo计算出新的属性

例子:

const Component = (a: number) => {
    const [b, setB] = useState<number>(1);
    
    // 正确的
    const sum = useMemo(() => a + b, [a, b]);
    
    // 错误的
    useEffect(() => {
        setSum(a + b); // 伪代码
    }, [a, b])
}
  1. 合并你的依赖

合并依赖是优化useEffect的重要手段,当依赖过多时容易猪脑过载,也容易造成useEffect反复执行,所以应当适当减少依赖,将多个依赖抽象成更高级的依赖会对你很有帮助,这是一种抽象能力,在实际开发中你没办法做好这一点,应该多加思考。

简单举例,在长列表中,加载完所有页面后弹出一个toast为例:

const [loading, setLoading] = useState<boolean>(false);
const [currPage, setCurrPage] = useState<number>(0);
const [allPage, setAllPage] = useState<number>(100);

// 不友好的
useEffect(() => {
    if (currPage >= allPage && !loading) {
        toast('加载完啦');
    } 
}, [loading, currPage, allPage]);

// 比较友好的 
const isAllPageLoaded = useMemo(() => currPage >= allPage, [currPage, allPage]);
useEffect(() => {
    if (isAllPageLoaded && !loading) {
        toast('加载完啦');
    } 
}, [loading, isAllPageLoaded]);
  1. 你并非只能写一个useEffect

新手写useEffect都很喜欢把所有的副作用写到同一个useEffect中,造成一个useEffect中依赖多,以及执行多余的不必要逻辑,这也是抽象能力欠缺的一种

简单举例,在长列表中,上拉加载完所有页面后弹出一个toast和没有数据时弹出一个toast:

不友好的:

const [loading, setLoading] = useState<boolean>(false);
const [currPage, setCurrPage] = useState<number>(0);
const [allPage, setAllPage] = useState<number>(100);
const [data, setData] = useState<Object[][]>([]);

useEffect(() => {
    if (currPage > 0 && data.length === 0) {
        toast('没有数据');
    }
    if (currPage >= allPage && !loading) {
        toast('加载完啦');
    } 
}, [loading, currPage, allPage, data]);

比较友好的:

const [loading, setLoading] = useState<boolean>(false);
const [currPage, setCurrPage] = useState<number>(0);
const [allPage, setAllPage] = useState<number>(100);
const [data, setData] = useState<Object[][]>([]);

// 我负责判断加载完
const isAllPageLoaded = useMemo(() => currPage >= allPage, [currPage, allPage]);
useEffect(() => {
     if (isAllPageLoaded && !loading) {
        toast('加载完啦');
    } 
}, [loading, isAllPageLoaded]);

// 我负责判断没有数据
useEffect(() => {
    if (currPage > 0 && data.length === 0) {
        toast('没有数据');
    }
}, [currPage, data.length]);

结尾我想表达的是,对于新手而言在“大胆质疑,小心求证”更应该小心求证,如果大家都觉得好用的东西你觉得难用那大概率是你不会用,当然你不想用你也不乐意思考我觉得还是声音小一点吧,少一点反向抹黑,让大家有个清净的环境。