React中可直接向数组push元素,为何还要使用setState?
为什么React中必须用
setMessages更新状态,而不能直接修改? 先看你提供的组件代码:
function ChatWindow() { const [messages, setMessages] = useState([]) const [newMessage, setNewMessage] = useState('') function sendMessage(e) { e.preventDefault(); messages.push(newMessage) // 直接修改状态 setNewMessage('') } function sendMessage2(e) { e.preventDefault(); setMessages([...messages, newMessage]) // 正确的状态更新方式 setNewMessage('') } }
你发现两种方法都能显示新增消息,是因为调用setNewMessage触发了组件重渲染——此时你直接修改的messages数组已经有了新值,所以渲染时会显示更新后的内容。但这只是巧合,直接修改状态的做法存在严重隐患:
- 重渲染不可靠:如果没有
setNewMessage这个触发重渲染的操作,直接messages.push后,组件不会重新渲染,页面完全不会更新。React是通过检测状态的引用变化来决定是否重渲染的,直接修改数组(比如push、splice)不会改变数组的引用,React认为状态没变化,就不会触发重渲染。 - 异步状态更新会出错:React的状态更新是异步批量处理的,当你后续依赖
messages的当前值做操作时,直接修改的状态不会被React的状态快照捕获。比如连续两次调用直接修改的方法,或者在useEffect里监听messages变化,你会发现useEffect不会触发,因为数组引用没改变,React认为状态没更新。 - 调试和维护困难:直接修改状态会让状态变化变得不可追踪,React DevTools里看不到这次状态更新的记录,当出现bug时,你很难回溯状态是如何变化的。
而setMessages([...messages, newMessage])这种方式,是创建了一个新的数组,改变了状态的引用,React能准确检测到状态变化,从而触发可靠的重渲染,同时也能在DevTools里清晰看到状态更新的轨迹,符合React的状态不可变原则。
内容的提问来源于stack exchange,提问作者Nitish
相关产品推荐
相关产品推荐

