调整浏览器大小时如何调用useEffect
Posted
技术标签:
【中文标题】调整浏览器大小时如何调用useEffect【英文标题】:How to call useEffect when browser is resized 【发布时间】:2021-09-17 18:58:34 【问题描述】:我需要在 react-slick 旋转木马内等高的引导卡。我从以下帖子中找到了解决方案:React Slick Slide Height Issue
下面是我的代码,它记录了包含引导卡的轮播 div 的高度。然后将捕获的高度作为道具传递给引导卡。
const [upcomingEventsHeight, setUpcomingEventsHeight] = React.useState("auto");
React.useEffect(() =>
setTimeout(
() =>
const height = document.getElementsByClassName("slick-track")[0].clientHeight;
setUpcomingEventsHeight(height + "px");
, 3000);
, []);
它工作正常,除非在调整浏览器大小时,因为高度仅在页面第一次渲染时设置。
我认为我需要在调整浏览器大小时重新渲染页面,并且我知道我可以使用
window.addEventListener('resize', ...);
但是,我收到以下代码的错误,因为无法在回调中调用 React.useEffect。
window.addEventListener('resize', () =>
React.useEffect(() =>
setTimeout(
() =>
const height = document.getElementsByClassName("slick-track")[0].clientHeight;
setUpcomingEventsHeight(height + "px");
, 3000);
, []);
);
我不确定如何解决这个问题,因为我想使用 useEffect 重新渲染页面。
【问题讨论】:
钩子的第一条规则——它必须在组件的顶层。所以你的要求是错误的 为什么在调整大小时需要useEffect
?您是否尝试将代码直接放在事件侦听器上?如果是因为setTimeout
,你可以尝试使用useRef
做一些事情来存储它的引用
我不是 React 人,所以请原谅任何无知 - 但为什么不在元素的 CSS 规则集中设置 height:100%
?
【参考方案1】:
这对于很多项目来说很棘手但微不足道。 你的useEffect会触发一次,每次用户调整浏览器大小都会触发里面的函数。
有时当您调整浏览器大小时,您无法访问状态或设置状态(使用 useState),所以我喜欢将窗口的 width
的值放在外面。这样我就可以随时重用这些值而几乎没有冲突。
// react using hooks
import useState, useEffect from 'react';
// use outside the component
let isMobile = true; // variable to check width
const MyComponent = () =>
// optional: save the width of the window using state
const [width, setWidth] = useState(window.innerWidth); // check width size of the window
const handleWindowSizeChange = () =>
setWidth(window.innerWidth);
isMobile = window.innerWidth < 700 ? true : false;
;
// call your useEffect
useEffect(() =>
window.addEventListener('resize', handleWindowSizeChange);
return () =>
window.removeEventListener('resize', handleWindowSizeChange);
;
, []);
// view of the component
return (<h1>isMobile</h1>)
【讨论】:
【参考方案2】:您想使用useEffect
添加事件侦听器(并删除它)。
const handleResize = () =>
...
React.useEffect(() =>
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
, [])
这将在组件渲染时添加事件侦听器,并在未渲染时将其删除(useEffect
的返回值在清理时运行)。 useEffect
将在第二个参数中数组中的变量每次更改时运行(在这种情况下,它保留为空 [],因此它只会运行一次)。
此外,您应该考虑使用“去抖动”函数this post explains how they work,而不是使用 setTimeout。您可以在 npm 和 lodash 等中找到可重用的 debounce 函数。
【讨论】:
【参考方案3】:您实际上应该使用useLayoutEffect
来处理这种计算,因为它是在组件渲染时触发的(在计算完成之后,但在绘制完成之前),而不是在组件之后运行的useEffect已渲染。
【讨论】:
以上是关于调整浏览器大小时如何调用useEffect的主要内容,如果未能解决你的问题,请参考以下文章
JQuery:如何仅在完成调整大小后才调用 RESIZE 事件?