反应:setInterval 在一个间隔后不起作用

时间:2021-04-07 20:49:28

标签: javascript html reactjs typescript setinterval

我的目标:

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

可能的问题:

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

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;

3 个答案:

答案 0 :(得分:2)

您的索引值取自初始闭包,除非再次调用 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);
  }, []);

答案 1 :(得分:1)

正如@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 的工作演示。

答案 2 :(得分:1)

下面我使用 setState 的回调版本编写了一个片段,这避免了使用带有 [] 的 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>