实现一个 Mini React:核心功能详解 - useDeferredValue 的实现, 从底层理解运行机制

193 阅读2分钟

xdm,又要到饭了,又更新代码了!

总结一下上一篇完成的内容,

  1. 完成了useContext的实现, 从底层理解运行机制。

有兴趣的可以点这里查看useContext的实现, 从底层理解运行机制

这一篇我们实现useDeferredValue hook。 这个hook的出现就是解决特定情况下需要延迟更新的场景。

比如,有复杂的计算放在了useEffect 里面,useEffect 的依赖值就是val, val就是复杂计算的一部分。那么如果val使用用户点击进行更新,那么useEffect 的复杂计算将会大量重复计算,这直接会是ui渲染卡顿。即一个frame里面如何完成该完成的工作(大量的计算), 代码如下,

function Test({val}) {
    const factorial = useMemo(()=>{
        // 大量计算的函数
        return computeFactorial(val)
    },[val]) 
}

由于val一直变化,即使上面的代码使用了useMemo也无法解决卡顿问题。那么既然卡顿由于大量计算导致,那么是可以配合ric的空闲时间进行延迟计算呢?这个就是useDeferredValue 解决的场景之一。

实现 useDeferredValue

function useDeferredValue(val) {
    const [deferredValue , setDeferredValue] = useState(val)
    const updateDeferredValue = ()=>{
        setDeferredValue(val)
    }
    useEffect(()=>{
        let handle
        
        if (requestIdleCallback !== 'undefined') {
           handle= requestIdleCallback(updateDeferredValue)
        } else {
           handle= setTimeout(updateDeferredValue, 0);
        }
        
        return ()=>{
            if (typeof requestIdleCallback !== 'undefined') {
                cancelIdleCallback(handle)
            } else {
                clearTimeout(handle)
            }
        }
    }, [val])
    
    return deferredValue
}

实现代码巧妙的尝试使用 ric 进行延迟更新,这样可以避免大量计算进而导致ui更新卡顿。

react 咋么做的

react由于有concurrent mode, 所以它可以赋予任务的优先级权重决定当前的任务运行顺序,这样的原理其实和 requestIdleCallback类似,但是不完全相同。

react 的实现

function useDeferredValue(value) {
    const [deferredValue, setDeferredValue] = useState(value)
    
    useEffect(()=>{
        // 低优先级任务会排在高优先级任务之后运行,
        const handle = scheduleCallback(PRIORITY_LOW, ()=>{
            setDeferredValue(value)
        })
    }, [value])
}

scheduleCallback 以及 useState 的底层实现之前的系列文章已经实现过了,有兴趣的可以查看。

这篇我们尝试实现了一个自己的useDeferredValue版本,然后实现了一个react的版本,也对对于useDeferredValue的使用场景以及解决了什么问题进行了讲解。

那么下一篇将从0-1实现开发 useLayoutEffect 。

如果文章对你有帮助,请点个赞支持一下!

啥也不是,散会。