【问题标题】:React: setInterval Not working after one interval反应:setInterval 在一个间隔后不起作用
【发布时间】:2021-07-03 17:29:39
【问题描述】:

我的目标:

我正在尝试构建一个组件,当您给它props.itemsprops.fadeEvery 时,它将充当文本旋转器。我最终希望它淡入淡出,但我的window.setInterval 有问题。

可能的问题:

我在useEffect 挂钩中调用setIndex,但这不是一个好习惯吗?我如何让它无限地遍历数组项?

TextFade.tsx

// Imports: Dependencies
import React, { useState, useEffect } from 'react';

// TypeScript Type: Props
interface Props {
  items: Array<string>,
  fadeEvery: number,
};

// Component: Text Fade
const TextFade: React.FC<Props> = (props): JSX.Element => {
  // React Hooks: State
  const [ index, setIndex ] = useState<number>(0);

  // React Hooks: Lifecycle Methods
  useEffect(() => {
    const timeoutID: number = window.setInterval(() => {
      // End Of Array
      if (index > props.items.length) {
        // Set Data
        setIndex(0);
      }
      else {
        // Set Data
        setIndex(index + 1);
      }
    }, props.fadeEvery * 1000);

    // Clear Timeout On Component Unmount
    return () => window.clearTimeout(timeoutID);
  }, []);

  return (
    <div id="text-fade-container">
      <p id="text-fade-text">{props.items[index]}</p>
    </div>
  );
};

// Exports
export default TextFade;

【问题讨论】:

  • index 在所谓的闭包中。你的使用效果被告知只渲染一次[]..所以你需要使用setIndex的回调版本
  • 再提醒一下,如果您使用setInterval,最好使用clearInterval 而不是clearTimeout。 MDN 确实说 ID 是共享的,但为了清楚起见,最好让它们保持同步。

标签: javascript html reactjs typescript setinterval


【解决方案1】:

您的索引值取自初始关闭,除非再次调用 useEffect 回调,否则它不会更新。您可以改为使用函数式方式来更新状态

useEffect(() => {
    const timeoutID: number = window.setInterval(() => {
      // End Of Array 
      setIndex(prevIdx => {
         if (prevIdx > props.items.length) {
            // Set Data
             return 0;
         }
         else {
           // Set Data
           return prevIdx + 1;
          }
      })
      
    }, props.fadeEvery * 1000);

    // Clear Timeout On Component Unmount
    return () => window.clearTimeout(timeoutID);
  }, []);

【讨论】:

  • 完美!感谢您的帮助!
【解决方案2】:

下面我使用 setState 的回调版本敲了一个 sn-p,这避免了使用 useEffect 和 [].. 时遇到的关闭问题。

const {useState, useEffect} = React;


const TextFade = (props) => {
  // React Hooks: State
  const [ index, setIndex ] = useState(0);

  // React Hooks: Lifecycle Methods
  useEffect(() => {
    const timeoutID: number = window.setInterval(() => {
      // End Of Array
      setIndex(index => 
        index + 1 >= props.items.length
          ? 0
          : index + 1);
    }, props.fadeEvery * 1000);

    // Clear Timeout On Component Unmount
    return () => window.clearInterval(timeoutID);
  }, []);

  return (
    <div id="text-fade-container">
      <p id="text-fade-text">{props.items[index]}</p>
    </div>
  );
};



ReactDOM.render(<TextFade items={['one','two', 'three']} fadeEvery={1}/>, document.querySelector('#mount'));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

<div id="mount"></div>

【讨论】:

    【解决方案3】:

    正如@Keith 所说:

    index 位于所谓的闭包中。你的使用效果被告知 只渲染一次 [].. 所以你需要使用回调版本 设置索引

    所以,您的 useEffect 钩子将是:

    useEffect(() => {
        const timeoutID: number = window.setInterval(() => {
          // End Of Array
          if (index > props.items.length) {
            // Set Data
            setIndex(0);
          } else {
            // Set Data
            setIndex(index + 1);
          }
        }, props.fadeEvery * 1000);
    
        // Clear Timeout On Component Unmount
        return () => window.clearTimeout(timeoutID);
      }, [index]);
    

    这是CodeSandbox 的工作演示。

    【讨论】:

    • 不要依赖cmets。它们经常被删除。
    • 好的。谢谢,@HereticMonkey。
    • 这是使用 useEffect 的依赖而不是 setState 回调,当然是另一种选择。您甚至可以将setInterval 更改为setTimeout。如果 useEffect 可能很耗时,我什至会说这是更好的选择。
    猜你喜欢
    • 1970-01-01
    • 2020-11-16
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 2022-07-21
    • 2018-12-22
    • 1970-01-01
    • 2021-12-30
    相关资源
    最近更新 更多