useLayoutEffect与useWidth

317 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第31天,点击查看活动详情

钩子函数:useLayoutEffect

场景:声明一个div组件,使它在1s之内移动

使用useEffect

useEffect(()=>{
                ref.current.style.WebkitTransform = `translate(500px)`
                ref.current.style.transtion = `all 1000ms`
  })

运行代码后可以观察到,是先绘制完div盒子,再进行盒子的移动.那是因为- useEffect 是异步非阻塞调用。在useEffect中修改真实dom的样式可以发现明显的样式变动。整个5s的过程都尽收眼底。

而代码:

 useLayoutEffect(()=>{
                ref.current.style.WebkitTransform = `translate(500px)`
                ref.current.style.transtion = `all 5000ms`
  })

同样也是修改了元素dom的样式,但运行之后观察页面不会发生明显的变动,那是因为useLayoutEffect为同步阻塞调用,不会发生闪动。

简单总结:

  • useEffect 是异步非阻塞调用
  • useLayoutEffect 是同步阻塞调用
  • useEffect 浏览器绘制后
  • useLayoutEffect 在 DOM 变更(React 的更新)后,浏览器绘制前完成所有操作

useWidth自定义hooks

很多自己封装完的hooks可以直接拿来复用,相比每次写完要重新再写要方便很多。

让我尝试写一个自定义hooks--useWidth,实时更新屏幕宽度

首先要知道获取浏览器屏幕宽度的方法

document.body.clientWidth document.body.innerWidth
const [width,setWidth] = useState(document.body.clientWidth)

定义一个函数来改变屏幕宽度的值

 const onChange = useCallback(()=>{
     setWidth(document.body.clientWidth)
 },[])

当屏幕宽度改变时,获取完宽度然后展示数字的方法使用到了副作用处理useEffect,当渲染完屏幕后监听屏幕宽度的变化。

useEffect(()=>{
    window.addEventListener("resize",onChange,false)
    return ()=>{
        window.removeEventListener("resize",onChange,false)
    }
},[])

(记得监听完要remove哦)

自定义hooks:封装成一个函数,可以直接调用

 function useWidth(defaultWidth){
const [width,setWidth] = useState(document.body.clientWidth||defaultWidth)
     //依赖,始终在使用这一个函数
     const onChange = useCallback(()=>{
         setWidth(document.body.clientWidth)
     },[])
     useEffect(()=>{
         window.addEventListener("resize",onChange,false)
         return ()=>{
             window.removeEventListener("resize",onChange,false)
         }
     },[])
     return width;
 }

封装完useWidth这个函数就可以直接当成hooks调用了

function App(){
//调用useWidth这个函数,并传入初始值
    const width = useWidth(document.body.clientWidth)
    return(
        <div>
         width:{width}    
        </div>
    )
}

注意,自己定义完一个函数hooks后如果直接调用:

//html下直接调用useWidth
 let result = useWidth(document.body.clientWidth)
 console.log(result)

会报错,因为自己封装的hooks只能在组件中使用,就像刚才在App中调用useWidth()一样。

好啦,hooks的学习就告一段落啦,认识到有一个新的hooks库叫做ahooks,可以随时来看,来学习,来使用。

指路ahooks库