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.
2
Answers
Ok I fixed it adding inside that
Now it works alright.
Result
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.