当前位置: 首页 > 科技观察

前端精神小伙:ReactHooks响应式布局

时间:2023-03-17 14:22:15 科技观察

前言现在稍大的站点都会使用H5/PC端并行,使用nignx获取浏览器UA信息来切换站点。但这对于一些企业站点或者人员不足的小项目来说是很难实现的。通过CSS媒体查询实现响应式布局是主流方式。然而,有时在React程序中,需要根据屏幕大小有条件地渲染不同的组件(写媒体查询太麻烦,不如另写一个组件)。事实上,使用ReactHooks可以更灵活。本文的实现来自:DevelopingresponsivelayoutswithReactHooks1。方案一:innerWidth是一个很简单粗暴的方案,前端已知:constMyComponent=()=>{//currentwindowwidthconstwidth=window.innerWidth;//neighboringvalueconstbreakpoint=620;//当宽度小于620时渲染移动组件,否则桌面组件返回宽度:;}这个简单的解决方案肯定有效。根据用户设备的窗口宽度,我们可以呈现桌面视图或移动视图。但是当窗口调整大小时,宽度值的更新并没有解决,可能会渲染错误的组件。2.方案二:Hooks+resize好说,在监听resize事件的时候,触发useEffect改变数据。constMyComponent=()=>{const[width,setWidth]=React.useState(window.innerWidth);constbreakpoint=620;React.useEffect(()=>{window.addEventListener("resize",()=>setWidth(window.innerWidth));},[]);returnwidth:;}但是精通Hooks的你一定知道这里有一个内存性能消耗的问题:resize事件是没有删除!优化版:constuseViewport=()=>{const[width,setWidth]=React.useState(window.innerWidth);React.useEffect(()=>{constandleWindowResize=()=>setWidth(window.innerWidth);window.addEventListener("resize",handleWindowResize);return()=>window.removeEventListener("resize",handleWindowResize);},[]);return{width};}3.方案三:构建useViewport自定义ReactHooks,可以最大限度地重用组件/功能。构建一个也很简单:constuseViewport=()=>{const[width,setWidth]=React.useState(window.innerWidth);React.useEffect(()=>{constandleWindowResize=()=>setWidth(window.innerWidth);window.addEventListener("resize",handleWindowResize);return()=>window.removeEventListener("resize",handleWindowResize);},[]);return{width};}精简组件代码:constMyComponent=()=>{const{width}=useViewport();constbreakpoint=620;returnwidth:;}但是这里还有一个性能问题:响应式布局会影响多个组件,这是一种性能浪费如果在多个地方使用useViewport。这时候就需要另一个React儿子:ReactContext(上下文)来帮忙了。4.终极方案:Hooks+Context我们会新建一个文件viewportContext,里面可以存放当前viewport大小的状态和计算逻辑。constviewportContext=React.createContext({});constViewportProvider=({children})=>{//顺便监控高度,备用const[width,setWidth]=React.useState(window.innerWidth);const[height,setHeight]=React.useState(window.innerHeight);constandleWindowResize=()=>{setWidth(window.innerWidth);setHeight(window.innerHeight);}React.useEffect(()=>{window.addEventListener("resize",handleWindowResize);return()=>window.removeEventListener("resize",handleWindowResize);},[]);return({children});};constuseViewport=()=>{const{width,height}=React.useContext(viewportContext);return{width,height};}接下来需要确保App被包裹在React根节点中:constApp=()=>{return();}以后每个useViewport()其实只是共享Hooks而已。constMyComponent=()=>{const{width}=useViewport();constbreakpoint=620;returnwidth:;}Postscriptgithub上的响应式布局钩子都是类似的实现方式。本文除了介绍ReactHooks的响应式布局实现外,还介绍了如何自定义hooks并使用Context复用它们,以达到最佳的性能优化。