如何基于页面索引标记问卷问题完成状态?代码异常求助
问题描述
我有一个包含11个问题的表单,需要构建进度条来更新每个问题对应的对象数组,标记其完成/未完成状态:
- 仅点击「下一步」时标记当前页面问题为完成
- 点击「上一步」时标记当前页面问题为未完成
示例流程:
- 处于问题1(索引0)时状态为未完成,进入问题2(索引1)后问题1变为完成
- 处于问题3(索引2)时状态为未完成,返回问题2(索引1)后问题2变为未完成
当前代码逻辑大致可行,但存在异常:连续点击两次「下一步」后点击「上一步」,需点击两次「上一步」才能正确更新状态。
代码如下:
const [currentPage, setCurrentPage] = useState(0); const [progress, setProgress] = useState([ { pageIndex: 0, completed: false }, { pageIndex: 1, completed: false }, { pageIndex: 2, completed: false }, { pageIndex: 3, completed: false }, { pageIndex: 4, completed: false }, { pageIndex: 5, completed: false }, { pageIndex: 6, completed: false }, { pageIndex: 7, completed: false }, { pageIndex: 8, completed: false }, { pageIndex: 9, completed: false }, { pageIndex: 10, completed: false }, ]); const handleNavButtonNext = () => { // Mark previous page as complete const newProgress = [...progress]; newProgress[currentPage].completed = true; setProgress(newProgress); // Move to next page setCurrentPage(currentPage + 1); }; const handleNavButtonBack = () => { // Mark current page as incomplete const newProgress = [...progress]; newProgress[currentPage].completed = false; setProgress(newProgress); // Move to previous page setCurrentPage(currentPage - 1); };
问题原因
核心问题在于React的useState状态更新是异步且批量处理的,当你连续点击按钮时,事件处理函数中捕获到的currentPage和progress都是更新前的旧值,导致状态更新逻辑出错:
- 连续点击两次「下一步」时,第二次点击触发
handleNavButtonNext时,currentPage还没完成第一次的更新(依然是初始的旧值),所以两次操作都标记了同一个页面索引为完成,而不是依次标记前一页并跳转。 - 后续点击「上一步」时,需要多次点击才能抵消之前错误的状态更新,最终让进度状态回到正确逻辑。
修复方案
使用函数式更新来获取最新的状态值,确保每次状态更新都基于当前最新的状态,而不是捕获到的旧值。修改后的代码如下:
const [currentPage, setCurrentPage] = useState(0); const [progress, setProgress] = useState([ { pageIndex: 0, completed: false }, { pageIndex: 1, completed: false }, { pageIndex: 2, completed: false }, { pageIndex: 3, completed: false }, { pageIndex: 4, completed: false }, { pageIndex: 5, completed: false }, { pageIndex: 6, completed: false }, { pageIndex: 7, completed: false }, { pageIndex: 8, completed: false }, { pageIndex: 9, completed: false }, { pageIndex: 10, completed: false }, ]); const handleNavButtonNext = () => { setCurrentPage(prevPage => { // 基于最新的旧页面索引,标记为完成 setProgress(prevProgress => { const newProgress = [...prevProgress]; newProgress[prevPage].completed = true; return newProgress; }); return prevPage + 1; }); }; const handleNavButtonBack = () => { setCurrentPage(prevPage => { // 基于最新的当前页面索引,标记为未完成 setProgress(prevProgress => { const newProgress = [...prevProgress]; newProgress[prevPage].completed = false; return newProgress; }); return prevPage - 1; }); };
逻辑说明
- 在更新
currentPage时,使用回调函数prevPage => ...获取最新的页面索引,确保每次跳转都是基于当前最新的页面位置。 - 同时在回调内部更新
progress,使用prevProgress获取最新的进度数组,确保标记的是正确的页面索引(跳转前的页面)。
这样就能避免异步状态更新导致的旧值捕获问题,保证每次点击按钮都能正确更新进度状态。
内容的提问来源于stack exchange,提问作者FlexLuthor
相关产品推荐
相关产品推荐

