I am creating a bot to auto generate text when component is mounted, but I have a problem when setInterval in useEffect. As my expected, I want to concate each word from the string in an sample text and update it into state until everything is done but my code not works, I only get a first word Hello in screen. What I am wrong and how I can resolve this problem?
const sampleText = 'Hello my customer, how can I help you?';
const [conversation, setConversation] = useState([]);
useEffect(() => {
let i = 0;
const textToArray = sampleText.split(' ');
const newText = [...conversation];
// create initialization state for the first time
if (newText.length < 1) {
newText.push({
id: Math.random(),
reply_as: 'bot',
message: '',
});
}
// begining to generate bot message to reply
const timer = setInterval(() => {
if (i < textToArray.length) {
// concate a message property in latest item with each string in newText array
newText[newText.length - 1].message += textToArray[i];
setConversation(newText);
} else {
clearInterval(timer);
}
i++;
}, 300);
return () => clearInterval(timer);
}, []);
return (
<div className="message-list">
{conversation.map(item => (
<div>
<span>Sender: {item.reply_as}</span>
<p>{item.message}</p>
</div>
))}
</div>
)
>Solution :
You need to provide a new array reference, otherwise React doesn’t re-render the component.
setConversation([...newText]);
The first setConversation triggered a re-render, that’s why "Hello" was shown, but the following calls to setConversation didn’t trigger a re-render because the array reference stayed the same.