调整浏览器大小时如何调用useEffect

How to call useEffect when browser is resized

我需要 bootstrap 个在 react-slick 旋转木马中等高的卡片。我从以下 post 中找到了解决方案:

下面是我的代码,它记录了包含 bootstrap 卡片的旋转木马 div 的高度。然后将捕获的高度作为道具传递给 bootstrap 卡片。

    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 添加事件侦听器(并删除它)。

const handleResize = () => {
   ...
}

React.useEffect(() => {
  window.addEventListener('resize', handleResize)

  return () => window.removeEventListener('resize', handleResize)
}, [])

这将在呈现组件时添加事件侦听器,并在未呈现时将其删除(useEffect 的 return 值在清理时为 运行)。每当第二个参数中的数组中的变量发生变化时,useEffect 将 运行(在这种情况下,它保留为空 [],因此它只会 运行 一次)。

此外,您应该考虑使用“去抖动”功能,而不是使用 setTimeout,this post explains how they work。您可以在 npm 和 lodash 等中找到可重用的去抖功能。

这对于很多项目来说是棘手但微不足道的。 你的useEffect会被触发一次,每次用户调整浏览器大小时都会触发里面的函数。

有时,当您调整浏览器大小时,您无法访问状态或设置状态(使用 useState),所以我喜欢将 window 的 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>)

}

你实际上应该使用 useLayoutEffect 来处理这种计算,因为它是在组件渲染时触发的(在计算完成后,但在绘制完成之前),而不是 useEffect,即在组件呈现后运行。