0

JavaScript code:

const [name, setName] = useState([]);
    const message = ["C", "h", "a", "s", "e", " ", "L", "i", "p", "s", "c", "o", "m", "b", " ", "W", "e", "b", " ", "D", "e", "v", "e", "l", "o", "p", "e", "r"]
    let letter = "";
    const displayName = () => {
        for(var i = 0; i<message.length; i++) {
            letter += message[i];
            console.log(letter)
            setName(letter);
            setTimeout(function(){console.log("work");}, 1000)
        }
    }
    useEffect(() => {
        displayName();
      }, []);

useEffect calls the displayName() function and should add a letter to name every second. When I run the app the full message is displayed in name. But I would like it to add a letter every second.

norbitrial
  • 14,716
  • 7
  • 32
  • 59
Chase L
  • 59
  • 1
  • 5
  • https://stackoverflow.com/questions/5226285/settimeout-in-for-loop-does-not-print-consecutive-values might also help. – jmargolisvt Dec 14 '19 at 17:47

2 Answers2

0

The below code worked for me:

  const string = ['t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 't'];
  const [name, setName] = useState("");

  useEffect(() => {
    if(name.length === string.length) {
      console.log("no more update")
      return;
    }
    const id = setTimeout(() => {
      setName(name + string[name.length])
    }, 1000);
    return () => clearInterval(id);
  }, [name]);
  return (<div>{name}</div>);

Two major points:

  • I think there is scope to make the code more pretty and human readable
  • If you are interested in understanding how the above code works I'd recommend that you go through Guide to useEffect. It is written by Dan Abramov.
subham
  • 43
  • 4
0

You can create a custom typewriter hook that accepts an array or a string, and uses setInterval() to iterate create the string by adding a character per interval:

const { useState, useRef, useEffect } = React;

const useTypewriter = (message = []) => {
  const [txt, setTxt] = useState('');
  
  const intervalRef = useRef();

  useEffect(() => {
    let index = 0; // init the index
    
    clearInterval(intervalRef.current); // clear the interval if message changes
    
    if(!message.length) return; // do nothing if message is empty

    intervalRef.current = setInterval(() => {
      setTxt(t => t + message[index]);
      
      index += 1;

      if(index === message.length) clearInterval(intervalRef.current); // clear interval when message ends
    }, 1000);

    return () => clearInterval(intervalRef.current); // clear interval if component is unmounted
  }, [message, intervalRef, setTxt]);
  
  return [txt];
};

const App = ({ message }) => {
  const [txt] = useTypewriter(message);
  
  return <div>{txt}</div>
};

const message = ["C", "h", "a", "s", "e", " ", "L", "i", "p", "s", "c", "o", "m", "b", " ", "W", "e", "b", " ", "D", "e", "v", "e", "l", "o", "p", "e", "r"];

ReactDOM.render(
  <App message={message} />,
  root
);
<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 id="root"></div>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209