React点击按钮更新状态无法获取最新值,状态被替换而非追加
React状态数组追加更新失败的解决方法
问题描述
timeline是一个数组状态,用于渲染元素列表。点击按钮时,期望将新内容追加到状态数组中,但实际效果是替换原有内容(比如点击Update按钮后,页面内容从Hi+按钮变成Bye,而非Hi+按钮+Bye)。尝试过用JSON.stringify和JSON.parse深拷贝,但因为数组中包含JSX元素无法序列化,所以该方法无效。
最小可复现代码:
JS代码
const App = () => { const [timeline, setTimeline] = React.useState([]); let timelineTemp = ['Hi']; React.useEffect(() => { timelineTemp.push( <button key="static" onClick={update}>Update</button> ); setTimeline([...timeline, ...timelineTemp]); }, []); const update = () => { setTimeline([...timeline, 'Bye']); }; return timeline; }; ReactDOM.render(<App />, document.getElementById("root"));
HTML代码
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="root"></div>
问题原因
核心是闭包捕获旧状态值:
- 组件首次渲染时,
update函数捕获了当时的timeline初始状态(空数组)。 - 后续点击按钮调用
update时,始终使用的是首次渲染时捕获的旧timeline值,而非最新状态,导致每次更新都是基于空数组拼接'Bye',看起来像是替换了原有内容。
解决方案
使用React的函数式状态更新,直接基于最新的前序状态进行修改,避免闭包带来的旧值问题:
修改update函数为:
const update = () => { setTimeline(prevTimeline => [...prevTimeline, 'Bye']); };
修改后的完整JS代码
const App = () => { const [timeline, setTimeline] = React.useState([]); let timelineTemp = ['Hi']; React.useEffect(() => { timelineTemp.push( <button key="static" onClick={update}>Update</button> ); setTimeline([...timeline, ...timelineTemp]); }, []); const update = () => { // 使用函数式更新,基于最新的前序状态追加内容 setTimeline(prevTimeline => [...prevTimeline, 'Bye']); }; return timeline; }; ReactDOM.render(<App />, document.getElementById("root"));
这样每次点击按钮时,都会基于当前最新的timeline状态去追加'Bye',实现预期的追加效果。
内容的提问来源于stack exchange,提问作者ADUCJ
相关产品推荐
相关产品推荐

