当我想检查窗口对象的属性是不是在这里时,useEffect 中的无限循环

Posted

技术标签:

【中文标题】当我想检查窗口对象的属性是不是在这里时,useEffect 中的无限循环【英文标题】:Infinite for loop in useEffect when i want to check if a property of window object is here当我想检查窗口对象的属性是否在这里时,useEffect 中的无限循环 【发布时间】:2022-01-24 02:50:29 【问题描述】:

我想在加载时检查对象窗口是否具有属性 VL.refCode。 我为我的网站使用病毒循环,并在用户注册时将病毒循环放入 window.VL 对象的属性 refCode。

我在useEffect中放了一个for循环来检查这个属性是否存在,不幸的是它变成了一个无限循环。

  useEffect(() => 
        if(window.VL)
          if(window.VL.refCode)
            setCryptoButtonMessage(t('common:cryptoButton_already_register'))
            console.log('useEffect :user already register')
          
          else
            console.log('useEffect : window.vl.refcode not exist')
          
        
        else 
          setCryptoButtonMessage(t('common:cryptoButton_title_waitlist'))
        
// t is for translation with i18n
,[t]);

此解决方案不起作用,因为病毒循环在第一次渲染后创建 window.VL 对象 1 到 2 秒最大。 如果我设置了 setTimeout,对于使用移动设备/慢 3g/没有光纤的用户来说,这不是一个有效的解决方案

所以我使用这个解决方案

  useEffect(() => 
    let animation;
    const check = () => 
      console.log('je suis dans check');
      console.log('je suis dans for');
        if ((Object.prototype.hasOwnProperty.call(window.VL, 'refCode'))) 
        console.log('je trouve refCode ');
        setCryptoButtonMessage(t('common:cryptoButton_already_register'))
        cancelAnimationFrame(animation);
        return;
      
      animation = requestAnimationFrame(check);
    ;
    animation = requestAnimationFrame(check);  
  ,[t]);

但是这个解决方案在 window.VL.refCode 存在之前永远不会停止......并不是网站性能的最佳解决方案......

我尝试放置一个“模拟计时器”,但它变成了一个无限循环......

  useEffect(() => 
    for (let i = 1; i < 10000; i += 1) 

    let animation;
    const check = () => 

        if ((Object.prototype.hasOwnProperty.call(window.VL, 'refCode'))) 

        setCryptoButtonMessage(t('common:cryptoButton_already_register'))
        cancelAnimationFrame(animation);
        return;
      
      animation = requestAnimationFrame(check);
    ;
    animation = requestAnimationFrame(check);  
  
  ,[t]);

【问题讨论】:

【参考方案1】:

我不知道在窗口上创建对象时自动告知的任何方式 - 据我所知,唯一的方法是使用投票。如果是我,我会将轮询 ref 代码的逻辑抽象到一个新的钩子中:

import  useEffect, useRef, useState  from 'react';

const useRefCode = (pollTimeMillis = 1000) => 
    const timeoutRef = useRef(undefined);
    const [refCode, setRefCode] = useState(window.VL?.refCode);

    const cancelTimeout = () => 
        if (!timeoutRef.current) return;

        clearTimeout(timeoutRef.current);
        timeoutRef.current = undefined;
    ;

    useEffect(() => 
        if (refCode) return;

        setTimeout(() => 
            setRefCode(window.VL?.refCode || undefined), 
            pollTimeMillis
        );

        return cancelTimeout;
    , [refCode]);

    return refCode;

那么你的其他组件想要根据 ref 代码改变消息就变得很简单了:

const OtherComponent = () => 
    const refCode = useRefCode();

    const translationKey = refCode
        ? 'common:cryptoButton_already_register'
        : 'common:cryptoButton_title_waitlist';

    return (
        <div>t(translationKey)</div>
    );

【讨论】:

以上是关于当我想检查窗口对象的属性是不是在这里时,useEffect 中的无限循环的主要内容,如果未能解决你的问题,请参考以下文章

当我只想在挂载时运行一次时,useEffect 缺少依赖项

通过检查器窗口设置四元数

NodeJS检查对象属性是否为空。

如何检查窗口在 Windows 窗体中是不是真的可见?

如何快速检查对象数组中是不是存在属性值

PHP检查对象或类中是不是存在属性