React中使用setTimeout与useEffect实现延迟效果及解决DOM不更新问题
问题根因
你没有遵循React状态不可变的更新规则,直接原地修改状态不会触发组件重渲染:
- 两次对
activeChat.messages执行push操作都属于原地修改数组,activeChat状态的引用没有发生变化,React无法检测到状态变更,自然不会主动触发DOM更新。你看到的下次交互时才更新,是因为交互触发了message等其他状态的更新,顺带把之前未生效的修改渲染了出来。
修正方案
所有涉及activeChat的更新都需要调用setActiveChat,传入新的状态对象,禁止直接修改原状态:
- 调整提交消息的更新逻辑
- 调整useEffect内setTimeout中的更新逻辑,建议使用函数式更新避免闭包问题
修正后完整代码
import React, { useEffect, useState } from 'react'; import { render } from 'react-dom'; interface Chat { messages: string[]; poster: string; } const App = () => { const [activeChat, setActiveChat] = useState<Chat>({ poster: 'Adam', messages: ['one', 'two', 'three'], }); const [message, setMessage] = useState(''); const [isBotChat, setIsBotChat] = useState(false); useEffect(() => { if (isBotChat) { setIsBotChat(false); setTimeout(() => { // 使用函数式更新,基于最新状态生成新状态 setActiveChat(prev => ({ ...prev, messages: [...prev.messages, 'dsadsadsada'] })) console.log('setTimeout completed'); }, 500); } }, [isBotChat]); const handleSubmit = (e) => { e.preventDefault(); if (message !== '') { // 传入新的状态对象,触发重渲染 setActiveChat(prev => ({ ...prev, messages: [...prev.messages, message] })) setMessage(''); setIsBotChat(true); } }; return ( <div> <h1>Active Chat</h1> <div> {activeChat?.messages.map((m, index) => ( <div key={index}>{m}</div> ))} </div> <form onSubmit={handleSubmit}> <input type="text" value={message} onChange={(e) => setMessage(e.currentTarget.value)} /> <button type="submit">Send Message</button> </form> </div> ); }; render(<App />, document.getElementById('root'));
内容的提问来源于stack exchange,提问作者Jake
相关产品推荐
相关产品推荐

