基于 url 的页面更新的 React useLocation 钩子的替代方案?
Posted
技术标签:
【中文标题】基于 url 的页面更新的 React useLocation 钩子的替代方案?【英文标题】:Alternative to React useLocation hook for page update based on url? 【发布时间】:2020-03-01 02:26:44 【问题描述】:这是一个棘手的问题。
一些信息:我可以有多个图像的多个集合,并且每个集合都有一个特定的标题徽标。 我的收藏网址看起来像这样/collection/collectionId/item/itemId
const MyApp = () =>
// unrelated code
return(
<BrowserRouter>
<SiteLayout>
</BrowserRouter>
)
和
const SiteLayout = () =>
location = useLocation()
collectionId = location.pathname.split('/')[2] //gives me the collection Alias
const [collData, setCollData] = useState()
useEffect(() =>
const getCollectionData = async() =>
//fetch collection data
//setCollData(fetched data)
getCollectionData()
, [collectionId])
return(
<CollectionContext.Provider value=collData>
<div className='mainContainer'>
<div className='headerContainer'>
<Header/>
</div>
<div className='mainContent'>
<Route exact path='/collection/:collectionId' component=CollectionViewPage>
<Route exact path='/collection/:collectionId/item/:itemId' component=ItemViewPage
</div>
<div className='footerContainer'>
<Footer/>
</div>
</div>
</CollectionContext.Provider>
)
export default SiteLayout
我的想法:
我是这样设置的,因为我不能在<BrowserRouter>
之外使用useLocation()
,并且我想更新我的collectionContext(其中包含有关我所在的集合的信息,包括集合特定的标题徽标) collectionId
更改,这是 location
的一部分
我的问题:
当我从一个项目移动到另一个项目时,在一个集合中,标题和其他所有内容仍然会重新呈现,例如
来自 -- /collection/
collection1/item
/1
至 -- /collection/
collection1/item
/2
我的想法:这个标题不应该更新,因为collectionId
从未改变。 然而,当我查看 React 开发工具中的 Profiler 时,它说 Header 更改了,因为父级更改了,然后跟踪到 <Route>
更改,因为它的状态 (location
) 更改了。
我在寻找什么:我如何重构它以在 collectionId
更改时更新,但不是每次 location
更改时更新?我需要这个是因为(很多事情,但为了简单起见)我希望在更改集合时更新标题,以便它可以使用正确的徽标,但如果我想防止 <Header>
重新渲染在集合中导航。
我尝试过的其他方法:我尝试删除 useLocation
并改用 window.location.pathname
,但没有任何更新。
【问题讨论】:
如果 Header 和 CollectionViewPage 是功能组件,也许你可以用React.memo 包裹下摆如果它们仍然重新渲染然后检查传递的道具,看看你需要什么,也许创建一个只选择的容器你真正需要的,而不是改变但未使用的道具。 @HMR 根据您的建议找到了解决方案(在下面的答案中注明)谢谢! 【参考方案1】:已解决
使用@HMR 的建议来回答原始问题:
如果 Header 和 CollectionViewPage 是功能组件,也许你可以将 [它们] 包装在 React.memo 如果它们仍然重新渲染 [...] 看看你需要什么,也许创建一个只选择你实际需要的容器。 .
实施:
通过添加一个中间层,我可以拆分location
,然后根据我想要的任何部分来记忆SiteLayout
。
const MyApp = () =>
// unrelated code
return(
<BrowserRouter>
<LocationPartition>
</BrowserRouter>
)
export default MyApp
在LocationPartition
中的位置(可能可以使用更好的名称):
const LocationPartition = () =>
const location = useLocation()
const collectionId = location.pathname.split('/')[2]
return(
<SiteLayout collection=collectionId/>
)
export default LocationPartition
所以在SiteLayout
中,我现在可以根据从LocationPartition
传递的collection
属性进行记忆
const SiteLayout = memo((collection)) =>
const [collData, setCollData] = useState()
useEffect(() =>
const getCollectionData = async() =>
//fetch collection data
//setCollData(fetched data)
getCollectionData()
, [collection])
return(
<CollectionContext.Provider value=collData>
<div className='mainContainer'>
<div className='headerContainer'>
<Header/>
</div>
<div className='mainContent'>
<Route exact path='/collection/:collectionId' component=CollectionViewPage>
<Route exact path='/collection/:collectionId/item/:itemId' component=ItemViewPage
</div>
<div className='footerContainer'>
<Footer/>
</div>
</div>
</CollectionContext.Provider>
)
export default SiteLayout
你瞧 ... React Profiler 现在只在我想要的地方显示重新渲染!
【讨论】:
以上是关于基于 url 的页面更新的 React useLocation 钩子的替代方案?的主要内容,如果未能解决你的问题,请参考以下文章
react-router-dom之 history+路由url更新页面不刷新的解决办法
我在使用 React 路由器时遇到问题,因为我的 url 在点击它时会得到更新,但页面没有被呈现