React Array State Update Not Consistant

Using setInterval and an index to keep track of position. Check out example here https://codesandbox.io/s/bold-wind-sq8lb?file=/src/App.js:

import { useEffect, useState } from "react";

export default function App() {
  const sentence =
    "The story, characters, and events, in this game are entirely fictional. Any similarities to actual people, places and events are entirely coicidental.";

  const [dialogue, setDialogue] = useState("");
  const [index, setIndex] = useState(0);
  const letterArray = sentence.split(/\b/);

  const handleChangeValue = () => {
    if (letterArray[index] !== undefined) {
      setDialogue((dialogue) => dialogue + letterArray[index]);
    }
  };

  useEffect(() => {
    // update the dialogue here
    const interval = setInterval(() => {
      if (index < letterArray.length) {
        setIndex((index) => index + 1);
      }
    }, 100);
    return () => clearInterval(interval);
  });

  useEffect(() => {
    // update the dialogue here
    handleChangeValue();
    console.log(`New dialogue: ${dialogue}`);
  }, [index]);

  return (
    <div className="App">
      <p>{dialogue}</p>
    </div>
  );
}

Don't use setTimeout directly within the React component return, it will setup massive of timers into Javascript runtime and never be recycled.

If the setTimeout or even setInterval is what you needed, wrap them with useEffect would be the idea

By guessing what you're trying to do, this is an example code. It will display a word every 0.5s to the screen till the end of params

export default function DialogueBox(params){

  const params = "The story, characters, and events, in this game are entirely fictional. Any similarities to actual people, places and events are entirely coicidental.";
  const letters = params.split(/\b/)

  const [dialogue, setDialogue] = useState([]);

  useEffect(() => {
    const timers = []

    letters.forEach((letter, index) => {
      timers.push(
        setTimeout(() => {
          console.log(`Display at 500*${index} ms: ${letter}`)
          setDialogue(originDialogue => [...originDialogue, letter])
        }, 500*index)
      )
    })

    return () => timers.map((timer) => clearTimeout(timer))  // clean up timers to prevent memory leak
  }, [params]) // params here as dependency of useEffect, see offical document for useEffect for detail

  return (
    <div className="dialogueBox">
      {dialogue.map((letter) => (
        <p>{letter}</p>
      ))}
    </div>
  )
}