react-router-dom v6通用页面包裹组件的合理性及替代方案咨询
问题:react-router-dom v6中URL参数变化时useEffect未触发导致数据不一致崩溃
场景说明
使用react-router-dom v6的带URL参数路由时,连续导航至同一页面但参数不同的情况下,路由对应的组件会重渲染,但依赖该参数的useEffect并未及时触发,导致客户端缓存的旧数据与新参数生成的结构混合,最终引发组件崩溃(白屏)。若中间跳转至其他页面则无异常。
当前解决方案
通过一个包裹组件PageWrapper为路由组件传递基于params生成的key,强制组件在参数变化时重新挂载:
const PageWrapper = ({page}) => { const params = useParams(); const key = JSON.stringify(params); return <div key={key}>{page}</div> }
路由配置示例:
<Route path={`thing_type/:thing_type_id`} element={ <PageWrapper page={<ThingTypePage/>} /> } />
该方案虽能解决问题,但写法繁琐,且担心存在不规范或未预见的潜在问题。曾尝试直接为element属性传递params作为key,但react-router-dom v6不支持此操作。
问题核心代码示例(简化版)
崩溃的直接原因是:参数更新后,旧请求返回的data尚未更新,却使用新参数生成了数据结构,导致渲染时数据与结构不匹配,触发未定义属性访问错误:
const ThingTypePage = () => { const {thing_type_id} = useParams(); const {cachedStaticData} = React.useContext(Context); const [data, setData] = useState(null); useEffect(() => { setData(null); const body = {thing_type_id}; const onSucceeded = (response) => setData(response.data); const onFailed = (err) => setData(false); myFetch("myBackendUrlExtension", body, onSucceeded, onFailed); }, [thing_type_id]) if(data === null) return <div>Loading...</div>; if(data === false) return <div>Failed to load</div>; const things = data.instances; const thingTypeObjectStructure = getThingTypeObjectStructure(cachedStaticData, thing_type_id); // 此时things为旧参数的请求结果,但thingTypeObjectStructure已使用新参数生成,导致渲染不匹配 return ( <div key={`ThingTypePage-${thing_type_id}`}> <ThingsTable things={things} structure={thingTypeObjectStructure} /> </div> ) }
咨询内容
- 当前的
PageWrapper方案是否合理? - 是否存在更简洁、规范的替代方案?
内容的提问来源于stack exchange,提问作者TBaby
相关产品推荐
相关产品推荐

