【问题标题】:React Lazy Load useEffectReact 延迟加载 useEffect
【发布时间】:2021-05-30 05:02:36
【问题描述】:

我在从 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;

有什么问题?

UsersContainerDOM中加载并渲染后,有'display: none',同时 DataTooltip 中的 useEffect 是异步触发的。

结果,DataTooltipclientWidth = 0,因为父级有 'display: none'

lazyLoad 移除 'display: none' 后如何让 useEffect 工作。

PS:useLayoutEffect 也一样,clientWidth = 0


这样解决了问题:

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

<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>

【问题讨论】:

    标签: reactjs react-hooks lazy-loading use-effect


    【解决方案1】:

    我不知道这是否能解决您的问题 - 但我立即注意到的一件事是您缺少 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 模式加载页面。延迟加载加载的用户,但设置“显示:无!重要”,此时用户得到了 useEffect,由于“显示:无!重要的'。然后延迟加载删除“显示:无”。
    • 是的,我没想到它会解决实际问题——这只是我注意到的一个问题,无论原始问题是否得到解决,它都会导致您的代码出现问题
    • 1. LazyLoad 使用 'display: none' 呈现页面; 2.页面触发useEffect; 3. LazyLoad 移除'display: none'。
    • 但是你为什么要这样做呢?延迟加载内容和使用 Suspense 的目的是它不会在组件准备好之前渲染内容。看来您正在 React.Lazy/Suspense 解决方案中打包自己的延迟加载。
    • 如果你绝对必须这样做 - 我会设置一个本地状态变量来检查你的组件的样式在你的 useEffect-hook 之前,然后将此变量作为 @987654326 的依赖项注入@,所以当它更新时,它会触发 useEffect 再次运行。您放入依赖数组中的任何变量都将导致函数在更改后再次运行。
    猜你喜欢
    • 2020-01-07
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 2021-12-25
    • 2016-12-08
    • 2020-12-16
    • 2021-06-14
    相关资源
    最近更新 更多