调整浏览器大小时如何调用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 事件?

如何在浏览器宽度调整大小但保持相同高度时自动调整图像大小?

调整浏览器窗口大小时如何显示带点的文本? [复制]

调整大小时如何使 QTreeWidget 调用 sizeHint?

调整浏览器大小时,如何使部分中的对象保持居中?

调整浏览器窗口大小时如何停止页面刷新(跳转)?