#javascript #reactjs #react-redux
Вопрос:
Для своей домашней страницы я пытаюсь использовать загружаемые компоненты с наблюдателем пересечения. Когда мой магазин redux обновляется, вся страница обновляется заново. Как я могу этого избежать?
import React from "react"
import loadable from "@loadable/component"
import { useSelector } from "react-redux"
const Index = () => {
const intersectState = useSelector(state => state.intersectState)
const BannerProducts = loadable(() =>
import("../components/bannerProducts/bannerProducts")
)
const SellingBulletPoints = loadable(() =>
import("../components/sellingBulletPoints/sellingBulletPoints")
)
const Category = intersectState.categoryComponent amp;amp;
loadable(() => import("../components/category/category"))
return (
<>
<BannerProducts />
<SellingBulletPoints />
{intersectState.categoryComponent amp;amp; <Category />}
</>
)
}
export default Index
Комментарии:
1. Используйте
useMemo
или используйтеuseCallBack
, чтобы остановить повторную передачу. Я думаю, что эта ссылка поможет вам kentcdodds.com/blog/usememo-and-usecallback или, если вы хотите ознакомиться с официальной документацией, пожалуйста, посетите эту страницу also.reactjs.org/docs/hooks-reference.html#usememo
Ответ №1:
Это происходит потому, что ваши компоненты переопределяются при каждом рендеринге.
Если вы переместите эти определения компонентов ленивой загрузки за пределы функции визуализации, то это должно работать нормально.
const BannerProducts = loadable(() =>
import("../components/bannerProducts/bannerProducts")
)
const SellingBulletPoints = loadable(() =>
import("../components/sellingBulletPoints/sellingBulletPoints")
)
const Category = loadable(() => import("../components/category/category"))
Вот как это работает:
loadable(()=>import('./component'))
Вызов создает только компонент-оболочку, который при визуализации приостанавливается (или просто становится нулевым) до тех пор, пока полный код не будет в браузере и готов к запуску. До тех пор, пока этот компонент не будет отрисован, код разделения кода не загружается в браузер.
Таким образом, воссоздавая компонент оболочки с ленивой загрузкой, вы ничего не делаете, кроме добавления дополнительных циклов. Фактически, вы уничтожаете то, что использует React, чтобы определить, является ли визуализируемый элемент тем же самым (т. Е. Component===Component
). Таким образом, при каждом повторном отображении родительского элемента ваш компонент-оболочка с отложенной загрузкой создается заново, что приводит к его отключению/повторному подключению.
К счастью, отложенная загрузка достаточно оптимизирована, так что она загружает один и тот же фрагмент только один раз — при первом отображении компонента с отложенной загрузкой (отсюда import('./component')
и строка).
Чтобы понять, как это работает и почему ваш компонент перемонтируется, я создал песочницу кода с 3 компонентами, все с одним и тем же кодом (хотя и с разными именами и строками).
import { useEffect } from "react";
console.log("CodeSplit Code loaded!");
export default function CodeSplit() {
useEffect(() => {
console.log(`CodeSplit Mounted`);
return () => {
console.log(`CodeSplit Unmounted`);
};
}, []);
return <div>CodeSplit</div>;
}
Если вы запустите codesandbox, эти три компонента:
NormalCode
— Код, отображаемый синхронно как часть базового пакета. NormalCode Code Loaded
Сообщение регистрируется по мере выполнения кода при загрузке основного пакета.
CodeSplit
— Код лениво загружается с использованием loadable
, но в правильном способе его использования. CodeSplit Code Loaded
Сообщение регистрируется, как только show splits
нажата кнопка. Это происходит потому, что это первый раз CodeSplit
, когда лениво загруженный компонент отображается, даже если <CodeSplit />
он находится в вызове. При этом, когда он отображается и вы вводите данные, больше нет никаких CodeSplit Mounted
сообщений и CodeSplit Unmounted
сообщений.
CodeSplitGoofed
— Код загружается с loadable
задержкой , но компонент с отложенной загрузкой создается в App
рендеринге компонента. Это происходит так же, как CodeSplit
и для аспектов отложенной загрузки, но когда вы вводите данные во входные данные, из журналов CodeSplitGoofed Mounted
и консоли видно CodeSplitGoofed Unmounted
, что этот компонент размонтируется и перемонтируется каждый раз при повторной App
отрисовке компонента. Причина этого такова, как указано выше — React не может знать, что это тот же компонент, что и раньше.
Комментарии:
1. На самом деле я напечатал это неправильно… Смотрите выше. Проблема в том, что intersectState.categoryКомпонент также должен быть в определениях компонентов. Я хочу сказать… если состояние в redux обновлено… найдите JS для этого компонента и отрисовайте его, не обновляя всю страницу.
2. Нет никакой разницы в функциональности того, что я предложил, по сравнению с тем, что вы отредактировали. Если вы динамически не импортируете другой
Category
компонент с другого пути (в этом случае удачи с webpack…), позвольте компонентам ленивой загрузки делать свое дело. Вам не нужно каждый раз заново создавать лениво загруженный компонент; просто динамически визуализируйте компонент. Воссоздание компонента заставит React каждый раз думать, что это совершенно другой компонент. Таким образом, он потеряет все внутреннее состояние, так как предыдущий будет размонтирован, а новый будет смонтирован.3. Разница в том, что const Category = intersectState.categoryComponent amp;amp; загружаемый(() => импорт(«../компоненты/категория/категория»)) загружает javascript только в том случае, если состояние redux говорит, что оно еще не загружено наблюдателем пересечения. Если я удалю проверку состояния, то он загрузит JS при загрузке страницы, даже если пользователь не перейдет к компоненту. Я просто пытался вырезать JS и загружать его только тогда, когда пользователь нажимает на этот компонент.
4. @JasonBiondo Я обновил свой ответ примером и большим количеством описания, чтобы помочь вам понять, как работает ленивая загрузка.