Автор оригинала: FreeCodeCamp Community Member.
Хосе М. Перес
Как использовать компонент с высоким порядком для загрузки того, что необходимо, при необходимости.
Компонерение отметила до и после разработки веб-разработки. Основными преимуществами, которые обычно упоминаются, являются повторное использование и модуляризация. Компоненты являются хорошо определенными деталями, которые мы можем использовать для создания наших сайтов, таких как кирпичи Legos. Оказывается, эта компонентная структура обеспечивает отличную основу для повышения производительности наших сайтов.
Мы явно о наших зависимостях, поэтому мы знаем, какой код нам нужен для запуска определенного компонента. Lazy-loading и расщепление пучка могут иметь огромное влияние на производительность страницы: меньше запрошенного кода, анализируемой и выполненным. И это не только относится к JavaScript, но каждый тип актива.
Я вижу много сайтов, которые могут воспользоваться этим. Я хотел показать некоторые основные методы для загрузки контента по мере необходимости.
Статья будет использовать преимущество/реагировать, но идеи могут быть применены к любой другой библиотеке компонентов.
Мы собираемся покрыть несколько тем.
Давайте начнем!
Композиционные узоры
В компоненте мировые компоненты не используются только для рендеринга фактических пикселей на экране. Они также могут обернуть функциональность, которая передается детским компонентам.
Это обычно достигается с использованием Компоненты высокого порядка (HOC) Отказ Эти компоненты получают другой компонент и добавляют некоторые функциональные возможности, как поведение.
Если вы использовали Redux, соединить
Функция – это HOC, который получает ваш не связанный компонент. Вы можете найти больше примеров в « ». РЕАГИМАЛЬНЫЕ КОМПОНЕНТЫ УДАЛЕННОГО ЗАКАЗА в глубину «Fran Guijarro.
const MyComponent = props => ({props.id} - {props.name});
// ...
const ConnectedComponent = connect(mapStateToProps, mapDispatchToProps)( MyComponent );
Функция как дочерний компонент (также известный как « Render Callback ») – еще один шаблон, используемый в аналогичных сценариях. Это становится довольно популярным в эти дни. Возможно, вы нашли их в Реагистрационные медиа или Неустановленные Отказ
Посмотрите на этот пример, взятый из React-Media:
const MyComponent = () => ({matches => matches ? ( );The document is less than 600px wide.
) : (The document is at least 600px wide.
) }
СМИ
Компонент называет своих детей, проходящих матчи
аргумент Таким образом, детские компоненты не должны знать о медиа-запросе. Компонтативность обычно облегчает тестирование и техническое обслуживание.
Улучшение производительности наших сайтов, загружая только то, что нужно
Представьте себе типичную веб-страницу. Вы можете проверить Сайт Сервис или Тенденции веб-дизайна: почему все сайты выглядят одинаково? Для некоторого вдохновения:). Страница примера, которую мы собираемся использовать, содержит несколько разделов или блоков:
- Заголовок (в наши дни, большой имидж героя, принимая весь складную область)
- Раздел с несколькими изображениями
- Еще один раздел с тяжелым компонентом, как карта
- нижний колонтитул
Это, сопоставлено в реактивные компоненты, было бы что-то подобное:
const Page = () => {};
Когда пользователь посещает страницу, весьма вероятно, что они увидят заголовок на экране. В конце концов, это самый верхний компонент. Очень вероятно, что они видят галерею, карту и нижний колонтитул, если они не прокручиваются.
В большинстве случаев вы сможете включить все сценарии и CSS, необходимые для рендеров всех разделов, как только пользователь посещает страницу. До недавнего времени было трудно определить зависимости модуля, и нагрузка, что нужно было.
Несколько лет назад Pre-ES6 крупные компании придумали свои собственные решения для определения зависимостей и нагрузки их по мере необходимости. Yahoo построил Yui Loader И Facebook писал Спешка, загрузчик и грунтовка Отказ
Когда вы отправляете код пользователя, который не нужен, вы тратите ресурсы на вашем конце, и от конца пользователя. Больше пропускной способности для передачи данных, больше процессора для анализа и выполнения их, и больше памяти, чтобы сохранить. И эти активы украдят ограниченные ресурсы из других критических активов, которые нуждаются в этом более срочно.
Какой смысл запросить ресурсы, которые пользователь не понадобится, как изображения, которые пользователь не достигнет? Или загрузка 3-го вечеринка, как карта Google, со всеми его дополнительными активами, необходимыми для того, чтобы сделать вещь?
Отчет о покрытии кода, как Один Google Chrome предоставляет не поможет нам много Отказ Код JS будет выполнен, а CSS, применяемый к элементам, которые не видны.
Как со всем остальным, Есть компромиссы с ленивой загрузкой Отказ Мы не хотим применить ленивую нагрузку на все. Вот некоторые очки, которые нужно учитывать.
- Не ленивая нагрузка выше сгиба Отказ В большинстве случаев мы хотим, чтобы контент выше, который будет отображаться как можно скорее. Каждая техника Lazy-loading представит задержку. Браузер должен запускать JS, который вводит HTML в документ, разбирать его и начать запрашивать ссылочные активы.
Где установить складку? Это сложно, и он будет зависеть от устройства пользователя, который сильно варьируется, и ваш макет.
- Ленивая нагрузка немного раньше, чем когда это нужно Отказ Вы хотите избежать отображения недействительных областей пользователю. Для этого вы можете загрузить активой, который необходим, когда он достаточно близко к видимой области. Например, пользователь прокручивается вниз, и если изображение нагрузки, скажем, 100px ниже нижней части Viewport начните запрашивать его.
- Невидимое содержание в некоторых сценариях Отказ Вы должны учитывать, что ленивый контент не будет показан в некоторых ситуациях:
1) Если загруженный ленивый контент не был загружен, он не будет отображаться при печати страницы.
2) То же самое может произойти, когда страница отображается в RSS-читателях, которые могут не выполнить JavaScript, необходимый для загрузки содержимого.
3) Когда дело доходит до SEO, у вас могут возникнуть проблемы с индексацией ленивого контента в Google. На момент написания этой статьи GoogleBot поддерживает IntersizerVerver. Это вызывает свой обратный вызов с изменениями в области просмотра выше сгиба. Тем не менее, Это не будет вызвать обратный вызов для контента ниже сгиба Отказ Таким образом, Этот контент не будет замечен, ни индексироваться Google Отказ Если ваш контент важен, вы можете, например, визуализацию текстовых и ленивых компонентов нагрузки, такие как изображения и другие виджеты (например, карты).
Вот я рендеринг тестовая страница (Вы можете увидеть источник здесь ) Использование Google Webmaster Tools ‘”Fetch в качестве Google”. GoogleBot отображает содержимое в коробке, показанном в поле ViewSt, но не содержимое под ним.
Небольшой компонент для обнаружения, когда область видима
Я говорил в прошлом о Ленивые изображения Отказ Это просто тип актива, который мы можем лениться, но мы можем применить методику на другие элементы.
Давайте построим простой компонент, который обнаружит, когда раздел виден в Viewport. Для краткости я буду использовать Пересечение Observer API экспериментальная технология с Неплохо хорошая поддержка Отказ
class Observer extends Component { constructor() { super(); this.state = { isVisible: false }; this.io = null; this.container = null; } componentDidMount() { this.io = new IntersectionObserver([entry] => { this.setState({ isVisible: entry.isIntersecting }); }, {}); this.io.observe(this.container); } componentWillUnmount() { if (this.io) { this.io.disconnect(); } } render() { return ( // we create a div to get a reference. // It's possible to use findDOMNode() to avoid // creating extra elements, but findDOMNode is discouraged{ this.container = div; }} > {Array.isArray(this.props.children) ? this.props.children.map(child => child(this.state.isVisible)) : this.props.children(this.state.isVisible)}); }}
Компонент использует InterSersebServer для обнаружения того, что контейнер пересекается с ViewPort (что это видно). Мы используем преимущества методов жизненного цикла Ractecycle для очистки пересечений, Отключить его при размонтировании.
Этот базовый компонент может быть расширен с дополнительными свойствами, переданными как Варианты для пересеченийBServer , как краевые или пороги. Это позволяет нам обнаруживать элементы, близкие, но не пересекающиеся с помощью просмотра. Параметры устанавливаются в конструкторе, и они только для чтения. Таким образом, добавление поддержки параметров означает, что нам нужно будет восстановить пересечениеОбсервер с новыми опциями, когда они меняются, добавляя дополнительную логику в ComponentWillReceiveProps
Что мы не собираемся прикрывать здесь.
Теперь мы можем использовать этот компонент для ленивых нагрузки двух наших компонентов, Галерея
и Карта
:
const Page = () => {}{isVisible => } {isVisible => }
В коде выше я просто передаю невидим
Имущество для Галерея
и Карта
компоненты, поэтому они обрабатывают это. В качестве альтернативы мы могли бы вернуть компонент, если видно, или пустой элемент в противном случае.
В любом случае Убедитесь, что вы зарезервируете область для ленивого компонента Отказ Вы не хотите, чтобы контент прыгнуть, так что если вы знаете, что ваш Карта
Высота 400 пикселей, визуализируйте пустой контейнер высоты 400px перед отображением карты.
Как Карта
и Галерея
Компоненты используют невидим
имущество? Давайте посмотрим на Карта
:
class Map extends Component { constructor() { super(); this.state = { initialized: false }; this.map = null; }
initializeMap() { this.setState({ initialized: true }); // loadScript loads an external script, its definition is not included here. loadScript("https://maps.google.com/maps/api/js?key=", () => { const latlng = new google.maps.LatLng(38.34, -0.48); const myOptions = { zoom: 15, center: latlng }; const map = new google.maps.Map(this.map, myOptions); }); }
componentDidMount() { if (this.props.isVisible) { this.initializeMap(); } }
componentWillReceiveProps(nextProps) { if (!this.state.initialized && nextProps.isVisible) { this.initializeMap(); } }
render() { return ({ this.map = div; }} /> ); }}
Когда контейнер отображается в ViewPort, мы сделаем запрос на включение сценария Google Map. После загрузки мы создаем карту. Это хороший пример JavaScript Lazy-loading, который не нужен с самого начала, а остальные ресурсы необходимы для отображения карты.
Компонент имеет состояние, чтобы избежать впрыскивания скрипта Google Maps.
Давайте посмотрим на Галерея
составная часть:
class Gallery extends Component { constructor() { super(); this.state = { hasBeenVisible: false }; } componentDidMount() { if (this.props.isVisible) { this.setState({ hasBeenVisible: true }); } } componentWillReceiveProps(nextProps) { if (!this.state.hasBeenVisible && nextProps.isVisible) { this.setState({ hasBeenVisible: true }); } } render() { return (); }}Some pictures
Picture 1 {this.state.hasBeenVisible ? () : ( )} Picture 2 {this.state.hasBeenVisible ? (
) : ( )}
Приведенный выше пример определяет другой государственный компонент. На самом деле, мы храним в государстве ту же информацию, что и с Карта
Отказ
Если галерея отображается в рамках Viewport, и после этого он находится за пределами Viewport, изображения будут оставаться в доме. В большинстве случаев это то, что мы хотим при работе с изображениями.
Участки без гражданства
Компонент без гражданства также может быть интересным. Это позволило бы нам разгрузить изображения, которые больше не видны, показывая находки заполнителей:
const Gallery = ({ isVisible }) => ();Some pictures
; Picture 1 {isVisible ? () : ( )} Picture 2 {isVisible ? (
) : ( )}
Если вы сделаете это, Убедитесь, что изображения имеют правильные заголовки ответа кэша. Это так последующие запросы из браузера попадают в кеш, и он не загружает изображения снова.
Если вы обнаружите, что сделаете свои ленивые компоненты, данные, только для отслеживания того, что они были видны хотя бы один раз, вы можете добавить эту логику в Наблюдатель
составная часть. В конце концов, Наблюдатель
уже условно, и он может легко вызвать своих детей дополнительным HasbeenVisible
аргумент
const Page = () => { ...{(isVisible, hasBeenVisible) => ...}// Gallery can be now stateless }
Другой вариант – иметь вариант Наблюдатель
Компонент, который проходит только как HasbeenVisible
Отказ Это имеет то преимущество, что мы можем отключить пересечений, как только этот элемент будет считать, поскольку мы не собираемся изменить его значение. Мы назовем этот компонент Наблюдатель
:
class ObserverOnce extends Component { constructor() { super(); this.state = { hasBeenVisible: false }; this.io = null; this.container = null; } componentDidMount() { this.io = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { this.setState({ hasBeenVisible: true }); this.io.disconnect(); } }); }, {}); this.io.observe(this.container); } componentWillUnmount() { if (this.io) { this.io.disconnect(); } } render() { return ({ this.container = div; }} > {Array.isArray(this.props.children) ? this.props.children.map(child => child(this.state.hasBeenVisible)) : this.props.children(this.state.hasBeenVisible)}); }}
Больше используйте случаи
Мы использовали Наблюдатель
Компонент для загрузки ресурсов по требованию. Мы также можем использовать его, чтобы начать анимацию компонента, как только пользователь видит его.
Вот пример, взятый из веб-сайта React Alicante. Он оживляет некоторые номера конференций, как только пользователь прокручивает к этому разделу.
Мы могли бы воссоздать это так (см. Пример на кодепене ):
class ConferenceData extends Component { constructor() { super(); this.state = { progress: 0 }; this.interval = null; this.animationDuration = 2000; this.startAnimation = null; } componentWillReceiveProps(nextProps) { if ( !this.props.isVisible && nextProps.isVisible && this.state.progress !== 1 ) { this.startAnimation = Date.now(); const tick = () => { const progress = Math.min( 1, (Date.now() - this.startAnimation) / this.animationDuration ); this.setState({ progress: progress }); if (progress < 1) { requestAnimationFrame(tick); } }; tick(); } } render() { return ({Math.floor(this.state.progress * 3)} days · {Math.floor(this.state.progress * 21)} talks · {Math.floor(this.state.progress * 4)} workshops · {Math.floor(this.state.progress * 350)} attendees); }}
Затем мы бы использовали его точно так, как остальные компоненты. Это показывает способность рассуждения логики обнаружения видимости вне компонентов, которые их нуждаются.
Polyfilling Intersersebserver по требованию
До сих пор мы использовали InterSeficateBServer для обнаружения, когда элемент становится видимым. Во время этой записи некоторые браузеры (например, Safari) не имеют поддержки для него, поэтому инсультирование инвентации пересекается.
Опция будет установлена невидим
к правда
Когда пересечениеОбсеревер не доступен. Это, на практике, отключит ленивую загрузку. Таким образом, мы рассмотрим ленивую загрузку как прогрессирующее улучшение:
class Observer extends Component { constructor() { super(); // isVisible is initialized to true if the browser // does not support IntersectionObserver API this.state = { isVisible: !(window.IntersectionObserver) }; this.io = null; this.container = null; } componentDidMount() { // only initialize the IntersectionObserver if supported if (window.IntersectionObserver) { this.io = new IntersectionObserver(entries => { ... } } }}
Другой вариант, который я предпочитаю, должен включать в себя полифилл, как Пересечение W3C Polyfill Отказ Таким образом, интерсефекционныйibserver будет работать во всех браузерах.
Следуя с темой погрузки ресурсов по требованию, а также привести к примеру, мы воспользуемся преимуществами кодового расщепления только запросить только полифилл, если это необходимо. Таким образом, браузеры, поддерживающие API, не нужно получать полифилл:
class Observer extends Component { ... componentDidMount() { (window.IntersectionObserver ? Promise.resolve() : import('intersection-observer') ).then(() => { this.io = new window.IntersectionObserver(entries => { entries.forEach(entry => { this.setState({ isVisible: entry.isIntersecting }); }); }, {}); this.io.observe(this.container); }); } ...}
Вы можете увидеть Демо здесь (Проверьте Источник кода ). Safari сделает дополнительную заявку на загрузку Пересечение-наблюдатель
Пакет NPM, поскольку он не поддерживает InterSersebServer.
Это достигается благодаря расщеплению кода. Есть такие инструменты, как Посылка или WebPack Это создаст пакет для этого импортированного пакета, а логика, необходимая для запроса файла.
Разделение кода и CSS-in-js
Пока что мы видели, как использовать HOC, чтобы обнаружить, что элемент находится в пределах просмотра. Мы также видели, как загрузить дополнительный JavaScript при необходимости.
Кодовое расщепление довольно распространено и просто для реализации на уровне маршрута. Браузер загружает дополнительные пакеты, так как пользователь навигациирует по разным URL-адресам на сайте. Инструменты, как Реагистрационный маршрутизатор и Next.js сделали это просто для реализации.
Через примеры на этом посте мы видели, что то же самое можно достичь в том же маршруте, загружая код для компонентов по требованию. Это очень полезно, если у нас есть компоненты, которые нуждаются в большом конкретном коде, не только JavaScript.
Компонент может ссылаться на другие ресурсы или даже встроить их. Подумайте о стилях SVG или CSS.
Нет смысла запрашивать стили, которые не будут применяться к любому элементу. Динамически запрашивающие и инъекционные CSS вызывают Fouc (вспышка нестандартного содержания). Браузер показывает HTML-элементы с существующим стилем. Как только дополнительные стили вводят его повторно стили содержание. С появлением решений CSS-In-JS (или JSS) это больше не проблема. CSS включен в компоненте, и мы получаем истинное разделение кода для наших компонентов. С CSS-In-JS мы принимаем кодовые расщепления дальше, загружая CSS по требованию.
Полезные реализации
В этом посте я объяснил, как реализовать базовый компонент наблюдателя. Существуют существующие реализации аналогичных компонентов, которые были более тестированы в бою, поддерживают больше вариантов и обеспечивают дополнительные способы интеграции в ваш проект.
Я определенно рекомендую вам проверить эти 2 библиотеки:
Заключение
Надеюсь, я показал, как компонента может сделать разделение кода и загрузки ресурсов по требованию легче, чем когда-либо. Определите, что ваш код зависит от и использует материалы и используют материалы и используют зависимости в зависимости от необходимых зависимостей, когда пользователь навигации к новым путям или новые компоненты отображаются на странице.
Я хотел бы поблагодарить @alexjoverm , @aarongarciah и @Flaviocorpa Для просмотра поста, исследуя аналогичные темы и рекомендации инструментов для предоставления примеров на странице.
Вы видели какую-либо опечачу или неправильную информацию? В этом случае брось мне линию Отказ
Читайте больше от меня на моем Веб-сайт .