Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

161
Visualizações
How to setup multiline typing effect for react with delay between lines

I have created a class-based component in React that starts a multiline typing effect on load.

It is working alright, but the issue is that both the lines start typing simultaneously, which makes sense given the nature of how setTimout is executed.

So I'm looking for any ideas/suggestions on how to make it wait for the first line to finish being typed before going on to the next one?

import React from 'react'
import TerminalCursor from 'icons/TerminalCursor'
import TerminalPrompt from 'icons/TerminalPrompt'
import { v4 as uuidv4 } from 'uuid'

type MyProps = {}
type MyState = {
  introArray: string[]
}
class Terminal extends React.Component<MyProps, MyState> {
  state: MyState = {
    introArray: [],
  }

  componentDidMount() {
    // Data to import from sanity
    const starterArray = [
      'The very first line that needs to finish typing before going to the next line',
      'The second line that needs to start being typed after the first line',
    ]

    const createTypingEffect = (text: string, index: number) => {
      for (let i = 0; i < text.length; i++) {
        setTimeout(() => {
          let arrayCopy = this.state.introArray.slice()
          this.setState((state) => ({
            introArray: [...state.introArray.slice(0, index), arrayCopy[index] + text[i], ...state.introArray.slice(index + 1)],
          }))
        }, 100 * i)
      }
    }
    starterArray.forEach((starterText, starterIndex) => {
      // Setting empty string for each line in starterArray so we dont get undefined as first character
      this.setState((state) => ({
        introArray: [...state.introArray, ''],
      }))

      // Need to wait for first line to finish typing before starting the second line
      createTypingEffect(starterText, starterIndex)
    })
  }
  render() {
    return (
      <div className="w-1/2 h-1/2 p-5 flex items-start justify-start bg-clip-padding bg-slate-900 backdrop-filter backdrop-blur-xl bg-opacity-60 border border-gray-900 rounded">
        <div className="flex flex-col">
          {this.state.introArray.map((introLine) => (
            <div className="flex items-center" key={uuidv4()}>
              <TerminalPrompt />
              <p className="text-white">{introLine}</p>
            </div>
          ))}
          {/* Actual prompt starts here */}
          <div className="flex">
            <TerminalPrompt />
            <TerminalCursor />
          </div>
        </div>
      </div>
    )
  }
}

export default Terminal

Here is a sandbox demo (not sure why some characters are being repeated in the sandbox, don't have this issue on local...)

https://codesandbox.io/s/recursing-star-iohjw9?file=/src/Terminal.tsx

about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

You need to use an asynchronous approach for this kind of tasks ( I did not check your typing effect logic, I just made the whole process asynchronous ):

import React from "react";

type MyProps = {};
type MyState = {
  introArray: string[];
};
class Terminal extends React.Component<MyProps, MyState> {
  state: MyState = {
    introArray: []
  };

  componentDidMount() {
    // Data to import from sanity
    const starterArray = [
      "The very first line that needs to finish typing before going to the next line",
      "The second line that needs to start being typed after the first line"
    ];

    const createTypingEffect = async (text: string, index: number) => {
      return Promise.all(
        text.split("").map(
          (c, i) =>
            new Promise((res) => {
              setTimeout(() => {
                let arrayCopy = this.state.introArray.slice();
                this.setState((state) => ({
                  introArray: [
                    ...state.introArray.slice(0, index),
                    arrayCopy[index] + c,
                    ...state.introArray.slice(index + 1)
                  ]
                }));
                res(null);
              }, 100 * i);
            })
        )
      );
    };

    const cycle = async () => {
      let i = 0;
      for (const starterText of starterArray) {
        // Setting empty string for each line in starterArray so we dont get undefined as first character
        this.setState((state) => ({
          introArray: [...state.introArray, ""]
        }));

        await createTypingEffect(starterText, i);
        i++;
      }
    };

    cycle();
  }
  render() {
    console.log(this.state.introArray);
    return (
      <div className="w-1/2 h-1/2 p-5 flex items-start justify-start bg-clip-padding bg-slate-900 backdrop-filter backdrop-blur-xl bg-opacity-60 border border-gray-900 rounded">
        <div className="flex flex-col">
          {this.state.introArray.map((introLine, index) => (
            <div className="flex items-center" key={index}>
              <p className="text-white">{introLine}</p>
            </div>
          ))}
        </div>
      </div>
    );
  }
}

export default Terminal;

You can use several approaches to handle the async logic, I used a Promise.all approach here, giving an incremental timer to the timeout, just to follow what you were doing. An alternative solution is to use a simple for...of loop and await for a promisified timeout inside. That way you don't need to give an incremental time to the timeout, since they will be executed relatively synchronously.

The working demo is HERE ( Working snippet can't be added here since SO has no TS support)

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda