React 惰性加载 useEffect

5

我在使用 useEffect 时遇到了获取 clientWidth 的问题。

有一个 lazyLoad,它会加载一个包含用户的页面。

import {Suspense, lazy} from 'react';

const UsersContainer = lazy (() => import ('./ users / users-container'));

const Index = (props) => {
    return (
        <Suspense fallback = {<div id = {'loading'} />}>
            <UsersContainer />
        </Suspense>
    )
}

export default Index;

UsersContainer有一个子组件dataTooltip,当用户名称无法适应块时,该组件将显示完整的用户名称。

import React, {useEffect, useRef} from 'react';

import '../common.scss';

const DataTooltip = ({title, ... props}) => {
    let ref = useRef ();

    useEffect (() => {
        if (ref.current.scrollWidth> ref.current.clientWidth) {
            ref.current.setAttribute ('data-tooltip', title)
        }
    });

    return (
        <div ref = {ref} className = {'tooltip'}>
            {
                React.cloneElement (props.children, {ref: ref})
            }
        </div>
    )
}

export default DataTooltip;

问题是什么?

UsersContainer 加载并在 DOM 中呈现后,它具有 'display: none',同时 DataTooltip 中的 useEffect 会异步触发。

结果是,DataTooltip 显示 clientWidth = 0,因为父元素具有 'display: none'

如何让 useEffectlazyLoad 删除 'display: none' 后起作用。

PS:useLayoutEffect 的效果相同,clientWidth=0


通过以下方式解决问题:

<Suspense fallback={<div id={'loading'}/>}>
   <Main/>
   <Acquaintance/>
   <UsersContainer/>
   <RegisterContainer/>
</Suspense>

to

<Suspense fallback={<div id={'loading'}/>}>
    <Main/>
</Suspense> 
            
<Suspense fallback={<div id={'loading'}/>}>
    <Acquaintance/> 
</Suspense>
            
<Suspense fallback={<div id={'loading'}/>}>
    <UsersContainer/>
</Suspense>
            
<Suspense fallback={<div id={'loading'}/>}>
    <RegisterContainer/>
</Suspense>
1个回答

0

我不确定这是否解决了你的问题 - 但是我立即注意到的一件事是,你的useEffect钩子缺少依赖数组。

import React, {useEffect, useRef} from 'react';
...

const DataTooltip = ({title, ... props}) => {
    let ref = useRef ();

    useEffect (() => {
        if (ref.current.scrollWidth> ref.current.clientWidth) {
            ref.current.setAttribute ('data-tooltip', title)
        }
    });

    return (...)
}

export default DataTooltip;

应该是:

import React, {useEffect, useRef} from 'react';
...

const DataTooltip = ({title, ... props}) => {
    let ref = useRef ();

    useEffect (() => {
        if (ref.current.scrollWidth> ref.current.clientWidth) {
            ref.current.setAttribute ('data-tooltip', title)
        }
    }, [ref]);

    return (...)
}

export default DataTooltip;

还要记住,每当ref发生变化时,组件都会重新渲染。根据useEffect钩子的文档,您应该始终将在useEffect钩子中使用的来自上层作用域的任何变量声明为依赖项数组的一部分。如果您不使用任何此类变量,则仍应传递一个空数组以防止运行无限循环。

没有帮助。 我在慢3G模式下加载页面。Lazy Load加载了用户,但设置了“display:none!Important”,此时用户得到了useEffect,由于“display:none!Important”,无法获取clientWidth。然后Lazy Load删除了“display:none”。 - TilikWebDeloper
是的,我并没有期望它会解决实际问题 - 这只是我注意到的一个问题,无论原始问题是否解决,都会对您的代码造成问题。 - Aasmund Berge Endresen
  1. LazyLoad使用'display: none'渲染了页面;
  2. 页面触发了useEffect;
  3. LazyLoad移除了'display: none'。
- TilikWebDeloper
但是你为什么要这样做呢?延迟加载内容并使用Suspense的目的是在组件准备好之前不会渲染内容。看起来你正在React.Lazy/Suspense解决方案中打包自己的延迟加载。 - Aasmund Berge Endresen
如果您非常有必要这样做,我建议在使用useEffect-hook之前将组件的样式设置为本地状态变量,并将此变量作为useEffect的依赖项进行注入,以便在更新时它会再次触发useEffect。如果在依赖项数组中放置任何变量,则会导致函数在这些变量发生更改时再次运行。 - Aasmund Berge Endresen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接