Remix Run:如何强制重新加载Outlet加载组件的所有子组件
如何强制React Router Outlet内的所有子组件重新渲染
问题描述
我通过父组件的<Outlet/>加载了一个组件,该组件会渲染ActionsBar和Collection两个子组件。当URL变化触发Outlet重新渲染时,我原本以为组件内所有内容都会重新渲染,但实际只有依赖变化数据的Collection组件会更新。我希望能找到方法强制Outlet内的所有子组件重新加载,这样就不用手动重置大量状态了。
代码示例:
export default function ComponentLoadedInOutlet() { const collectionData = useLoaderData(); return ( <div> <ActionsBar /> <Collection data={collectionData} /> </div> ) }
解决方案
1. 给Outlet添加基于URL的key
React通过key识别组件实例,当key改变时,会销毁旧组件实例并创建新的,从而触发所有子组件的重新挂载(状态自动重置)。在使用Outlet的父组件中,用当前URL路径作为key:
import { Outlet, useLocation } from 'react-router-dom'; function ParentComponent() { const location = useLocation(); return <Outlet key={location.pathname} />; }
这样每次URL变化,Outlet内的ComponentLoadedInOutlet会被完全重建,所有子组件(包括ActionsBar)都会重新挂载,状态自然重置。
2. 在Outlet加载的组件中监听location变化
如果不想修改父组件,可以在ComponentLoadedInOutlet中监听location,让组件自身重新渲染:
import { useLoaderData, useLocation } from 'react-router-dom'; import React from 'react'; export default function ComponentLoadedInOutlet() { const collectionData = useLoaderData(); const location = useLocation(); // 依赖location变化触发组件更新 React.useEffect(() => {}, [location]); return ( <div> <ActionsBar /> <Collection data={collectionData} /> </div> ) }
注意:如果ActionsBar是用React.memo包裹的纯组件,这种方法可能不会让它重新渲染,此时方法1更稳妥。
3. 给特定子组件添加动态key
如果只需要重置某个子组件的状态,可以给目标组件添加基于URL的key:
import { useLoaderData, useLocation } from 'react-router-dom'; export default function ComponentLoadedInOutlet() { const collectionData = useLoaderData(); const location = useLocation(); return ( <div> <ActionsBar key={location.pathname} /> <Collection data={collectionData} /> </div> ) }
每次URL变化时,ActionsBar会被重新创建,状态随之重置。
内容的提问来源于stack exchange,提问作者jon
相关产品推荐
相关产品推荐

