持续创作,加速成长!这是我参与「掘金日新计划 · 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库