英文:
State not update inside setInterval in React useEffect
问题
我正在创建一个机器人,在组件挂载时自动生成文本,但是在useEffect
中使用setInterval
时出现了问题。根据我的期望,我想要将字符串中的每个单词连接在一个示例文本中,并将其更新到状态,直到所有操作完成,但我的代码不起作用,屏幕上只显示第一个单词Hello
。我做错了什么,如何解决这个问题?
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];
// 创建第一次的初始化状态
if (newText.length < 1) {
newText.push({
id: Math.random(),
reply_as: 'bot',
message: '',
});
}
// 开始生成机器人消息以回复
const timer = setInterval(() => {
if (i < textToArray.length) {
// 将最新项的消息属性与 newText 数组中的每个字符串连接起来
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>
)
以上是您提供的代码的翻译部分。
英文:
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>
)
答案1
得分: 4
你需要提供一个新的数组引用,否则 React 不会重新渲染组件。
setConversation([...newText]);
第一个 `setConversation` 触发了重新渲染,这就是为什么显示了 "Hello",但后续对 `setConversation` 的调用没有触发重新渲染,因为数组引用保持不变。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论