Trying to create a typing effect on reactjs

Could make it a class component like this:

class Typer extends React.Component {

  static defaultProps = {
    heading: '',
    dataText: []
  }

  constructor(props) {
    super(props);

    this.state = {
      text: '',
      isDeleting: false,
      loopNum: 0,
      typingSpeed: 150
    }
  }

  componentDidMount() {
    this.handleType();
  }

  handleType = () => {
    const { dataText } = this.props;
    const { isDeleting, loopNum, text, typingSpeed } = this.state;
    const i = loopNum % dataText.length;
    const fullText = dataText[i];

    this.setState({
      text: isDeleting ? fullText.substring(0, text.length - 1) : fullText.substring(0, text.length + 1),
      typingSpeed: isDeleting ? 30 : 150
    });

    if (!isDeleting && text === fullText) {
      
      setTimeout(() => this.setState({ isDeleting: true }), 500);
      
    } else if (isDeleting && text === '') {
      
      this.setState({
        isDeleting: false,
        loopNum: loopNum + 1
      });
      
    }

    setTimeout(this.handleType, typingSpeed);
  };

  render() {    
    return (
      <h1>{ this.props.heading }&nbsp;
        <span>{ this.state.text }</span>
        <span id="cursor"/>
      </h1>
    );
    
  }
}

ReactDOM.render(
  <Typer
    heading={'Things I want to type:'}
    dataText={["WELCOME TO MY WORLD","THIS IS MY WEBSITE","I AM AT YOUR SERVICE"]} 
  />, 
  document.getElementById('app')
);
@import url('https://fonts.googleapis.com/css?family=VT323');
body {
  font-family: 'VT323', monospace;
  background-color: #003B00;
  padding: 1em 2em;
}

h1 {
  color: #00FF41;
}

#cursor {
  border-left: .1em solid #00FF41;
  animation: blink .7s steps(1) infinite;
}

@keyframes blink {
  50% {
    border-color: transparent;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>

<div id="app"></div>

Link to pen: https://codepen.io/AliKlein/pen/aPyKjy JSFiddle: https://jsfiddle.net/am9qke3v/


If you want to use hooks to accomplish this, you can do something like this:

(big thanks to @AliKlein for the inspiration)

const { render } = ReactDOM;
const { useState, useEffect } = React;

const CONSTANTS = {
  DELETING_SPEED: 30,
  TYPING_SPEED: 150,
}

function TypeWriter({ messages, heading }) {
  const [state, setState] = useState({
    text: "",
    message: "",
    isDeleting: false,
    loopNum: 0,
    typingSpeed: CONSTANTS.TYPING_SPEED,
  });

  useEffect(() => {
    let timer = "";
    const handleType = () => {
      setState(cs => ({
        ...cs, // cs means currentState
        text: getCurrentText(cs),
        typingSpeed: getTypingSpeed(cs)
      }));
      timer = setTimeout(handleType, state.typingSpeed);
    };
    handleType();
    return () => clearTimeout(timer);
  }, [state.isDeleting]);

  useEffect(() => {
    if (!state.isDeleting && state.text === state.message) {
      setTimeout(() => {
        setState(cs => ({
          ...cs,
          isDeleting: true
        }))
      }, 500);
    } else if (state.isDeleting && state.text === "") {
      setState(cs => ({
        ...cs, // cs means currentState
        isDeleting: false,
        loopNum: cs.loopNum + 1,
        message: getMessage(cs, messages)
      }));
    }
  }, [state.text, state.message, state.isDeleting, messages]);

  function getCurrentText(currentState) {
    return currentState.isDeleting
      ? currentState.message.substring(0, currentState.text.length - 1)
      : currentState.message.substring(0, currentState.text.length + 1);
  }

  function getMessage(currentState, data) {
    return data[Number(currentState.loopNum) % Number(data.length)];
  }

  function getTypingSpeed(currentState) {
    return currentState.isDeleting
      ? CONSTANTS.TYPING_SPEED
      : CONSTANTS.DELETING_SPEED;
  }

  return (
    <h1>
      {heading}&nbsp;
        <span>{state.text}</span>
      <span id="cursor" />
    </h1>
  );
}

let msgs = ["WELCOME TO MY WORLD","THIS IS MY WEBSITE","I AM AT YOUR SERVICE"];
render(<TypeWriter heading={"Things I want to type:"} messages={msgs} />, document.body);
@import url('https://fonts.googleapis.com/css?family=VT323');
body {
  font-family: 'VT323', monospace;
  background-color: #003B00;
  padding: 1em 2em;
}

h1 {
  color: #00FF41;
}

#cursor {
  border-left: .1em solid #00FF41;
  animation: blink .7s steps(1) infinite;
}

@keyframes blink {
  50% {
    border-color: transparent;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>


You are returning a single item from your function on the first iteration of your loop. This is incorrect. You need to return an array of JSX objects:

const content =()=>{
  const message =["WELCOME TO MY WORLD","THIS IS MY WEBSITE","I AM AT YOUR SERVICE"];
  let i =0 ;
  let jsxArray = [];
  for(i=0; i<message.length;i++){
    jsxArray.push(
      <div className='background'>
        <h1 className="typewriter">
            {message[i]}    
        </h1>
      </div>
     );
  }
  return jsxArray;
}