skip to Main Content

I want to render a message inside a div of my React app simulating a chat. I fetch messages from the REST backend and then I made a function passing that message and I useEffect from React to achieve this
Here is my ChatMessage Function :

import React, { useState, useEffect } from "react";

export default function ChatMessage({ message }) {
 const [currentIndex, setCurrentIndex] = useState(0);
 const [currentMessage, setCurrentMessage] = useState("");

 useEffect(() => {
    const intervalId = setInterval(() => {
    setCurrentMessage(message.slice(0, currentIndex + 1));
    setCurrentIndex((prevIndex) => prevIndex + 1);
 }, 1000);
  return () => clearInterval(intervalId);
 }, [currentIndex, message]);

return (
<div class="py-6 border-b border-coolGray-100">
  <div class="flex flex-wrap justify-center -m-2">
    <p class="text-sm text-coolGray-800 font-semibold">{currentMessage}</p>
  </div>
</div>
 );
}

And this function is called from another function which is actually fetching this message from a API and passing it to this function like below :

{currentMessage ? (
            <ChatMessage message={currentMessage} />
          ) : (
            <div class="py-6 border-b border-coolGray-100">
              <div class="flex flex-wrap justify-center -m-2">
                <Comment
                  visible={true}
                  height="80"
                  width="80"
                  ariaLabel="comment-loading"
                  wrapperStyle={{}}
                  wrapperClass="comment-wrapper"
                  color="#fff"
                  backgroundColor="#F4442E"
                />
              </div>
            </div>
          )}

What I am doing wrong? because still I don’t see messages displayed one by one rather there is a slight delay and then the whole message is rendered at once. I tried increasing the interval to large values but still, the same result message appear at once with a small delay.

Possible solution
I updated code a bit and now I have desired effect however the spaces between each word is not preserved and that result into showing message with desired delay but without space. I need to have space preserved between complete words and sentences.

import React, { useState, useEffect } from "react";

export default function ChatMessage({ message }) {
 const [words, setWords] = useState([]);

 useEffect(() => {
  const messageString = message.toString();
const wordList = messageString.split(" ");
let i = 0;
const interval = setInterval(() => {
  setWords((prevWords) => [...prevWords, wordList[i]]);
  i++;
  if (i === wordList.length) {
    clearInterval(interval);
  }
}, 1000);

return () => clearInterval(interval);
}, [message]);

return (
<div class="py-6 border-b border-coolGray-100">
  <div class="flex flex-wrap justify-center -m-2">
    {words.map((word, index) => (
      <p class="text-sm text-coolGray-800 font-semibold" key={index}>
        {word}{" "}
      </p>
    ))}
  </div>
</div>
);   }

Please help me fix this last issue.

Output:
enter image description here

2

Answers


  1. Chosen as BEST ANSWER

    Ok I fixed it adding   inside that

    <p class="text-sm text-coolGray-800 font-semibold" key={index}>
        {word}&bsp;
      </p>
    

    Now it works alright.
    Result

    enter image description here


  2. The problem in your code is that you’re using the useEffect hook with currentIndex as a dependency. This causes a new interval to be created every time the currentIndex changes, leading to overlapping intervals and causing the message to appear at once with a small delay.

     useEffect(() => {
        let index = 0;
        const interval = setInterval(() => {
          if (index < message.length) {
            index++;
            setCurrentMessage((prevMessage) => {
              if (message[index - 1] !== undefined) {
                return prevMessage + message[index - 1];
              }
              return prevMessage;
            });
          } else {
            clearInterval(interval);
          }
        }, 1000);
    
        return () => {
          clearInterval(interval);
        };
      }, [message]);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search