最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 盘点那些 React Hooks 里常见的问题

    正文概述 掘金(Tonychen)   2021-06-16   466

    原文:juejin.cn/post/697243…
    作者:Tonychen

    Infinite Chain Of Update

    实际使用中有时候会碰到 Infinite Chain Of Update 这个报错,其实就是你的一段代码引发了「死循环更新」。下面我们来看几个例子?

    依赖数组问题

    比如说在使用 useEffect 时没有传入依赖数组?

    // count 会无限 + 1
    function App() {
        const [count, setCount] = useState(0)
    
        useEffect(() => {
            setCount(count + 1)
        })
    }
    

    为什么说 count 会无限更新?这里的逻辑是这样的?

    • 组件更新
    • 执行 useEffect
    • 更新 count 并触发组件更新
    • 执行 useEffect
    • ……

    盘点那些 React Hooks 里常见的问题

    解决方法很简单,只要给 useEffect 传一个空数组作为第三个参数,下次更新时 useEffect 便不会执行。

    // 正常渲染
    function App() {
        const [count, setCount] = useState(0)
    
        useEffect(() => {
            setCount(count + 1)
        }, [])
    }
    

    监听了被更新的值

    这个算是新手 hooks 玩家经常会遇到、老手也有些头疼的问题。

    • 案例1

    useEeffect 中更新的 state 间接影响了被监听的变量,举个例子?

    function App() {
        const [obj, setObj] = useState({a: 0})
        const {a} = obj
        useEffect(() => {
            setObj({
                ...obj,
                a: 1
            })
        }, [a, obj])
    }
    

    上面这段代码在实际运行的时候就会导致死循环,为什么呢?因为在 setObj 的时候改变的是 obj 这个值,而 useEffect 监听了这个值,从而 导致了死循环……

    盘点那些 React Hooks 里常见的问题

    怎么解决呢?由于是 obj 变化引起的 infinite loop ,那么其实只要不监听 obj 就没有这回事了

    ?,这里可以利用一下 setState 的「回调函数」用法?

    function App() {
        const [obj, setObj] = useState({a: 0})
        const {a} = obj;
        useEffect(() => {
            setObj((state) => ({
                ...state,
                a: 1
            }))
        }, [a])
    }
    
    • 案例2

    有时候你需要根据不同的「状态」来决定组件显示什么,那么通常就需要利用一个 state 来控制若干种「状态」的显示,从状态 1 到状态 2 的转化是异步的。一个简单的做法就是用 useEffect 来监听它。

    盘点那些 React Hooks 里常见的问题

    如果说这个状态有一部分依赖外部传入,另外一部分根据这个外部传入的状态的变化来进行对应的处理。举个例子?

    export function App({outsider, wait}) {
        const [state, setState] = useState('INIT')
        useEffect(() => {
            // 根据 ousider 处理 state 的值
            if (outsider === true) {
                    setState('PENDING')
            } else {
                if (state === 'PENDING') {
                    setTimeout(() => {
                        setState('RESOLVED')
                    }, wait)
                }
            }
        }, [outsider, state])
        return (
            // 根据 state 来渲染不同的组件/样式
        )
    }
    

    实际运行起来的话又是 infinite loop 了,可能你第一时间我想的一样,就是采用「案例1」的解法。但是注意,这里是有异步处理的,所以这里只能说是利用 useRef 来做一下简单的处理。

    export function App({outsider, wait}) {
        const [state, setState] = useState('INIT')
        const stateRef = useRef(state)
        useEffect(() => {
            // 根据 ousider 处理 state 的值
            if (outsider === true) {
                setState('PENDING')
                stateRef.current = 'PENDING'
            } else {
                if (stateRef.current === 'PENDING') {
                    setTimeout(() => {
                        setState('RESOLVED')
                        stateRef.current = 'RESOLVED'
                    }, wait)
                }
            }
        }, [outsider])
        return (
            // 根据 state 来渲染不同的组件/样式
        )
    }
    

    这样一来在 useEffect 中就不需要依赖 state ,而且能够根据 state 当前的值做出一些操作?

    小结

    在写 hooks 的时候,需要经常注意代码中是否有依赖 statesetState 的地方,通常直觉上的写法是会带来 infinite loop 的。

    盘点那些 React Hooks 里常见的问题

    获取不到最新的值

    新手 hooks 经常会碰到这类问题,下面是一个简单的例子?

    import { useCallback, useEffect, useState } from "react";
    
    let timeout = null;
    export default function App() {
      const [count, setCount] = useState(0);
    
      const handleClick = useCallback(() => {
        setCount(count + 1);
        timeout = setTimeout(() => {
          console.log("timeout", count);
          setCount(count + 1);
        }, 1000);
      }, [count]);
    
      useEffect(() => {
        return () => {
          clearTimeout(timeout);
        };
      }, []);
    
      return (
        <div className="App">
          <p>{count}</p>
          <button onClick={handleClick}>click me</button>
        </div>
      );
    }
    

    运行之后你会发现,每次 console.log 打印出来的都是上一次 count + 1 前的结果,而这其实就和 useState 实现有关系了,这里仅截取源码中的一小部分实现?

    盘点那些 React Hooks 里常见的问题

    可以看出,从 useState 中解构出来的是原数据的值而非引用,所以在上面的例子中,在 setTimeout 里拿不到最新的 count 值。

    参考资料

    Setting State based on Previous State in useEffect - Its a trap!


    起源地下载网 » 盘点那些 React Hooks 里常见的问题

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元