React使用react-router-dom存储筛选参数时浏览器返回功能失效
异常原因
- 多余的
popstate事件监听逻辑导致点击返回时多回退多层历史记录:popstate事件本身就是用户点击浏览器返回/前进按钮触发的系统事件,你在回调里额外调用history.goBack(),相当于每次点返回会执行两次回退操作。如果你的筛选页在历史栈里有效记录较少,两次回退就会直接跳出筛选页回到浏览器主页。 - 没有同步路由参数到本地筛选状态:当点击返回导致
location.search变化时,你本地的Standard/Hobbies/Responsibility三个状态没有从最新的路由参数里取值,就算回退成功,页面也不会显示上一次的筛选条件。 - 组件初始化时冗余的
history.push操作:只要组件挂载,依赖QueryString的useEffect就会执行一次history.push,相当于刚进页面就多压了一条相同的历史记录,拉长了历史栈,放大了第一个问题的影响。 - 手动维护
QueryString状态属于多余逻辑:路由的location.search本身就是唯一的数据源,额外用state存一份反而会导致数据不同步。
修复方案
- 删掉所有手动监听
popstate的代码,react-router已经内置了历史记录管理,不需要自己额外处理。 - 以
location.search作为唯一的数据源,组件挂载和location变化时,都从路由参数里解析出筛选值同步到本地state。 - 点击应用按钮时直接调用
history.push更新路由,不需要额外维护QueryString状态。 - 受控组件不需要同时设置
defaultValue和value,删掉多余的defaultValue属性避免冲突。
修复后代码如下:
import React, {useState, useEffect} from 'react' import {DropDownList, MultiSelect} from "@progress/kendo-react-dropdowns" import {Button} from '@progress/kendo-react-buttons' import { useHistory, useLocation } from "react-router-dom" const Filter = () => { const history=useHistory() const location=useLocation() const [Standard,setStandard] = useState("All") const [Hobbies,setHobbies] = useState(["Playing"]) const [Responsibility,setResponsibility] = useState("All") const options={ StandardList:["All","VI","VII","VIII"], HobbiesList: ["Playing", "Drawing","Swimming"], ResponsibilityList:["All","Monitor","Head","Sports Captain"] } // 路由参数变化时同步到本地state useEffect(() => { const params = new URLSearchParams(location.search) if (params.get('Standard')) { setStandard(JSON.parse(params.get('Standard'))) } if (params.get('Responsibility')) { setResponsibility(JSON.parse(params.get('Responsibility'))) } if (params.get('IncidentStatus')) { setHobbies(JSON.parse(params.get('IncidentStatus'))) } }, [location.search]) const handleApply = () => { const params = new URLSearchParams() params.set('Standard', JSON.stringify(Standard)) params.set('Responsibility', JSON.stringify(Responsibility)) params.set('IncidentStatus', JSON.stringify(Hobbies)) history.push({ search: params.toString() }) } return ( <div> <label>Standard </label> <DropDownList data={options.StandardList} value={Standard} onChange={(event)=>setStandard(event.target.value)}/> <label > Hobbies </label> <MultiSelect data={options.HobbiesList} value={Hobbies} onChange={(event)=>setHobbies([...event.value])}/> <label > Responsibility </label> <DropDownList data= {options.ResponsibilityList} value={Responsibility} onChange={(event)=>setResponsibility(event.target.value)} /> <Button id="submitFilter" type="button" onClick={handleApply} > Apply </Button> </div> ) } export default Filter
内容的提问来源于stack exchange,提问作者Chaya
相关产品推荐
相关产品推荐

