Альтернатива React useLocation hook для обновления страницы на основе URL? - PullRequest
3 голосов
/ 04 ноября 2019

Это сложная проблема.

Немного информации :
У меня может быть несколько коллекций из нескольких изображений и отдельный логотип заголовка для каждой коллекции.
URL моей коллекции выглядит следующим образом /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

Мои мысли:

  • Янастроить его таким образом, потому что я не могу использовать useLocation() за пределами <BrowserRouter> и хочу обновить свой collectionContext (который содержит информацию о коллекции, в которой я работаю, включая логотип заголовка конкретной коллекции), когда collectionIdизменения, которые являются частью location

Моя проблема:

  • При переходе от элемента к элементу, в пределах коллекция, заголовок и все остальное по-прежнему визуализируется, например

    из - /collection/ collection1 / item / 1
    до - /collection/ коллекция1 / item / 2

  • Мои мысли: Этот заголовок не должен обновляться, потому что collectionId никогда не менялся. Однако , когда я смотрю на Профилировщик в инструментах разработчика React, он говорит, что Заголовок изменился, потому что изменился родительский элемент, следуя за ним до <Route>, который изменился, потому что изменилось его состояние (location).

Что я ищу : Как мне реорганизовать это для обновления, когда меняется collectionId, но не каждый раз, когда меняется location? Мне это нужно, потому что (много вещей, но для простоты) я хочу, чтобы заголовок обновлялся при изменении коллекций, чтобы он мог использовать правильный логотип, но я бы хотел предотвратить повторную визуализацию <Header>, если янавигация по внутри коллекции.

Что-то еще, что я пробовал :
Я пытался вырвать useLocation и вместо этого использовать window.location.pathname, но ничего не обновится.

1 Ответ

1 голос
/ 04 ноября 2019

Решено


Использование предложения @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, теперь я могу запоминать, основываясь на collection пропепередано от LocationPartition

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 теперь показывает только те рендеры, которые мне нужны!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...