使用 useEffect 和 setInterval 一個接一個地打印一個字母 (print one letter after the other with useEffect and setInterval)


問題描述

使用 useEffect 和 setInterval 一個接一個地打印一個字母 (print one letter after the other with useEffect and setInterval)

我試圖了解使用 useEffect 創建每隔一段時間(如打字機)打印一個字母的組件的最佳方法是什麼setInterval

  • 這樣會導致interval永遠運行:
function Printer({ str }) {
  const [val, setVal] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setVal((preVal) => preVal + 1);
    }, 200);
    return () => {
      clearInterval(interval);
    };
  }, [str]);

  return <div>{str.slice(0, val)}</div>;
}
  • 而這個會抱怨val 是 useEffect 依賴數組的缺失依賴:
function Printer({ str }) {
  const [val, setVal] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      if (val < str.length) {
        setVal((preVal) => preVal + 1);
      } else {
        clearInterval(interval);
      }
    }, 200);
    return () => {
      clearInterval(interval);
    };
  }, [str]);

  return <div>{str.slice(0, val)}</div>;
}
  • 如果將 val 添加到依賴數組中 ‑ 我們設置了多個冗餘間隔(並刪除它們,所以這感覺有點糟糕):
function Printer({ str }) {
  const [val, setVal] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      if (val < str.length) {
        setVal((preVal) => preVal + 1);
      } else {
        clearInterval(interval);
      }
    }, 200);
    return () => {
      clearInterval(interval);
    };
  }, [str, val]);

  return <div>{str.slice(0, val)}</div>;
}

不確定我是否遺漏了有關 useEffect 的內容,依賴數組或者這只是 linter 拖釣我。


參考解法

方法 1:

You can use useRef() to store the end condition (stop):

const { useState, useRef, useEffect } = React;

function Printer({ str }) {
  const [val, setVal] = useState(0);
  const stop = useRef();

  useEffect(() => {
    stop.current = val === str.length;
  });

  useEffect(() => {
    const interval = setInterval(() => {
      if(stop.current) clearInterval(interval);
      else setVal((preVal) => preVal + 1);
    }, 200);
    return () => {
      clearInterval(interval);
    };
  }, []);

  return <div>{str.slice(0, val)}</div>;
}

ReactDOM.render(
  <Printer str="cats" />,
  root
);
<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="root"></div>

方法 2:

Put both the string prop and the state index into the dependency array, and to make things easier, use a timeout instead of an interval. Also add a callback that runs when the string prop changes so you can reset the state index to 0.

const Printer = ({ str }) => {
  const [index, setIndex] = React.useState(0);
  React.useEffect(() => {
    if (index < str.length) {
      const timeoutId = setTimeout(() => {
        setIndex(index + 1);
        return () => clearTimeout(timeoutId);
      }, 200);
      return () => clearTimeout(timeoutId);
    }
  }, [index, str]);
  React.useEffect(() => {
    setIndex(0);
  }, [str]);
  return <div>{str.slice(0, index)}</div>;
}
const App = () => {
  const [str, setStr] = React.useState('');
  return (
    <div>
      <input value={str} onChange={(e) => setStr(e.currentTarget.value)} />
      <Printer str={str} />
    </div>
  );
};
ReactDOM.render(<App/>, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react‑dom@16/umd/react‑dom.development.js"></script>
<div class='react'></div>

(by mikey.naglerOri DroriCertainPerformance)

參考文件

  1. print one letter after the other with useEffect and setInterval (CC BY‑SA 2.5/3.0/4.0)

#react-hooks #setInterval #use-effect #reactjs






相關問題

使用反應鉤子useState更新功能的正確方法是什麼? (What is the correct way to use react hook useState update function?)

測試 react-redux useSelector (testing react-redux useSelector)

從深度嵌套的組件更新狀態而不重新渲染父組件 (Update state from deeply nested component without re-rendering parents)

React Hook useEffect 缺少依賴項(在上下文中定義的函數) (React Hook useEffect has a missing dependency (function defined in context))

類型“IntrinsicAttributes”(自定義掛鉤)上不存在 React 屬性 (React Property does not exist on type 'IntrinsicAttributes' (custom hook))

即使驗證要求無效,數據仍在發送,解決此問題的最佳方法是什麼? (Data is sending even if validation requirements are not valid, whats the best way to approach this?)

如何在使用狀態掛鉤更新狀態時覆蓋具有相同鍵的對象 (How can overwrite objects that have the same key in updating State with state hooks)

在 useEffect 中,調用更新時是否會更新所有變量? (In useEffect, do all variables get updated when an update is called?)

反應鉤子,不會將選中的屬性更改為複選框 (React hooks, does not change the checked property to checkbox)

在 reactJS 中動態設置圖像 src (Setting image src dynamically in reactJS)

如何防止組件在反應中重新渲染? (How to prevent component from re-rendering in react?)

使用 useEffect 和 setInterval 一個接一個地打印一個字母 (print one letter after the other with useEffect and setInterval)







留言討論