You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pushstate和popstate在条件渲染组件场景下无法正常工作如何解决

修复方案

原有代码的核心问题如下:

  • useState的状态更新是异步操作,在handleClick回调中刚执行setShow2(true)就判断if(show2),此时读取到的show2仍是更新前的旧值,永远无法触发show3的显示逻辑
  • 仅在组件挂载时调用了一次history.pushState,后续每次切换页面都没有将新的页面状态存入浏览器历史栈,导致前进后退时读取不到对应页面的状态
  • 监听popstate的useEffect没有添加空依赖数组,会在每次组件渲染时重复绑定事件;同时移除事件时传入的回调和绑定时的回调不是同一个引用,无法正确移除事件,会导致内存泄漏和逻辑冲突
  • popstate的状态判断逻辑仅覆盖了从show2切回show1的场景,没有处理show3切回show2等其余场景
  • 初始化的stateForHistory全为false,和组件挂载时show1=true的实际状态不匹配

下面是可直接运行的修复后代码:

import { useState, useEffect } from 'react';
import Screen1 from './Screen1';
import Screen2 from './Screen2';
import Screen3 from './Screen3';

export default function App() {
  // 用单个变量管理当前步骤,替代三个独立的show状态,更易维护
  const [currentStep, setCurrentStep] = useState(1);

  // 组件挂载时,存入初始页面状态
  useEffect(() => {
    window.history.pushState({ currentStep: 1 }, "", "");
  }, []);

  // 绑定popstate监听,仅挂载一次,卸载时正确移除
  useEffect(() => {
    const handlePopstate = (e) => {
      if (e.state?.currentStep) {
        setCurrentStep(e.state.currentStep);
      }
    };
    window.addEventListener("popstate", handlePopstate);
    return () => {
      window.removeEventListener("popstate", handlePopstate);
    };
  }, []);

  const handleNext = () => {
    const nextStep = currentStep + 1;
    if (nextStep > 3) return;
    // 更新页面状态
    setCurrentStep(nextStep);
    // 把新的步骤状态推入历史栈
    window.history.pushState({ currentStep: nextStep }, "", "");
  };

  return (
    <div className="App">
      <div id="screen-1">
        {currentStep === 1 && <Screen1 />}
      </div>
      <div id="screen-2">
        {currentStep === 2 && <Screen2 />}
      </div>
      <div id="screen-3">
        {currentStep === 3 && <Screen3 />}
      </div>

      {currentStep < 3 && (
        <button onClick={handleNext} id="btn">
          下一步
        </button>
      )}
    </div>
  );
}

核心实现逻辑说明:

  • 用单个currentStep变量管理当前展示的页面,替换三个独立的show状态,大幅简化状态判断逻辑
  • 每次点击下一步切换页面时,同步将新的步骤状态推入浏览器历史栈,保证历史栈的每一条记录都对应一个页面状态
  • popstate事件触发时,直接读取历史记录中存储的currentStep值更新状态即可,不需要额外写多分支判断
  • 事件监听逻辑仅在组件挂载时执行一次,卸载时用同一个回调引用移除事件,避免内存泄漏

内容的提问来源于stack exchange,提问作者Shahir Riaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 04:06:04