基于 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

我的想法:

我是这样设置的,因为我不能在&lt;BrowserRouter&gt; 之外使用useLocation(),并且我想更新我的collectionContext(其中包含有关我所在的集合的信息,包括集合特定的标题徽标) collectionId 更改,这是 location 的一部分

我的问题:

当我从一个项目移动到另一个项目时,在一个集合中,标题和其他所有内容仍然会重新呈现,例如

来自 -- /collection/collection1/item/1 至 -- /collection/collection1/item/2

我的想法:这个标题不应该更新,因为collectionId 从未改变。 然而,当我查看 React 开发工具中的 Profiler 时,它说 Header 更改了,因为父级更改了,然后跟踪到 &lt;Route&gt; 更改,因为它的状态 (location) 更改了。

我在寻找什么:我如何重构它以在 collectionId 更改时更新,但不是每次 location 更改时更新?我需要这个是因为(很多事情,但为了简单起见)我希望在更改集合时更新标题,以便它可以使用正确的徽标,但如果我想防止 &lt;Header&gt; 重新渲染集合中导航。

我尝试过的其他方法:我尝试删除 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 在点击它时会得到更新,但页面没有被呈现

React 路由器更改 url 但未更新上下文

React Router在url参数不同的情况下跳转页面不更新解决方案

状态更改时 React 组件未更新

React-router-dom更改URL但不更新样式组件的ThemeProvider的内容